LCOV - code coverage report
Current view: top level - dom/media/webaudio - AudioNode.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 342 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 57 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim:set ts=2 sw=2 sts=2 et cindent: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "AudioNode.h"
       8             : #include "mozilla/ErrorResult.h"
       9             : #include "AudioNodeStream.h"
      10             : #include "AudioNodeEngine.h"
      11             : #include "mozilla/dom/AudioParam.h"
      12             : #include "mozilla/Services.h"
      13             : #include "nsIObserverService.h"
      14             : 
      15             : namespace mozilla {
      16             : namespace dom {
      17             : 
      18             : static const uint32_t INVALID_PORT = 0xffffffff;
      19             : static uint32_t gId = 0;
      20             : 
      21             : NS_IMPL_CYCLE_COLLECTION_CLASS(AudioNode)
      22             : 
      23           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(AudioNode, DOMEventTargetHelper)
      24           0 :   tmp->DisconnectFromGraph();
      25           0 :   if (tmp->mContext) {
      26           0 :     tmp->mContext->UnregisterNode(tmp);
      27             :   }
      28           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mContext)
      29           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mOutputNodes)
      30           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mOutputParams)
      31           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
      32           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(AudioNode,
      33             :                                                   DOMEventTargetHelper)
      34           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContext)
      35           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOutputNodes)
      36           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOutputParams)
      37           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
      38             : 
      39           0 : NS_IMPL_ADDREF_INHERITED(AudioNode, DOMEventTargetHelper)
      40           0 : NS_IMPL_RELEASE_INHERITED(AudioNode, DOMEventTargetHelper)
      41             : 
      42           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(AudioNode)
      43           0 :   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
      44           0 : NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
      45             : 
      46           0 : AudioNode::AudioNode(AudioContext* aContext,
      47             :                      uint32_t aChannelCount,
      48             :                      ChannelCountMode aChannelCountMode,
      49           0 :                      ChannelInterpretation aChannelInterpretation)
      50             :   : DOMEventTargetHelper(aContext->GetParentObject())
      51             :   , mContext(aContext)
      52             :   , mChannelCount(aChannelCount)
      53             :   , mChannelCountMode(aChannelCountMode)
      54             :   , mChannelInterpretation(aChannelInterpretation)
      55           0 :   , mId(gId++)
      56             :   , mPassThrough(false)
      57           0 :   , mAbstractMainThread(aContext->GetOwnerGlobal()->AbstractMainThreadFor(TaskCategory::Other))
      58             : {
      59           0 :   MOZ_ASSERT(aContext);
      60           0 :   DOMEventTargetHelper::BindToOwner(aContext->GetParentObject());
      61           0 :   aContext->RegisterNode(this);
      62           0 : }
      63             : 
      64           0 : AudioNode::~AudioNode()
      65             : {
      66           0 :   MOZ_ASSERT(mInputNodes.IsEmpty());
      67           0 :   MOZ_ASSERT(mOutputNodes.IsEmpty());
      68           0 :   MOZ_ASSERT(mOutputParams.IsEmpty());
      69           0 :   MOZ_ASSERT(!mStream,
      70             :              "The webaudio-node-demise notification must have been sent");
      71           0 :   if (mContext) {
      72           0 :     mContext->UnregisterNode(this);
      73             :   }
      74           0 : }
      75             : 
      76             : void
      77           0 : AudioNode::Initialize(const AudioNodeOptions& aOptions, ErrorResult& aRv)
      78             : {
      79           0 :   if (aOptions.mChannelCount.WasPassed()) {
      80           0 :     SetChannelCount(aOptions.mChannelCount.Value(), aRv);
      81           0 :     if (NS_WARN_IF(aRv.Failed())) {
      82           0 :       return;
      83             :     }
      84             :   }
      85             : 
      86           0 :   if (aOptions.mChannelCountMode.WasPassed()) {
      87           0 :     SetChannelCountModeValue(aOptions.mChannelCountMode.Value(), aRv);
      88           0 :     if (NS_WARN_IF(aRv.Failed())) {
      89           0 :       return;
      90             :     }
      91             :   }
      92             : 
      93           0 :   if (aOptions.mChannelInterpretation.WasPassed()) {
      94           0 :     SetChannelInterpretationValue(aOptions.mChannelInterpretation.Value());
      95             :   }
      96             : }
      97             : 
      98             : size_t
      99           0 : AudioNode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
     100             : {
     101             :   // Not owned:
     102             :   // - mContext
     103             :   // - mStream
     104           0 :   size_t amount = 0;
     105             : 
     106           0 :   amount += mInputNodes.ShallowSizeOfExcludingThis(aMallocSizeOf);
     107           0 :   for (size_t i = 0; i < mInputNodes.Length(); i++) {
     108           0 :     amount += mInputNodes[i].SizeOfExcludingThis(aMallocSizeOf);
     109             :   }
     110             : 
     111             :   // Just measure the array. The entire audio node graph is measured via the
     112             :   // MediaStreamGraph's streams, so we don't want to double-count the elements.
     113           0 :   amount += mOutputNodes.ShallowSizeOfExcludingThis(aMallocSizeOf);
     114             : 
     115           0 :   amount += mOutputParams.ShallowSizeOfExcludingThis(aMallocSizeOf);
     116           0 :   for (size_t i = 0; i < mOutputParams.Length(); i++) {
     117           0 :     amount += mOutputParams[i]->SizeOfIncludingThis(aMallocSizeOf);
     118             :   }
     119             : 
     120           0 :   return amount;
     121             : }
     122             : 
     123             : size_t
     124           0 : AudioNode::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
     125             : {
     126           0 :   return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
     127             : }
     128             : 
     129             : template <class InputNode>
     130             : static size_t
     131           0 : FindIndexOfNode(const nsTArray<InputNode>& aInputNodes, const AudioNode* aNode)
     132             : {
     133           0 :   for (size_t i = 0; i < aInputNodes.Length(); ++i) {
     134           0 :     if (aInputNodes[i].mInputNode == aNode) {
     135           0 :       return i;
     136             :     }
     137             :   }
     138           0 :   return nsTArray<InputNode>::NoIndex;
     139             : }
     140             : 
     141             : template <class InputNode>
     142             : static size_t
     143           0 : FindIndexOfNodeWithPorts(const nsTArray<InputNode>& aInputNodes,
     144             :                          const AudioNode* aNode,
     145             :                          uint32_t aInputPort, uint32_t aOutputPort)
     146             : {
     147           0 :   for (size_t i = 0; i < aInputNodes.Length(); ++i) {
     148           0 :     if (aInputNodes[i].mInputNode == aNode &&
     149           0 :         aInputNodes[i].mInputPort == aInputPort &&
     150           0 :         aInputNodes[i].mOutputPort == aOutputPort) {
     151           0 :       return i;
     152             :     }
     153             :   }
     154           0 :   return nsTArray<InputNode>::NoIndex;
     155             : }
     156             : 
     157             : void
     158           0 : AudioNode::DisconnectFromGraph()
     159             : {
     160           0 :   MOZ_ASSERT(mRefCnt.get() > mInputNodes.Length(),
     161             :              "Caller should be holding a reference");
     162             : 
     163             :   // The idea here is that we remove connections one by one, and at each step
     164             :   // the graph is in a valid state.
     165             : 
     166             :   // Disconnect inputs. We don't need them anymore.
     167           0 :   while (!mInputNodes.IsEmpty()) {
     168           0 :     size_t i = mInputNodes.Length() - 1;
     169           0 :     RefPtr<AudioNode> input = mInputNodes[i].mInputNode;
     170           0 :     mInputNodes.RemoveElementAt(i);
     171           0 :     input->mOutputNodes.RemoveElement(this);
     172             :   }
     173             : 
     174           0 :   while (!mOutputNodes.IsEmpty()) {
     175           0 :     size_t i = mOutputNodes.Length() - 1;
     176           0 :     RefPtr<AudioNode> output = mOutputNodes[i].forget();
     177           0 :     mOutputNodes.RemoveElementAt(i);
     178           0 :     size_t inputIndex = FindIndexOfNode(output->mInputNodes, this);
     179             :     // It doesn't matter which one we remove, since we're going to remove all
     180             :     // entries for this node anyway.
     181           0 :     output->mInputNodes.RemoveElementAt(inputIndex);
     182             :     // This effects of this connection will remain.
     183           0 :     output->NotifyHasPhantomInput();
     184             :   }
     185             : 
     186           0 :   while (!mOutputParams.IsEmpty()) {
     187           0 :     size_t i = mOutputParams.Length() - 1;
     188           0 :     RefPtr<AudioParam> output = mOutputParams[i].forget();
     189           0 :     mOutputParams.RemoveElementAt(i);
     190           0 :     size_t inputIndex = FindIndexOfNode(output->InputNodes(), this);
     191             :     // It doesn't matter which one we remove, since we're going to remove all
     192             :     // entries for this node anyway.
     193           0 :     output->RemoveInputNode(inputIndex);
     194             :   }
     195             : 
     196           0 :   DestroyMediaStream();
     197           0 : }
     198             : 
     199             : AudioNode*
     200           0 : AudioNode::Connect(AudioNode& aDestination, uint32_t aOutput,
     201             :                    uint32_t aInput, ErrorResult& aRv)
     202             : {
     203           0 :   if (aOutput >= NumberOfOutputs() ||
     204           0 :       aInput >= aDestination.NumberOfInputs()) {
     205           0 :     aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     206           0 :     return nullptr;
     207             :   }
     208             : 
     209           0 :   if (Context() != aDestination.Context()) {
     210           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
     211           0 :     return nullptr;
     212             :   }
     213             : 
     214           0 :   if (FindIndexOfNodeWithPorts(aDestination.mInputNodes,
     215             :                                this, aInput, aOutput) !=
     216             :       nsTArray<AudioNode::InputNode>::NoIndex) {
     217             :     // connection already exists.
     218           0 :     return &aDestination;
     219             :   }
     220             : 
     221           0 :   WEB_AUDIO_API_LOG("%f: %s %u Connect() to %s %u",
     222             :                     Context()->CurrentTime(), NodeType(), Id(),
     223             :                     aDestination.NodeType(), aDestination.Id());
     224             : 
     225             :   // The MediaStreamGraph will handle cycle detection. We don't need to do it
     226             :   // here.
     227             : 
     228           0 :   mOutputNodes.AppendElement(&aDestination);
     229           0 :   InputNode* input = aDestination.mInputNodes.AppendElement();
     230           0 :   input->mInputNode = this;
     231           0 :   input->mInputPort = aInput;
     232           0 :   input->mOutputPort = aOutput;
     233           0 :   AudioNodeStream* destinationStream = aDestination.mStream;
     234           0 :   if (mStream && destinationStream) {
     235             :     // Connect streams in the MediaStreamGraph
     236           0 :     MOZ_ASSERT(aInput <= UINT16_MAX, "Unexpected large input port number");
     237           0 :     MOZ_ASSERT(aOutput <= UINT16_MAX, "Unexpected large output port number");
     238             :     input->mStreamPort = destinationStream->
     239           0 :       AllocateInputPort(mStream, AudioNodeStream::AUDIO_TRACK, TRACK_ANY,
     240             :                         static_cast<uint16_t>(aInput),
     241           0 :                         static_cast<uint16_t>(aOutput));
     242             :   }
     243           0 :   aDestination.NotifyInputsChanged();
     244             : 
     245             :   // This connection may have connected a panner and a source.
     246           0 :   Context()->UpdatePannerSource();
     247             : 
     248           0 :   return &aDestination;
     249             : }
     250             : 
     251             : void
     252           0 : AudioNode::Connect(AudioParam& aDestination, uint32_t aOutput,
     253             :                    ErrorResult& aRv)
     254             : {
     255           0 :   if (aOutput >= NumberOfOutputs()) {
     256           0 :     aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     257           0 :     return;
     258             :   }
     259             : 
     260           0 :   if (Context() != aDestination.GetParentObject()) {
     261           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
     262           0 :     return;
     263             :   }
     264             : 
     265           0 :   if (FindIndexOfNodeWithPorts(aDestination.InputNodes(),
     266             :                                this, INVALID_PORT, aOutput) !=
     267             :       nsTArray<AudioNode::InputNode>::NoIndex) {
     268             :     // connection already exists.
     269           0 :     return;
     270             :   }
     271             : 
     272           0 :   mOutputParams.AppendElement(&aDestination);
     273           0 :   InputNode* input = aDestination.AppendInputNode();
     274           0 :   input->mInputNode = this;
     275           0 :   input->mInputPort = INVALID_PORT;
     276           0 :   input->mOutputPort = aOutput;
     277             : 
     278           0 :   MediaStream* stream = aDestination.Stream();
     279           0 :   MOZ_ASSERT(stream->AsProcessedStream());
     280           0 :   ProcessedMediaStream* ps = static_cast<ProcessedMediaStream*>(stream);
     281           0 :   if (mStream) {
     282             :     // Setup our stream as an input to the AudioParam's stream
     283           0 :     MOZ_ASSERT(aOutput <= UINT16_MAX, "Unexpected large output port number");
     284             :     input->mStreamPort =
     285           0 :       ps->AllocateInputPort(mStream, AudioNodeStream::AUDIO_TRACK, TRACK_ANY,
     286           0 :                             0, static_cast<uint16_t>(aOutput));
     287             :   }
     288             : }
     289             : 
     290             : void
     291           0 : AudioNode::SendDoubleParameterToStream(uint32_t aIndex, double aValue)
     292             : {
     293           0 :   MOZ_ASSERT(mStream, "How come we don't have a stream here?");
     294           0 :   mStream->SetDoubleParameter(aIndex, aValue);
     295           0 : }
     296             : 
     297             : void
     298           0 : AudioNode::SendInt32ParameterToStream(uint32_t aIndex, int32_t aValue)
     299             : {
     300           0 :   MOZ_ASSERT(mStream, "How come we don't have a stream here?");
     301           0 :   mStream->SetInt32Parameter(aIndex, aValue);
     302           0 : }
     303             : 
     304             : void
     305           0 : AudioNode::SendThreeDPointParameterToStream(uint32_t aIndex,
     306             :                                             const ThreeDPoint& aValue)
     307             : {
     308           0 :   MOZ_ASSERT(mStream, "How come we don't have a stream here?");
     309           0 :   mStream->SetThreeDPointParameter(aIndex, aValue);
     310           0 : }
     311             : 
     312             : void
     313           0 : AudioNode::SendChannelMixingParametersToStream()
     314             : {
     315           0 :   if (mStream) {
     316           0 :     mStream->SetChannelMixingParameters(mChannelCount, mChannelCountMode,
     317           0 :                                         mChannelInterpretation);
     318             :   }
     319           0 : }
     320             : 
     321             : template<>
     322             : bool
     323           0 : AudioNode::DisconnectFromOutputIfConnected<AudioNode>(uint32_t aOutputNodeIndex,
     324             :                                                       uint32_t aInputIndex)
     325             : {
     326           0 :   WEB_AUDIO_API_LOG("%f: %s %u Disconnect()", Context()->CurrentTime(),
     327             :                     NodeType(), Id());
     328             : 
     329           0 :   AudioNode* destination = mOutputNodes[aOutputNodeIndex];
     330             : 
     331           0 :   MOZ_ASSERT(aOutputNodeIndex < mOutputNodes.Length());
     332           0 :   MOZ_ASSERT(aInputIndex < destination->InputNodes().Length());
     333             : 
     334             :   // An upstream node may be starting to play on the graph thread, and the
     335             :   // engine for a downstream node may be sending a PlayingRefChangeHandler
     336             :   // ADDREF message to this (main) thread.  Wait for a round trip before
     337             :   // releasing nodes, to give engines receiving sound now time to keep their
     338             :   // nodes alive.
     339           0 :   class RunnableRelease final : public Runnable
     340             :   {
     341             :   public:
     342           0 :     explicit RunnableRelease(already_AddRefed<AudioNode> aNode)
     343           0 :       : mozilla::Runnable("RunnableRelease")
     344           0 :       , mNode(aNode)
     345             :     {
     346           0 :     }
     347             : 
     348           0 :     NS_IMETHOD Run() override
     349             :     {
     350           0 :       mNode = nullptr;
     351           0 :       return NS_OK;
     352             :     }
     353             :   private:
     354             :     RefPtr<AudioNode> mNode;
     355             :   };
     356             : 
     357           0 :   InputNode& input = destination->mInputNodes[aInputIndex];
     358           0 :   if (input.mInputNode != this) {
     359           0 :     return false;
     360             :   }
     361             : 
     362             :   // Remove one instance of 'dest' from mOutputNodes. There could be
     363             :   // others, and it's not correct to remove them all since some of them
     364             :   // could be for different output ports.
     365           0 :   RefPtr<AudioNode> output = mOutputNodes[aOutputNodeIndex].forget();
     366           0 :   mOutputNodes.RemoveElementAt(aOutputNodeIndex);
     367             :   // Destroying the InputNode here sends a message to the graph thread
     368             :   // to disconnect the streams, which should be sent before the
     369             :   // RunAfterPendingUpdates() call below.
     370           0 :   destination->mInputNodes.RemoveElementAt(aInputIndex);
     371           0 :   output->NotifyInputsChanged();
     372           0 :   if (mStream) {
     373           0 :     nsCOMPtr<nsIRunnable> runnable = new RunnableRelease(output.forget());
     374           0 :     mStream->RunAfterPendingUpdates(runnable.forget());
     375             :   }
     376           0 :   return true;
     377             : }
     378             : 
     379             : template<>
     380             : bool
     381           0 : AudioNode::DisconnectFromOutputIfConnected<AudioParam>(uint32_t aOutputParamIndex,
     382             :                                                        uint32_t aInputIndex)
     383             : {
     384           0 :   MOZ_ASSERT(aOutputParamIndex < mOutputParams.Length());
     385             : 
     386           0 :   AudioParam* destination = mOutputParams[aOutputParamIndex];
     387             : 
     388           0 :   MOZ_ASSERT(aInputIndex < destination->InputNodes().Length());
     389             : 
     390           0 :   const InputNode& input = destination->InputNodes()[aInputIndex];
     391           0 :   if (input.mInputNode != this) {
     392           0 :     return false;
     393             :   }
     394           0 :   destination->RemoveInputNode(aInputIndex);
     395             :   // Remove one instance of 'dest' from mOutputParams. There could be
     396             :   // others, and it's not correct to remove them all since some of them
     397             :   // could be for different output ports.
     398           0 :   mOutputParams.RemoveElementAt(aOutputParamIndex);
     399           0 :   return true;
     400             : }
     401             : 
     402             : template<>
     403             : const nsTArray<AudioNode::InputNode>&
     404           0 : AudioNode::InputsForDestination<AudioNode>(uint32_t aOutputNodeIndex) const {
     405           0 :   return mOutputNodes[aOutputNodeIndex]->InputNodes();
     406             : }
     407             : 
     408             : template<>
     409             : const nsTArray<AudioNode::InputNode>&
     410           0 : AudioNode::InputsForDestination<AudioParam>(uint32_t aOutputNodeIndex) const {
     411           0 :   return mOutputParams[aOutputNodeIndex]->InputNodes();
     412             : }
     413             : 
     414             : template<typename DestinationType, typename Predicate>
     415             : bool
     416           0 : AudioNode::DisconnectMatchingDestinationInputs(uint32_t aDestinationIndex,
     417             :                                                Predicate aPredicate)
     418             : {
     419           0 :   bool wasConnected = false;
     420             :   uint32_t inputCount =
     421           0 :     InputsForDestination<DestinationType>(aDestinationIndex).Length();
     422             : 
     423           0 :   for (int32_t inputIndex = inputCount - 1; inputIndex >= 0; --inputIndex) {
     424             :     const InputNode& input =
     425           0 :       InputsForDestination<DestinationType>(aDestinationIndex)[inputIndex];
     426           0 :     if (aPredicate(input)) {
     427           0 :       if (DisconnectFromOutputIfConnected<DestinationType>(aDestinationIndex,
     428             :                                                            inputIndex)) {
     429           0 :         wasConnected = true;
     430           0 :         break;
     431             :       }
     432             :     }
     433             :   }
     434           0 :   return wasConnected;
     435             : }
     436             : 
     437             : void
     438           0 : AudioNode::Disconnect(ErrorResult& aRv)
     439             : {
     440           0 :   for (int32_t outputIndex = mOutputNodes.Length() - 1;
     441           0 :        outputIndex >= 0; --outputIndex) {
     442           0 :     DisconnectMatchingDestinationInputs<AudioNode>(outputIndex,
     443           0 :                                                    [](const InputNode&) {
     444             :                                                      return true;
     445           0 :                                                    });
     446             :   }
     447             : 
     448           0 :   for (int32_t outputIndex = mOutputParams.Length() - 1;
     449           0 :        outputIndex >= 0; --outputIndex) {
     450           0 :     DisconnectMatchingDestinationInputs<AudioParam>(outputIndex,
     451           0 :                                                     [](const InputNode&) {
     452             :                                                       return true;
     453           0 :                                                     });
     454             :   }
     455             : 
     456             :   // This disconnection may have disconnected a panner and a source.
     457           0 :   Context()->UpdatePannerSource();
     458           0 : }
     459             : 
     460             : void
     461           0 : AudioNode::Disconnect(uint32_t aOutput, ErrorResult& aRv)
     462             : {
     463           0 :   if (aOutput >= NumberOfOutputs()) {
     464           0 :     aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     465           0 :     return;
     466             :   }
     467             : 
     468           0 :   for (int32_t outputIndex = mOutputNodes.Length() - 1;
     469           0 :        outputIndex >= 0; --outputIndex) {
     470           0 :     DisconnectMatchingDestinationInputs<AudioNode>(
     471             :         outputIndex,
     472           0 :         [aOutput](const InputNode& aInputNode) {
     473           0 :           return aInputNode.mOutputPort == aOutput;
     474           0 :         });
     475             :   }
     476             : 
     477           0 :   for (int32_t outputIndex = mOutputParams.Length() - 1;
     478           0 :        outputIndex >= 0; --outputIndex) {
     479           0 :     DisconnectMatchingDestinationInputs<AudioParam>(
     480             :         outputIndex,
     481           0 :         [aOutput](const InputNode& aInputNode) {
     482           0 :           return aInputNode.mOutputPort == aOutput;
     483           0 :         });
     484             :   }
     485             : 
     486             :   // This disconnection may have disconnected a panner and a source.
     487           0 :   Context()->UpdatePannerSource();
     488             : }
     489             : 
     490             : void
     491           0 : AudioNode::Disconnect(AudioNode& aDestination, ErrorResult& aRv)
     492             : {
     493           0 :   bool wasConnected = false;
     494             : 
     495           0 :   for (int32_t outputIndex = mOutputNodes.Length() - 1;
     496           0 :        outputIndex >= 0; --outputIndex) {
     497           0 :     if (mOutputNodes[outputIndex] != &aDestination) {
     498           0 :       continue;
     499             :     }
     500           0 :     wasConnected |=
     501           0 :       DisconnectMatchingDestinationInputs<AudioNode>(outputIndex,
     502           0 :                                                      [](const InputNode&) {
     503             :                                                        return true;
     504           0 :                                                      });
     505             :   }
     506             : 
     507           0 :   if (!wasConnected) {
     508           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
     509           0 :     return;
     510             :   }
     511             : 
     512             :   // This disconnection may have disconnected a panner and a source.
     513           0 :   Context()->UpdatePannerSource();
     514             : }
     515             : 
     516             : void
     517           0 : AudioNode::Disconnect(AudioNode& aDestination,
     518             :                       uint32_t aOutput,
     519             :                       ErrorResult& aRv)
     520             : {
     521           0 :   if (aOutput >= NumberOfOutputs()) {
     522           0 :     aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     523           0 :     return;
     524             :   }
     525             : 
     526           0 :   bool wasConnected = false;
     527             : 
     528           0 :   for (int32_t outputIndex = mOutputNodes.Length() - 1;
     529           0 :        outputIndex >= 0; --outputIndex) {
     530           0 :     if (mOutputNodes[outputIndex] != &aDestination) {
     531           0 :       continue;
     532             :     }
     533           0 :     wasConnected |=
     534           0 :       DisconnectMatchingDestinationInputs<AudioNode>(
     535             :           outputIndex,
     536           0 :           [aOutput](const InputNode& aInputNode) {
     537           0 :             return aInputNode.mOutputPort == aOutput;
     538           0 :           });
     539             :   }
     540             : 
     541           0 :   if (!wasConnected) {
     542           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
     543           0 :     return;
     544             :   }
     545             : 
     546             :   // This disconnection may have disconnected a panner and a source.
     547           0 :   Context()->UpdatePannerSource();
     548             : }
     549             : 
     550             : void
     551           0 : AudioNode::Disconnect(AudioNode& aDestination,
     552             :                       uint32_t aOutput,
     553             :                       uint32_t aInput,
     554             :                       ErrorResult& aRv)
     555             : {
     556           0 :   if (aOutput >= NumberOfOutputs()) {
     557           0 :     aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     558           0 :     return;
     559             :   }
     560             : 
     561           0 :   if (aInput >= aDestination.NumberOfInputs()) {
     562           0 :     aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     563           0 :     return;
     564             :   }
     565             : 
     566           0 :   bool wasConnected = false;
     567             : 
     568           0 :   for (int32_t outputIndex = mOutputNodes.Length() - 1;
     569           0 :        outputIndex >= 0; --outputIndex) {
     570           0 :     if (mOutputNodes[outputIndex] != &aDestination) {
     571           0 :       continue;
     572             :     }
     573           0 :     wasConnected |=
     574           0 :       DisconnectMatchingDestinationInputs<AudioNode>(
     575             :           outputIndex,
     576           0 :           [aOutput, aInput](const InputNode& aInputNode) {
     577           0 :             return aInputNode.mOutputPort == aOutput &&
     578           0 :                    aInputNode.mInputPort == aInput;
     579           0 :           });
     580             :   }
     581             : 
     582           0 :   if (!wasConnected) {
     583           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
     584           0 :     return;
     585             :   }
     586             : 
     587             :   // This disconnection may have disconnected a panner and a source.
     588           0 :   Context()->UpdatePannerSource();
     589             : }
     590             : 
     591             : void
     592           0 : AudioNode::Disconnect(AudioParam& aDestination, ErrorResult& aRv)
     593             : {
     594           0 :   bool wasConnected = false;
     595             : 
     596           0 :   for (int32_t outputIndex = mOutputParams.Length() - 1;
     597           0 :        outputIndex >= 0; --outputIndex) {
     598           0 :     if (mOutputParams[outputIndex] != &aDestination) {
     599           0 :       continue;
     600             :     }
     601           0 :     wasConnected |=
     602           0 :       DisconnectMatchingDestinationInputs<AudioParam>(outputIndex,
     603           0 :                                                       [](const InputNode&) {
     604             :                                                         return true;
     605           0 :                                                       });
     606             :   }
     607             : 
     608           0 :   if (!wasConnected) {
     609           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
     610           0 :     return;
     611             :   }
     612             : }
     613             : 
     614             : void
     615           0 : AudioNode::Disconnect(AudioParam& aDestination,
     616             :                       uint32_t aOutput,
     617             :                       ErrorResult& aRv)
     618             : {
     619           0 :   if (aOutput >= NumberOfOutputs()) {
     620           0 :     aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     621           0 :     return;
     622             :   }
     623             : 
     624           0 :   bool wasConnected = false;
     625             : 
     626           0 :   for (int32_t outputIndex = mOutputParams.Length() - 1;
     627           0 :        outputIndex >= 0; --outputIndex) {
     628           0 :     if (mOutputParams[outputIndex] != &aDestination) {
     629           0 :       continue;
     630             :     }
     631           0 :     wasConnected |=
     632           0 :       DisconnectMatchingDestinationInputs<AudioParam>(
     633             :           outputIndex,
     634           0 :           [aOutput](const InputNode& aInputNode) {
     635           0 :             return aInputNode.mOutputPort == aOutput;
     636           0 :           });
     637             :   }
     638             : 
     639           0 :   if (!wasConnected) {
     640           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
     641           0 :     return;
     642             :   }
     643             : }
     644             : 
     645             : void
     646           0 : AudioNode::DestroyMediaStream()
     647             : {
     648           0 :   if (mStream) {
     649             :     // Remove the node pointer on the engine.
     650           0 :     AudioNodeStream* ns = mStream;
     651           0 :     MOZ_ASSERT(ns, "How come we don't have a stream here?");
     652           0 :     MOZ_ASSERT(ns->Engine()->NodeMainThread() == this,
     653             :                "Invalid node reference");
     654           0 :     ns->Engine()->ClearNode();
     655             : 
     656           0 :     mStream->Destroy();
     657           0 :     mStream = nullptr;
     658             : 
     659           0 :     nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
     660           0 :     if (obs) {
     661           0 :       nsAutoString id;
     662           0 :       id.AppendPrintf("%u", mId);
     663           0 :       obs->NotifyObservers(nullptr, "webaudio-node-demise", id.get());
     664             :     }
     665             :   }
     666           0 : }
     667             : 
     668             : void
     669           0 : AudioNode::RemoveOutputParam(AudioParam* aParam)
     670             : {
     671           0 :   mOutputParams.RemoveElement(aParam);
     672           0 : }
     673             : 
     674             : bool
     675           0 : AudioNode::PassThrough() const
     676             : {
     677           0 :   MOZ_ASSERT(NumberOfInputs() <= 1 && NumberOfOutputs() == 1);
     678           0 :   return mPassThrough;
     679             : }
     680             : 
     681             : void
     682           0 : AudioNode::SetPassThrough(bool aPassThrough)
     683             : {
     684           0 :   MOZ_ASSERT(NumberOfInputs() <= 1 && NumberOfOutputs() == 1);
     685           0 :   mPassThrough = aPassThrough;
     686           0 :   if (mStream) {
     687           0 :     mStream->SetPassThrough(mPassThrough);
     688             :   }
     689           0 : }
     690             : 
     691             : } // namespace dom
     692             : } // namespace mozilla

Generated by: LCOV version 1.13