tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ConstantSourceNode.cpp (8344B)


      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 "ConstantSourceNode.h"
      8 
      9 #include "AudioDestinationNode.h"
     10 #include "AudioNodeEngine.h"
     11 #include "AudioNodeTrack.h"
     12 #include "Tracing.h"
     13 #include "nsContentUtils.h"
     14 
     15 namespace mozilla::dom {
     16 
     17 NS_IMPL_CYCLE_COLLECTION_INHERITED(ConstantSourceNode, AudioScheduledSourceNode,
     18                                   mOffset)
     19 
     20 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ConstantSourceNode)
     21 NS_INTERFACE_MAP_END_INHERITING(AudioScheduledSourceNode)
     22 
     23 NS_IMPL_ADDREF_INHERITED(ConstantSourceNode, AudioScheduledSourceNode)
     24 NS_IMPL_RELEASE_INHERITED(ConstantSourceNode, AudioScheduledSourceNode)
     25 
     26 class ConstantSourceNodeEngine final : public AudioNodeEngine {
     27 public:
     28  ConstantSourceNodeEngine(AudioNode* aNode, AudioDestinationNode* aDestination)
     29      : AudioNodeEngine(aNode),
     30        mSource(nullptr),
     31        mDestination(aDestination->Track()),
     32        mStart(-1),
     33        mStop(TRACK_TIME_MAX)
     34        // Keep the default values in sync with
     35        // ConstantSourceNode::ConstantSourceNode.
     36        ,
     37        mOffset(1.0f) {
     38    MOZ_ASSERT(NS_IsMainThread());
     39  }
     40 
     41  void SetSourceTrack(AudioNodeTrack* aSource) { mSource = aSource; }
     42 
     43  enum Parameters {
     44    OFFSET,
     45    START,
     46    STOP,
     47  };
     48  void RecvTimelineEvent(uint32_t aIndex, AudioParamEvent& aEvent) override {
     49    MOZ_ASSERT(mDestination);
     50 
     51    aEvent.ConvertToTicks(mDestination);
     52 
     53    switch (aIndex) {
     54      case OFFSET:
     55        mOffset.InsertEvent<int64_t>(aEvent);
     56        break;
     57      default:
     58        NS_ERROR("Bad ConstantSourceNodeEngine TimelineParameter");
     59    }
     60  }
     61 
     62  void SetTrackTimeParameter(uint32_t aIndex, TrackTime aParam) override {
     63    switch (aIndex) {
     64      case START:
     65        mStart = aParam;
     66        mSource->SetActive();
     67        break;
     68      case STOP:
     69        mStop = aParam;
     70        break;
     71      default:
     72        NS_ERROR("Bad ConstantSourceNodeEngine TrackTimeParameter");
     73    }
     74  }
     75 
     76  void ProcessBlock(AudioNodeTrack* aTrack, GraphTime aFrom,
     77                    const AudioBlock& aInput, AudioBlock* aOutput,
     78                    bool* aFinished) override {
     79    MOZ_ASSERT(mSource == aTrack, "Invalid source track");
     80    TRACE("ConstantSourceNodeEngine::ProcessBlock");
     81 
     82    TrackTime ticks = mDestination->GraphTimeToTrackTime(aFrom);
     83    if (mStart == -1) {
     84      aOutput->SetNull(WEBAUDIO_BLOCK_SIZE);
     85      return;
     86    }
     87 
     88    if (ticks + WEBAUDIO_BLOCK_SIZE <= mStart || ticks >= mStop ||
     89        mStop <= mStart) {
     90      aOutput->SetNull(WEBAUDIO_BLOCK_SIZE);
     91    } else {
     92      aOutput->AllocateChannels(1);
     93      float* output = aOutput->ChannelFloatsForWrite(0);
     94      uint32_t writeOffset = 0;
     95 
     96      if (ticks < mStart) {
     97        MOZ_ASSERT(mStart - ticks <= WEBAUDIO_BLOCK_SIZE);
     98        uint32_t count = mStart - ticks;
     99        std::fill_n(output, count, 0.0f);
    100        writeOffset += count;
    101      }
    102 
    103      MOZ_ASSERT(ticks + writeOffset >= mStart);
    104      MOZ_ASSERT(mStop - ticks >= writeOffset);
    105      uint32_t count =
    106          std::min<TrackTime>(WEBAUDIO_BLOCK_SIZE, mStop - ticks) - writeOffset;
    107 
    108      if (mOffset.HasSimpleValue()) {
    109        float value = mOffset.GetValue();
    110        std::fill_n(output + writeOffset, count, value);
    111      } else {
    112        mOffset.GetValuesAtTime(ticks + writeOffset, output + writeOffset,
    113                                count);
    114      }
    115 
    116      writeOffset += count;
    117 
    118      std::fill_n(output + writeOffset, WEBAUDIO_BLOCK_SIZE - writeOffset,
    119                  0.0f);
    120    }
    121 
    122    if (ticks + WEBAUDIO_BLOCK_SIZE >= mStop) {
    123      // We've finished playing.
    124      *aFinished = true;
    125    }
    126  }
    127 
    128  bool IsActive() const override {
    129    // start() has been called.
    130    return mStart != -1;
    131  }
    132 
    133  size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override {
    134    size_t amount = AudioNodeEngine::SizeOfExcludingThis(aMallocSizeOf);
    135 
    136    // Not owned:
    137    // - mSource
    138    // - mDestination
    139    // - mOffset (internal ref owned by node)
    140 
    141    return amount;
    142  }
    143 
    144  size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override {
    145    return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
    146  }
    147 
    148  // mSource deletes the engine in its destructor.
    149  AudioNodeTrack* MOZ_NON_OWNING_REF mSource;
    150  RefPtr<AudioNodeTrack> mDestination;
    151  TrackTime mStart;
    152  TrackTime mStop;
    153  AudioParamTimeline mOffset;
    154 };
    155 
    156 ConstantSourceNode::ConstantSourceNode(AudioContext* aContext)
    157    : AudioScheduledSourceNode(aContext, 2, ChannelCountMode::Max,
    158                               ChannelInterpretation::Speakers),
    159      mStartCalled(false) {
    160  mOffset =
    161      CreateAudioParam(ConstantSourceNodeEngine::OFFSET, u"offset"_ns, 1.0f);
    162  ConstantSourceNodeEngine* engine =
    163      new ConstantSourceNodeEngine(this, aContext->Destination());
    164  mTrack = AudioNodeTrack::Create(aContext, engine,
    165                                  AudioNodeTrack::NEED_MAIN_THREAD_ENDED,
    166                                  aContext->Graph());
    167  engine->SetSourceTrack(mTrack);
    168  mTrack->AddMainThreadListener(this);
    169 }
    170 
    171 ConstantSourceNode::~ConstantSourceNode() = default;
    172 
    173 size_t ConstantSourceNode::SizeOfExcludingThis(
    174    MallocSizeOf aMallocSizeOf) const {
    175  size_t amount = AudioNode::SizeOfExcludingThis(aMallocSizeOf);
    176 
    177  amount += mOffset->SizeOfIncludingThis(aMallocSizeOf);
    178  return amount;
    179 }
    180 
    181 size_t ConstantSourceNode::SizeOfIncludingThis(
    182    MallocSizeOf aMallocSizeOf) const {
    183  return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
    184 }
    185 
    186 JSObject* ConstantSourceNode::WrapObject(JSContext* aCx,
    187                                         JS::Handle<JSObject*> aGivenProto) {
    188  return ConstantSourceNode_Binding::Wrap(aCx, this, aGivenProto);
    189 }
    190 
    191 already_AddRefed<ConstantSourceNode> ConstantSourceNode::Constructor(
    192    const GlobalObject& aGlobal, AudioContext& aContext,
    193    const ConstantSourceOptions& aOptions) {
    194  RefPtr<ConstantSourceNode> object = new ConstantSourceNode(&aContext);
    195  object->mOffset->SetInitialValue(aOptions.mOffset);
    196  return object.forget();
    197 }
    198 
    199 void ConstantSourceNode::DestroyMediaTrack() {
    200  if (mTrack) {
    201    mTrack->RemoveMainThreadListener(this);
    202  }
    203  AudioNode::DestroyMediaTrack();
    204 }
    205 
    206 void ConstantSourceNode::Start(double aWhen, ErrorResult& aRv) {
    207  if (!WebAudioUtils::IsTimeValid(aWhen)) {
    208    aRv.ThrowRangeError<MSG_VALUE_OUT_OF_RANGE>("start time");
    209    return;
    210  }
    211 
    212  if (mStartCalled) {
    213    aRv.ThrowInvalidStateError("Can't call start() more than once");
    214    return;
    215  }
    216  mStartCalled = true;
    217 
    218  if (!mTrack) {
    219    return;
    220  }
    221 
    222  mTrack->SetTrackTimeParameter(ConstantSourceNodeEngine::START, Context(),
    223                                aWhen);
    224 
    225  MarkActive();
    226  Context()->StartBlockedAudioContextIfAllowed();
    227 }
    228 
    229 void ConstantSourceNode::Stop(double aWhen, ErrorResult& aRv) {
    230  if (!WebAudioUtils::IsTimeValid(aWhen)) {
    231    aRv.ThrowRangeError<MSG_VALUE_OUT_OF_RANGE>("stop time");
    232    return;
    233  }
    234 
    235  if (!mStartCalled) {
    236    aRv.ThrowInvalidStateError("Can't call stop() without calling start()");
    237    return;
    238  }
    239 
    240  if (!mTrack || !Context()) {
    241    return;
    242  }
    243 
    244  mTrack->SetTrackTimeParameter(ConstantSourceNodeEngine::STOP, Context(),
    245                                std::max(0.0, aWhen));
    246 }
    247 
    248 void ConstantSourceNode::NotifyMainThreadTrackEnded() {
    249  MOZ_ASSERT(mTrack->IsEnded());
    250 
    251  class EndedEventDispatcher final : public Runnable {
    252   public:
    253    explicit EndedEventDispatcher(ConstantSourceNode* aNode)
    254        : mozilla::Runnable("EndedEventDispatcher"), mNode(aNode) {}
    255    NS_IMETHOD Run() override {
    256      // If it's not safe to run scripts right now, schedule this to run later
    257      if (!nsContentUtils::IsSafeToRunScript()) {
    258        nsContentUtils::AddScriptRunner(this);
    259        return NS_OK;
    260      }
    261 
    262      mNode->DispatchTrustedEvent(u"ended"_ns);
    263      // Release track resources.
    264      mNode->DestroyMediaTrack();
    265      return NS_OK;
    266    }
    267 
    268   private:
    269    RefPtr<ConstantSourceNode> mNode;
    270  };
    271 
    272  Context()->Dispatch(do_AddRef(new EndedEventDispatcher(this)));
    273 
    274  // Drop the playing reference
    275  // Warning: The below line might delete this.
    276  MarkInactive();
    277 }
    278 
    279 }  // namespace mozilla::dom