LCOV - code coverage report
Current view: top level - dom/media/webaudio - DelayNode.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 105 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 21 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 "DelayNode.h"
       8             : #include "mozilla/dom/DelayNodeBinding.h"
       9             : #include "AudioNodeEngine.h"
      10             : #include "AudioNodeStream.h"
      11             : #include "AudioDestinationNode.h"
      12             : #include "WebAudioUtils.h"
      13             : #include "DelayBuffer.h"
      14             : #include "PlayingRefChangeHandler.h"
      15             : 
      16             : namespace mozilla {
      17             : namespace dom {
      18             : 
      19           0 : NS_IMPL_CYCLE_COLLECTION_INHERITED(DelayNode, AudioNode,
      20             :                                    mDelay)
      21             : 
      22           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DelayNode)
      23           0 : NS_INTERFACE_MAP_END_INHERITING(AudioNode)
      24             : 
      25           0 : NS_IMPL_ADDREF_INHERITED(DelayNode, AudioNode)
      26           0 : NS_IMPL_RELEASE_INHERITED(DelayNode, AudioNode)
      27             : 
      28           0 : class DelayNodeEngine final : public AudioNodeEngine
      29             : {
      30             :   typedef PlayingRefChangeHandler PlayingRefChanged;
      31             : public:
      32           0 :   DelayNodeEngine(AudioNode* aNode, AudioDestinationNode* aDestination,
      33             :                   double aMaxDelayTicks)
      34           0 :     : AudioNodeEngine(aNode)
      35           0 :     , mDestination(aDestination->Stream())
      36             :     // Keep the default value in sync with the default value in DelayNode::DelayNode.
      37             :     , mDelay(0.f)
      38             :     // Use a smoothing range of 20ms
      39             :     , mBuffer(std::max(aMaxDelayTicks,
      40           0 :                        static_cast<double>(WEBAUDIO_BLOCK_SIZE)),
      41             :               WebAudioUtils::ComputeSmoothingRate(0.02,
      42           0 :                                                   mDestination->SampleRate()))
      43             :     , mMaxDelay(aMaxDelayTicks)
      44             :     , mHaveProducedBeforeInput(false)
      45           0 :     , mLeftOverData(INT32_MIN)
      46             :   {
      47           0 :   }
      48             : 
      49           0 :   DelayNodeEngine* AsDelayNodeEngine() override
      50             :   {
      51           0 :     return this;
      52             :   }
      53             : 
      54             :   enum Parameters {
      55             :     DELAY,
      56             :   };
      57           0 :   void RecvTimelineEvent(uint32_t aIndex,
      58             :                          AudioTimelineEvent& aEvent) override
      59             :   {
      60           0 :     MOZ_ASSERT(mDestination);
      61           0 :     WebAudioUtils::ConvertAudioTimelineEventToTicks(aEvent,
      62           0 :                                                     mDestination);
      63             : 
      64           0 :     switch (aIndex) {
      65             :     case DELAY:
      66           0 :       mDelay.InsertEvent<int64_t>(aEvent);
      67           0 :       break;
      68             :     default:
      69           0 :       NS_ERROR("Bad DelayNodeEngine TimelineParameter");
      70             :     }
      71           0 :   }
      72             : 
      73           0 :   void ProcessBlock(AudioNodeStream* aStream,
      74             :                     GraphTime aFrom,
      75             :                     const AudioBlock& aInput,
      76             :                     AudioBlock* aOutput,
      77             :                     bool* aFinished) override
      78             :   {
      79           0 :     MOZ_ASSERT(aStream->SampleRate() == mDestination->SampleRate());
      80             : 
      81           0 :     if (!aInput.IsSilentOrSubnormal()) {
      82           0 :       if (mLeftOverData <= 0) {
      83             :         RefPtr<PlayingRefChanged> refchanged =
      84           0 :           new PlayingRefChanged(aStream, PlayingRefChanged::ADDREF);
      85           0 :         aStream->Graph()->DispatchToMainThreadAfterStreamStateUpdate(
      86           0 :           refchanged.forget());
      87             :       }
      88           0 :       mLeftOverData = mBuffer.MaxDelayTicks();
      89           0 :     } else if (mLeftOverData > 0) {
      90           0 :       mLeftOverData -= WEBAUDIO_BLOCK_SIZE;
      91             :     } else {
      92           0 :       if (mLeftOverData != INT32_MIN) {
      93           0 :         mLeftOverData = INT32_MIN;
      94           0 :         aStream->ScheduleCheckForInactive();
      95             : 
      96             :         // Delete our buffered data now we no longer need it
      97           0 :         mBuffer.Reset();
      98             : 
      99             :         RefPtr<PlayingRefChanged> refchanged =
     100           0 :           new PlayingRefChanged(aStream, PlayingRefChanged::RELEASE);
     101           0 :         aStream->Graph()->DispatchToMainThreadAfterStreamStateUpdate(
     102           0 :           refchanged.forget());
     103             :       }
     104           0 :       aOutput->SetNull(WEBAUDIO_BLOCK_SIZE);
     105           0 :       return;
     106             :     }
     107             : 
     108           0 :     mBuffer.Write(aInput);
     109             : 
     110             :     // Skip output update if mLastChunks has already been set by
     111             :     // ProduceBlockBeforeInput() when in a cycle.
     112           0 :     if (!mHaveProducedBeforeInput) {
     113           0 :       UpdateOutputBlock(aStream, aFrom, aOutput, 0.0);
     114             :     }
     115           0 :     mHaveProducedBeforeInput = false;
     116           0 :     mBuffer.NextBlock();
     117             :   }
     118             : 
     119           0 :   void UpdateOutputBlock(AudioNodeStream* aStream, GraphTime aFrom,
     120             :                          AudioBlock* aOutput, double minDelay)
     121             :   {
     122           0 :     double maxDelay = mMaxDelay;
     123           0 :     double sampleRate = aStream->SampleRate();
     124             :     ChannelInterpretation channelInterpretation =
     125           0 :       aStream->GetChannelInterpretation();
     126           0 :     if (mDelay.HasSimpleValue()) {
     127             :       // If this DelayNode is in a cycle, make sure the delay value is at least
     128             :       // one block, even if that is greater than maxDelay.
     129           0 :       double delayFrames = mDelay.GetValue() * sampleRate;
     130             :       double delayFramesClamped =
     131           0 :         std::max(minDelay, std::min(delayFrames, maxDelay));
     132           0 :       mBuffer.Read(delayFramesClamped, aOutput, channelInterpretation);
     133             :     } else {
     134             :       // Compute the delay values for the duration of the input AudioChunk
     135             :       // If this DelayNode is in a cycle, make sure the delay value is at least
     136             :       // one block.
     137           0 :       StreamTime tick = mDestination->GraphTimeToStreamTime(aFrom);
     138             :       float values[WEBAUDIO_BLOCK_SIZE];
     139           0 :       mDelay.GetValuesAtTime(tick, values,WEBAUDIO_BLOCK_SIZE);
     140             : 
     141             :       double computedDelay[WEBAUDIO_BLOCK_SIZE];
     142           0 :       for (size_t counter = 0; counter < WEBAUDIO_BLOCK_SIZE; ++counter) {
     143           0 :         double delayAtTick = values[counter] * sampleRate;
     144             :         double delayAtTickClamped =
     145           0 :           std::max(minDelay, std::min(delayAtTick, maxDelay));
     146           0 :         computedDelay[counter] = delayAtTickClamped;
     147             :       }
     148           0 :       mBuffer.Read(computedDelay, aOutput, channelInterpretation);
     149             :     }
     150           0 :   }
     151             : 
     152           0 :   void ProduceBlockBeforeInput(AudioNodeStream* aStream,
     153             :                                GraphTime aFrom,
     154             :                                AudioBlock* aOutput) override
     155             :   {
     156           0 :     if (mLeftOverData <= 0) {
     157           0 :       aOutput->SetNull(WEBAUDIO_BLOCK_SIZE);
     158             :     } else {
     159           0 :       UpdateOutputBlock(aStream, aFrom, aOutput, WEBAUDIO_BLOCK_SIZE);
     160             :     }
     161           0 :     mHaveProducedBeforeInput = true;
     162           0 :   }
     163             : 
     164           0 :   bool IsActive() const override
     165             :   {
     166           0 :     return mLeftOverData != INT32_MIN;
     167             :   }
     168             : 
     169           0 :   size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override
     170             :   {
     171           0 :     size_t amount = AudioNodeEngine::SizeOfExcludingThis(aMallocSizeOf);
     172             :     // Not owned:
     173             :     // - mDestination - probably not owned
     174             :     // - mDelay - shares ref with AudioNode, don't count
     175           0 :     amount += mBuffer.SizeOfExcludingThis(aMallocSizeOf);
     176           0 :     return amount;
     177             :   }
     178             : 
     179           0 :   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override
     180             :   {
     181           0 :     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
     182             :   }
     183             : 
     184             :   AudioNodeStream* mDestination;
     185             :   AudioParamTimeline mDelay;
     186             :   DelayBuffer mBuffer;
     187             :   double mMaxDelay;
     188             :   bool mHaveProducedBeforeInput;
     189             :   // How much data we have in our buffer which needs to be flushed out when our inputs
     190             :   // finish.
     191             :   int32_t mLeftOverData;
     192             : };
     193             : 
     194           0 : DelayNode::DelayNode(AudioContext* aContext, double aMaxDelay)
     195             :   : AudioNode(aContext,
     196             :               2,
     197             :               ChannelCountMode::Max,
     198             :               ChannelInterpretation::Speakers)
     199             :   , mDelay(new AudioParam(this, DelayNodeEngine::DELAY, "delayTime", 0.0f,
     200           0 :                           0.f, aMaxDelay))
     201             : {
     202             :   DelayNodeEngine* engine =
     203           0 :     new DelayNodeEngine(this, aContext->Destination(),
     204           0 :                         aContext->SampleRate() * aMaxDelay);
     205           0 :   mStream = AudioNodeStream::Create(aContext, engine,
     206             :                                     AudioNodeStream::NO_STREAM_FLAGS,
     207           0 :                                     aContext->Graph());
     208           0 : }
     209             : 
     210             : /* static */ already_AddRefed<DelayNode>
     211           0 : DelayNode::Create(AudioContext& aAudioContext,
     212             :                   const DelayOptions& aOptions,
     213             :                   ErrorResult& aRv)
     214             : {
     215           0 :   if (aAudioContext.CheckClosed(aRv)) {
     216           0 :     return nullptr;
     217             :   }
     218             : 
     219           0 :   if (aOptions.mMaxDelayTime <= 0. || aOptions.mMaxDelayTime >= 180.) {
     220           0 :     aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
     221           0 :     return nullptr;
     222             :   }
     223             : 
     224             :   RefPtr<DelayNode> audioNode = new DelayNode(&aAudioContext,
     225           0 :                                               aOptions.mMaxDelayTime);
     226             : 
     227           0 :   audioNode->Initialize(aOptions, aRv);
     228           0 :   if (NS_WARN_IF(aRv.Failed())) {
     229           0 :     return nullptr;
     230             :   }
     231             : 
     232           0 :   audioNode->DelayTime()->SetValue(aOptions.mDelayTime);
     233           0 :   return audioNode.forget();
     234             : }
     235             : 
     236             : size_t
     237           0 : DelayNode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
     238             : {
     239           0 :   size_t amount = AudioNode::SizeOfExcludingThis(aMallocSizeOf);
     240           0 :   amount += mDelay->SizeOfIncludingThis(aMallocSizeOf);
     241           0 :   return amount;
     242             : }
     243             : 
     244             : size_t
     245           0 : DelayNode::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
     246             : {
     247           0 :   return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
     248             : }
     249             : 
     250             : JSObject*
     251           0 : DelayNode::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
     252             : {
     253           0 :   return DelayNodeBinding::Wrap(aCx, this, aGivenProto);
     254             : }
     255             : 
     256             : } // namespace dom
     257             : } // namespace mozilla

Generated by: LCOV version 1.13