LCOV - code coverage report
Current view: top level - dom/media/webaudio - OscillatorNode.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 284 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 39 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 "OscillatorNode.h"
       8             : #include "AudioNodeEngine.h"
       9             : #include "AudioNodeStream.h"
      10             : #include "AudioDestinationNode.h"
      11             : #include "nsContentUtils.h"
      12             : #include "WebAudioUtils.h"
      13             : #include "blink/PeriodicWave.h"
      14             : 
      15             : namespace mozilla {
      16             : namespace dom {
      17             : 
      18           0 : NS_IMPL_CYCLE_COLLECTION_INHERITED(OscillatorNode, AudioScheduledSourceNode,
      19             :                                    mPeriodicWave, mFrequency, mDetune)
      20             : 
      21           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(OscillatorNode)
      22           0 : NS_INTERFACE_MAP_END_INHERITING(AudioScheduledSourceNode)
      23             : 
      24           0 : NS_IMPL_ADDREF_INHERITED(OscillatorNode, AudioScheduledSourceNode)
      25           0 : NS_IMPL_RELEASE_INHERITED(OscillatorNode, AudioScheduledSourceNode)
      26             : 
      27           0 : class OscillatorNodeEngine final : public AudioNodeEngine
      28             : {
      29             : public:
      30           0 :   OscillatorNodeEngine(AudioNode* aNode, AudioDestinationNode* aDestination)
      31           0 :     : AudioNodeEngine(aNode)
      32             :     , mSource(nullptr)
      33           0 :     , mDestination(aDestination->Stream())
      34             :     , mStart(-1)
      35             :     , mStop(STREAM_TIME_MAX)
      36             :     // Keep the default values in sync with OscillatorNode::OscillatorNode.
      37             :     , mFrequency(440.f)
      38             :     , mDetune(0.f)
      39             :     , mType(OscillatorType::Sine)
      40             :     , mPhase(0.)
      41             :     , mFinalFrequency(0.)
      42             :     , mPhaseIncrement(0.)
      43             :     , mRecomputeParameters(true)
      44             :     , mCustomLength(0)
      45           0 :     , mCustomDisableNormalization(false)
      46             :   {
      47           0 :     MOZ_ASSERT(NS_IsMainThread());
      48           0 :     mBasicWaveFormCache = aDestination->Context()->GetBasicWaveFormCache();
      49           0 :   }
      50             : 
      51           0 :   void SetSourceStream(AudioNodeStream* aSource)
      52             :   {
      53           0 :     mSource = aSource;
      54           0 :   }
      55             : 
      56             :   enum Parameters {
      57             :     FREQUENCY,
      58             :     DETUNE,
      59             :     TYPE,
      60             :     PERIODICWAVE_LENGTH,
      61             :     DISABLE_NORMALIZATION,
      62             :     START,
      63             :     STOP,
      64             :   };
      65           0 :   void RecvTimelineEvent(uint32_t aIndex,
      66             :                          AudioTimelineEvent& aEvent) override
      67             :   {
      68           0 :     mRecomputeParameters = true;
      69             : 
      70           0 :     MOZ_ASSERT(mDestination);
      71             : 
      72           0 :     WebAudioUtils::ConvertAudioTimelineEventToTicks(aEvent,
      73           0 :                                                     mDestination);
      74             : 
      75           0 :     switch (aIndex) {
      76             :     case FREQUENCY:
      77           0 :       mFrequency.InsertEvent<int64_t>(aEvent);
      78           0 :       break;
      79             :     case DETUNE:
      80           0 :       mDetune.InsertEvent<int64_t>(aEvent);
      81           0 :       break;
      82             :     default:
      83           0 :       NS_ERROR("Bad OscillatorNodeEngine TimelineParameter");
      84             :     }
      85           0 :   }
      86             : 
      87           0 :   void SetStreamTimeParameter(uint32_t aIndex, StreamTime aParam) override
      88             :   {
      89           0 :     switch (aIndex) {
      90             :     case START:
      91           0 :       mStart = aParam;
      92           0 :       mSource->SetActive();
      93           0 :       break;
      94           0 :     case STOP: mStop = aParam; break;
      95             :     default:
      96           0 :       NS_ERROR("Bad OscillatorNodeEngine StreamTimeParameter");
      97             :     }
      98           0 :   }
      99             : 
     100           0 :   void SetInt32Parameter(uint32_t aIndex, int32_t aParam) override
     101             :   {
     102           0 :     switch (aIndex) {
     103             :       case TYPE:
     104             :         // Set the new type.
     105           0 :         mType = static_cast<OscillatorType>(aParam);
     106           0 :         if (mType == OscillatorType::Sine) {
     107             :           // Forget any previous custom data.
     108           0 :           mCustomLength = 0;
     109           0 :           mCustomDisableNormalization = false;
     110           0 :           mCustom = nullptr;
     111           0 :           mPeriodicWave = nullptr;
     112           0 :           mRecomputeParameters = true;
     113             :         }
     114           0 :         switch (mType) {
     115             :           case OscillatorType::Sine:
     116           0 :             mPhase = 0.0;
     117           0 :             break;
     118             :           case OscillatorType::Square:
     119             :           case OscillatorType::Triangle:
     120             :           case OscillatorType::Sawtooth:
     121           0 :             mPeriodicWave = mBasicWaveFormCache->GetBasicWaveForm(mType);
     122           0 :             break;
     123             :           case OscillatorType::Custom:
     124           0 :             break;
     125             :           default:
     126           0 :             NS_ERROR("Bad OscillatorNodeEngine type parameter.");
     127             :         }
     128             :         // End type switch.
     129           0 :         break;
     130             :       case PERIODICWAVE_LENGTH:
     131           0 :         MOZ_ASSERT(aParam >= 0, "negative custom array length");
     132           0 :         mCustomLength = static_cast<uint32_t>(aParam);
     133           0 :         break;
     134             :       case DISABLE_NORMALIZATION:
     135           0 :         MOZ_ASSERT(aParam >= 0, "negative custom array length");
     136           0 :         mCustomDisableNormalization = static_cast<uint32_t>(aParam);
     137           0 :         break;
     138             :       default:
     139           0 :         NS_ERROR("Bad OscillatorNodeEngine Int32Parameter.");
     140             :     }
     141             :     // End index switch.
     142           0 :   }
     143             : 
     144           0 :   void SetBuffer(already_AddRefed<ThreadSharedFloatArrayBufferList> aBuffer) override
     145             :   {
     146           0 :     MOZ_ASSERT(mCustomLength, "Custom buffer sent before length");
     147           0 :     mCustom = aBuffer;
     148           0 :     MOZ_ASSERT(mCustom->GetChannels() == 2,
     149             :                "PeriodicWave should have sent two channels");
     150           0 :     mPeriodicWave = WebCore::PeriodicWave::create(mSource->SampleRate(),
     151             :                                                   mCustom->GetData(0),
     152             :                                                   mCustom->GetData(1),
     153           0 :                                                   mCustomLength,
     154           0 :                                                   mCustomDisableNormalization);
     155           0 :   }
     156             : 
     157           0 :   void IncrementPhase()
     158             :   {
     159           0 :     const float twoPiFloat = float(2 * M_PI);
     160           0 :     mPhase += mPhaseIncrement;
     161           0 :     if (mPhase > twoPiFloat) {
     162           0 :       mPhase -= twoPiFloat;
     163           0 :     } else if (mPhase < -twoPiFloat) {
     164           0 :       mPhase += twoPiFloat;
     165             :     }
     166           0 :   }
     167             : 
     168             :   // Returns true if the final frequency (and thus the phase increment) changed,
     169             :   // false otherwise. This allow some optimizations at callsite.
     170           0 :   bool UpdateParametersIfNeeded(StreamTime ticks, size_t count)
     171             :   {
     172             :     double frequency, detune;
     173             : 
     174             :     // Shortcut if frequency-related AudioParam are not automated, and we
     175             :     // already have computed the frequency information and related parameters.
     176           0 :     if (!ParametersMayNeedUpdate()) {
     177           0 :       return false;
     178             :     }
     179             : 
     180           0 :     bool simpleFrequency = mFrequency.HasSimpleValue();
     181           0 :     bool simpleDetune = mDetune.HasSimpleValue();
     182             : 
     183           0 :     if (simpleFrequency) {
     184           0 :       frequency = mFrequency.GetValue();
     185             :     } else {
     186           0 :       frequency = mFrequency.GetValueAtTime(ticks, count);
     187             :     }
     188           0 :     if (simpleDetune) {
     189           0 :       detune = mDetune.GetValue();
     190             :     } else {
     191           0 :       detune = mDetune.GetValueAtTime(ticks, count);
     192             :     }
     193             : 
     194           0 :     float finalFrequency = frequency * pow(2., detune / 1200.);
     195           0 :     float signalPeriod = mSource->SampleRate() / finalFrequency;
     196           0 :     mRecomputeParameters = false;
     197             : 
     198           0 :     mPhaseIncrement = 2 * M_PI / signalPeriod;
     199             : 
     200           0 :     if (finalFrequency != mFinalFrequency) {
     201           0 :       mFinalFrequency = finalFrequency;
     202           0 :       return true;
     203             :     }
     204           0 :     return false;
     205             :   }
     206             : 
     207           0 :   void FillBounds(float* output, StreamTime ticks,
     208             :                   uint32_t& start, uint32_t& end)
     209             :   {
     210           0 :     MOZ_ASSERT(output);
     211             :     static_assert(StreamTime(WEBAUDIO_BLOCK_SIZE) < UINT_MAX,
     212             :         "WEBAUDIO_BLOCK_SIZE overflows interator bounds.");
     213           0 :     start = 0;
     214           0 :     if (ticks < mStart) {
     215           0 :       start = mStart - ticks;
     216           0 :       for (uint32_t i = 0; i < start; ++i) {
     217           0 :         output[i] = 0.0;
     218             :       }
     219             :     }
     220           0 :     end = WEBAUDIO_BLOCK_SIZE;
     221           0 :     if (ticks + end > mStop) {
     222           0 :       end = mStop - ticks;
     223           0 :       for (uint32_t i = end; i < WEBAUDIO_BLOCK_SIZE; ++i) {
     224           0 :         output[i] = 0.0;
     225             :       }
     226             :     }
     227           0 :   }
     228             : 
     229           0 :   void ComputeSine(float * aOutput, StreamTime ticks, uint32_t aStart, uint32_t aEnd)
     230             :   {
     231           0 :     for (uint32_t i = aStart; i < aEnd; ++i) {
     232             :       // We ignore the return value, changing the frequency has no impact on
     233             :       // performances here.
     234           0 :       UpdateParametersIfNeeded(ticks, i);
     235             : 
     236           0 :       aOutput[i] = sin(mPhase);
     237             : 
     238           0 :       IncrementPhase();
     239             :     }
     240           0 :   }
     241             : 
     242           0 :   bool ParametersMayNeedUpdate()
     243             :   {
     244           0 :     return !mDetune.HasSimpleValue() ||
     245           0 :            !mFrequency.HasSimpleValue() ||
     246           0 :            mRecomputeParameters;
     247             :   }
     248             : 
     249           0 :   void ComputeCustom(float* aOutput,
     250             :                      StreamTime ticks,
     251             :                      uint32_t aStart,
     252             :                      uint32_t aEnd)
     253             :   {
     254           0 :     MOZ_ASSERT(mPeriodicWave, "No custom waveform data");
     255             : 
     256           0 :     uint32_t periodicWaveSize = mPeriodicWave->periodicWaveSize();
     257             :     // Mask to wrap wave data indices into the range [0,periodicWaveSize).
     258           0 :     uint32_t indexMask = periodicWaveSize - 1;
     259           0 :     MOZ_ASSERT(periodicWaveSize && (periodicWaveSize & indexMask) == 0,
     260             :                "periodicWaveSize must be power of 2");
     261           0 :     float* higherWaveData = nullptr;
     262           0 :     float* lowerWaveData = nullptr;
     263             :     float tableInterpolationFactor;
     264             :     // Phase increment at frequency of 1 Hz.
     265             :     // mPhase runs [0,periodicWaveSize) here instead of [0,2*M_PI).
     266           0 :     float basePhaseIncrement = mPeriodicWave->rateScale();
     267             : 
     268           0 :     bool needToFetchWaveData = UpdateParametersIfNeeded(ticks, aStart);
     269             : 
     270           0 :     bool parametersMayNeedUpdate = ParametersMayNeedUpdate();
     271           0 :     mPeriodicWave->waveDataForFundamentalFrequency(mFinalFrequency,
     272             :                                                    lowerWaveData,
     273             :                                                    higherWaveData,
     274           0 :                                                    tableInterpolationFactor);
     275             : 
     276           0 :     for (uint32_t i = aStart; i < aEnd; ++i) {
     277           0 :       if (parametersMayNeedUpdate) {
     278           0 :         if (needToFetchWaveData) {
     279           0 :           mPeriodicWave->waveDataForFundamentalFrequency(mFinalFrequency,
     280             :                                                          lowerWaveData,
     281             :                                                          higherWaveData,
     282           0 :                                                          tableInterpolationFactor);
     283             :         }
     284           0 :         needToFetchWaveData = UpdateParametersIfNeeded(ticks, i);
     285             :       }
     286             :       // Bilinear interpolation between adjacent samples in each table.
     287           0 :       float floorPhase = floorf(mPhase);
     288           0 :       int j1Signed = static_cast<int>(floorPhase);
     289           0 :       uint32_t j1 = j1Signed & indexMask;
     290           0 :       uint32_t j2 = j1 + 1;
     291           0 :       j2 &= indexMask;
     292             : 
     293           0 :       float sampleInterpolationFactor = mPhase - floorPhase;
     294             : 
     295           0 :       float lower = (1.0f - sampleInterpolationFactor) * lowerWaveData[j1] +
     296           0 :                     sampleInterpolationFactor * lowerWaveData[j2];
     297           0 :       float higher = (1.0f - sampleInterpolationFactor) * higherWaveData[j1] +
     298           0 :                     sampleInterpolationFactor * higherWaveData[j2];
     299           0 :       aOutput[i] = (1.0f - tableInterpolationFactor) * lower +
     300           0 :                    tableInterpolationFactor * higher;
     301             : 
     302             :       // Calculate next phase position from wrapped value j1 to avoid loss of
     303             :       // precision at large values.
     304           0 :       mPhase =
     305           0 :         j1 + sampleInterpolationFactor + basePhaseIncrement * mFinalFrequency;
     306             :     }
     307           0 :   }
     308             : 
     309           0 :   void ComputeSilence(AudioBlock *aOutput)
     310             :   {
     311           0 :     aOutput->SetNull(WEBAUDIO_BLOCK_SIZE);
     312           0 :   }
     313             : 
     314           0 :   void ProcessBlock(AudioNodeStream* aStream,
     315             :                     GraphTime aFrom,
     316             :                     const AudioBlock& aInput,
     317             :                     AudioBlock* aOutput,
     318             :                     bool* aFinished) override
     319             :   {
     320           0 :     MOZ_ASSERT(mSource == aStream, "Invalid source stream");
     321             : 
     322           0 :     StreamTime ticks = mDestination->GraphTimeToStreamTime(aFrom);
     323           0 :     if (mStart == -1) {
     324           0 :       ComputeSilence(aOutput);
     325           0 :       return;
     326             :     }
     327             : 
     328           0 :     if (ticks + WEBAUDIO_BLOCK_SIZE <= mStart || ticks >= mStop) {
     329           0 :       ComputeSilence(aOutput);
     330             : 
     331             :     } else {
     332           0 :       aOutput->AllocateChannels(1);
     333           0 :       float* output = aOutput->ChannelFloatsForWrite(0);
     334             : 
     335             :       uint32_t start, end;
     336           0 :       FillBounds(output, ticks, start, end);
     337             : 
     338             :       // Synthesize the correct waveform.
     339           0 :       switch(mType) {
     340             :         case OscillatorType::Sine:
     341           0 :           ComputeSine(output, ticks, start, end);
     342           0 :           break;
     343             :         case OscillatorType::Square:
     344             :         case OscillatorType::Triangle:
     345             :         case OscillatorType::Sawtooth:
     346             :         case OscillatorType::Custom:
     347           0 :           ComputeCustom(output, ticks, start, end);
     348           0 :           break;
     349             :         default:
     350           0 :           ComputeSilence(aOutput);
     351             :       };
     352             :     }
     353             : 
     354           0 :     if (ticks + WEBAUDIO_BLOCK_SIZE >= mStop) {
     355             :       // We've finished playing.
     356           0 :       *aFinished = true;
     357             :     }
     358             :   }
     359             : 
     360           0 :   bool IsActive() const override
     361             :   {
     362             :     // start() has been called.
     363           0 :     return mStart != -1;
     364             :   }
     365             : 
     366           0 :   size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override
     367             :   {
     368           0 :     size_t amount = AudioNodeEngine::SizeOfExcludingThis(aMallocSizeOf);
     369             : 
     370             :     // Not owned:
     371             :     // - mSource
     372             :     // - mDestination
     373             :     // - mFrequency (internal ref owned by node)
     374             :     // - mDetune (internal ref owned by node)
     375             : 
     376           0 :     if (mCustom) {
     377           0 :       amount += mCustom->SizeOfIncludingThis(aMallocSizeOf);
     378             :     }
     379             : 
     380           0 :     if (mPeriodicWave) {
     381           0 :       amount += mPeriodicWave->sizeOfIncludingThis(aMallocSizeOf);
     382             :     }
     383             : 
     384           0 :     return amount;
     385             :   }
     386             : 
     387           0 :   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override
     388             :   {
     389           0 :     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
     390             :   }
     391             : 
     392             :   AudioNodeStream* mSource;
     393             :   AudioNodeStream* mDestination;
     394             :   StreamTime mStart;
     395             :   StreamTime mStop;
     396             :   AudioParamTimeline mFrequency;
     397             :   AudioParamTimeline mDetune;
     398             :   OscillatorType mType;
     399             :   float mPhase;
     400             :   float mFinalFrequency;
     401             :   float mPhaseIncrement;
     402             :   bool mRecomputeParameters;
     403             :   RefPtr<ThreadSharedFloatArrayBufferList> mCustom;
     404             :   RefPtr<BasicWaveFormCache> mBasicWaveFormCache;
     405             :   uint32_t mCustomLength;
     406             :   bool mCustomDisableNormalization;
     407             :   RefPtr<WebCore::PeriodicWave> mPeriodicWave;
     408             : };
     409             : 
     410           0 : OscillatorNode::OscillatorNode(AudioContext* aContext)
     411             :   : AudioScheduledSourceNode(aContext,
     412             :                              2,
     413             :                              ChannelCountMode::Max,
     414             :                              ChannelInterpretation::Speakers)
     415             :   , mType(OscillatorType::Sine)
     416             :   , mFrequency(
     417             :     new AudioParam(this, OscillatorNodeEngine::FREQUENCY, "frequency", 440.0f,
     418           0 :                    -(aContext->SampleRate() / 2), aContext->SampleRate() / 2))
     419           0 :   , mDetune(new AudioParam(this, OscillatorNodeEngine::DETUNE, "detune", 0.0f))
     420           0 :   , mStartCalled(false)
     421             : {
     422             : 
     423           0 :   OscillatorNodeEngine* engine = new OscillatorNodeEngine(this, aContext->Destination());
     424           0 :   mStream = AudioNodeStream::Create(aContext, engine,
     425             :                                     AudioNodeStream::NEED_MAIN_THREAD_FINISHED,
     426           0 :                                     aContext->Graph());
     427           0 :   engine->SetSourceStream(mStream);
     428           0 :   mStream->AddMainThreadListener(this);
     429           0 : }
     430             : 
     431             : /* static */ already_AddRefed<OscillatorNode>
     432           0 : OscillatorNode::Create(AudioContext& aAudioContext,
     433             :                        const OscillatorOptions& aOptions,
     434             :                        ErrorResult& aRv)
     435             : {
     436           0 :   if (aAudioContext.CheckClosed(aRv)) {
     437           0 :     return nullptr;
     438             :   }
     439             : 
     440           0 :   RefPtr<OscillatorNode> audioNode = new OscillatorNode(&aAudioContext);
     441             : 
     442           0 :   audioNode->Initialize(aOptions, aRv);
     443           0 :   if (NS_WARN_IF(aRv.Failed())) {
     444           0 :     return nullptr;
     445             :   }
     446             : 
     447           0 :   audioNode->SetType(aOptions.mType, aRv);
     448           0 :   if (NS_WARN_IF(aRv.Failed())) {
     449           0 :     return nullptr;
     450             :   }
     451             : 
     452           0 :   audioNode->Frequency()->SetValue(aOptions.mFrequency);
     453           0 :   audioNode->Detune()->SetValue(aOptions.mDetune);
     454             : 
     455           0 :   if (aOptions.mPeriodicWave.WasPassed()) {
     456           0 :     audioNode->SetPeriodicWave(aOptions.mPeriodicWave.Value());
     457             :   }
     458             : 
     459           0 :   return audioNode.forget();
     460             : }
     461             : 
     462             : size_t
     463           0 : OscillatorNode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
     464             : {
     465           0 :   size_t amount = AudioNode::SizeOfExcludingThis(aMallocSizeOf);
     466             : 
     467             :   // For now only report if we know for sure that it's not shared.
     468           0 :   if (mPeriodicWave) {
     469           0 :     amount += mPeriodicWave->SizeOfIncludingThisIfNotShared(aMallocSizeOf);
     470             :   }
     471           0 :   amount += mFrequency->SizeOfIncludingThis(aMallocSizeOf);
     472           0 :   amount += mDetune->SizeOfIncludingThis(aMallocSizeOf);
     473           0 :   return amount;
     474             : }
     475             : 
     476             : size_t
     477           0 : OscillatorNode::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
     478             : {
     479           0 :   return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
     480             : }
     481             : 
     482             : JSObject*
     483           0 : OscillatorNode::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
     484             : {
     485           0 :   return OscillatorNodeBinding::Wrap(aCx, this, aGivenProto);
     486             : }
     487             : 
     488             : void
     489           0 : OscillatorNode::DestroyMediaStream()
     490             : {
     491           0 :   if (mStream) {
     492           0 :     mStream->RemoveMainThreadListener(this);
     493             :   }
     494           0 :   AudioNode::DestroyMediaStream();
     495           0 : }
     496             : 
     497             : void
     498           0 : OscillatorNode::SendTypeToStream()
     499             : {
     500           0 :   if (!mStream) {
     501           0 :     return;
     502             :   }
     503           0 :   if (mType == OscillatorType::Custom) {
     504             :     // The engine assumes we'll send the custom data before updating the type.
     505           0 :     SendPeriodicWaveToStream();
     506             :   }
     507           0 :   SendInt32ParameterToStream(OscillatorNodeEngine::TYPE, static_cast<int32_t>(mType));
     508             : }
     509             : 
     510           0 : void OscillatorNode::SendPeriodicWaveToStream()
     511             : {
     512           0 :   NS_ASSERTION(mType == OscillatorType::Custom,
     513             :                "Sending custom waveform to engine thread with non-custom type");
     514           0 :   MOZ_ASSERT(mStream, "Missing node stream.");
     515           0 :   MOZ_ASSERT(mPeriodicWave, "Send called without PeriodicWave object.");
     516           0 :   SendInt32ParameterToStream(OscillatorNodeEngine::PERIODICWAVE_LENGTH,
     517           0 :                              mPeriodicWave->DataLength());
     518           0 :   SendInt32ParameterToStream(OscillatorNodeEngine::DISABLE_NORMALIZATION,
     519           0 :                              mPeriodicWave->DisableNormalization());
     520             :   RefPtr<ThreadSharedFloatArrayBufferList> data =
     521           0 :     mPeriodicWave->GetThreadSharedBuffer();
     522           0 :   mStream->SetBuffer(data.forget());
     523           0 : }
     524             : 
     525             : void
     526           0 : OscillatorNode::Start(double aWhen, ErrorResult& aRv)
     527             : {
     528           0 :   if (!WebAudioUtils::IsTimeValid(aWhen)) {
     529           0 :     aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
     530           0 :     return;
     531             :   }
     532             : 
     533           0 :   if (mStartCalled) {
     534           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     535           0 :     return;
     536             :   }
     537           0 :   mStartCalled = true;
     538             : 
     539           0 :   if (!mStream) {
     540             :     // Nothing to play, or we're already dead for some reason
     541           0 :     return;
     542             :   }
     543             : 
     544             :   // TODO: Perhaps we need to do more here.
     545           0 :   mStream->SetStreamTimeParameter(OscillatorNodeEngine::START,
     546           0 :                                   Context(), aWhen);
     547             : 
     548           0 :   MarkActive();
     549             : }
     550             : 
     551             : void
     552           0 : OscillatorNode::Stop(double aWhen, ErrorResult& aRv)
     553             : {
     554           0 :   if (!WebAudioUtils::IsTimeValid(aWhen)) {
     555           0 :     aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
     556           0 :     return;
     557             :   }
     558             : 
     559           0 :   if (!mStartCalled) {
     560           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     561           0 :     return;
     562             :   }
     563             : 
     564           0 :   if (!mStream || !Context()) {
     565             :     // We've already stopped and had our stream shut down
     566           0 :     return;
     567             :   }
     568             : 
     569             :   // TODO: Perhaps we need to do more here.
     570           0 :   mStream->SetStreamTimeParameter(OscillatorNodeEngine::STOP,
     571           0 :                                   Context(), std::max(0.0, aWhen));
     572             : }
     573             : 
     574             : void
     575           0 : OscillatorNode::NotifyMainThreadStreamFinished()
     576             : {
     577           0 :   MOZ_ASSERT(mStream->IsFinished());
     578             : 
     579           0 :   class EndedEventDispatcher final : public Runnable
     580             :   {
     581             :   public:
     582           0 :     explicit EndedEventDispatcher(OscillatorNode* aNode)
     583           0 :       : mozilla::Runnable("EndedEventDispatcher")
     584           0 :       , mNode(aNode)
     585             :     {
     586           0 :     }
     587           0 :     NS_IMETHOD Run() override
     588             :     {
     589             :       // If it's not safe to run scripts right now, schedule this to run later
     590           0 :       if (!nsContentUtils::IsSafeToRunScript()) {
     591           0 :         nsContentUtils::AddScriptRunner(this);
     592           0 :         return NS_OK;
     593             :       }
     594             : 
     595           0 :       mNode->DispatchTrustedEvent(NS_LITERAL_STRING("ended"));
     596             :       // Release stream resources.
     597           0 :       mNode->DestroyMediaStream();
     598           0 :       return NS_OK;
     599             :     }
     600             :   private:
     601             :     RefPtr<OscillatorNode> mNode;
     602             :   };
     603             : 
     604           0 :   Context()->Dispatch(do_AddRef(new EndedEventDispatcher(this)));
     605             : 
     606             :   // Drop the playing reference
     607             :   // Warning: The below line might delete this.
     608           0 :   MarkInactive();
     609           0 : }
     610             : 
     611             : } // namespace dom
     612             : } // namespace mozilla

Generated by: LCOV version 1.13