tor-browser

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

MediaTrackGraph.h (52353B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 #ifndef MOZILLA_MEDIATRACKGRAPH_H_
      7 #define MOZILLA_MEDIATRACKGRAPH_H_
      8 
      9 #include <speex/speex_resampler.h>
     10 
     11 #include "AudioSampleFormat.h"
     12 #include "CubebUtils.h"
     13 #include "MainThreadUtils.h"
     14 #include "MediaSegment.h"
     15 #include "mozilla/LinkedList.h"
     16 #include "mozilla/Maybe.h"
     17 #include "mozilla/Mutex.h"
     18 #include "mozilla/StateWatching.h"
     19 #include "mozilla/TaskQueue.h"
     20 #include "nsAutoRef.h"
     21 #include "nsIRunnable.h"
     22 #include "nsTArray.h"
     23 
     24 class nsIRunnable;
     25 class nsIGlobalObject;
     26 class nsPIDOMWindowInner;
     27 
     28 namespace mozilla {
     29 class AsyncLogger;
     30 class AudioCaptureTrack;
     31 class CrossGraphTransmitter;
     32 class CrossGraphReceiver;
     33 class NativeInputTrack;
     34 };  // namespace mozilla
     35 
     36 extern mozilla::AsyncLogger gMTGTraceLogger;
     37 
     38 template <>
     39 class nsAutoRefTraits<SpeexResamplerState>
     40    : public nsPointerRefTraits<SpeexResamplerState> {
     41 public:
     42  static void Release(SpeexResamplerState* aState) {
     43    speex_resampler_destroy(aState);
     44  }
     45 };
     46 
     47 namespace mozilla {
     48 
     49 extern LazyLogModule gMediaTrackGraphLog;
     50 
     51 namespace dom {
     52 enum class AudioContextOperation : uint8_t;
     53 enum class AudioContextOperationFlags;
     54 enum class AudioContextState : uint8_t;
     55 }  // namespace dom
     56 
     57 /*
     58 * MediaTrackGraph is a framework for synchronized audio/video processing
     59 * and playback. It is designed to be used by other browser components such as
     60 * HTML media elements, media capture APIs, real-time media streaming APIs,
     61 * multitrack media APIs, and advanced audio APIs.
     62 *
     63 * The MediaTrackGraph uses a dedicated thread to process media --- the media
     64 * graph thread. This ensures that we can process media through the graph
     65 * without blocking on main-thread activity. The media graph is only modified
     66 * on the media graph thread, to ensure graph changes can be processed without
     67 * interfering with media processing. All interaction with the media graph
     68 * thread is done with message passing.
     69 *
     70 * APIs that modify the graph or its properties are described as "control APIs".
     71 * These APIs are asynchronous; they queue graph changes internally and
     72 * those changes are processed all-at-once by the MediaTrackGraph. The
     73 * MediaTrackGraph monitors the main thread event loop via
     74 * nsIAppShell::RunInStableState to ensure that graph changes from a single
     75 * event loop task are always processed all together. Control APIs should only
     76 * be used on the main thread, currently; we may be able to relax that later.
     77 *
     78 * To allow precise synchronization of times in the control API, the
     79 * MediaTrackGraph maintains a "media timeline". Control APIs that take or
     80 * return times use that timeline. Those times never advance during
     81 * an event loop task. This time is returned by
     82 * MediaTrackGraph::GetCurrentTime().
     83 *
     84 * Media decoding, audio processing and media playback use thread-safe APIs to
     85 * the media graph to ensure they can continue while the main thread is blocked.
     86 *
     87 * When the graph is changed, we may need to throw out buffered data and
     88 * reprocess it. This is triggered automatically by the MediaTrackGraph.
     89 */
     90 
     91 class AudioProcessingTrack;
     92 class AudioNodeEngine;
     93 class AudioNodeExternalInputTrack;
     94 class AudioNodeTrack;
     95 class DirectMediaTrackListener;
     96 class ForwardedInputTrack;
     97 class MediaInputPort;
     98 class MediaTrack;
     99 class MediaTrackGraph;
    100 class MediaTrackGraphImpl;
    101 class MediaTrackListener;
    102 class DeviceInputConsumerTrack;
    103 class DeviceInputTrack;
    104 class ProcessedMediaTrack;
    105 class SourceMediaTrack;
    106 
    107 class AudioDataListenerInterface {
    108 protected:
    109  // Protected destructor, to discourage deletion outside of Release():
    110  virtual ~AudioDataListenerInterface() = default;
    111 
    112 public:
    113  /**
    114   * Number of audio input channels.
    115   */
    116  virtual uint32_t RequestedInputChannelCount(
    117      MediaTrackGraph* aGraph) const = 0;
    118 
    119  /**
    120   * The input processing params this listener wants the platform to apply.
    121   */
    122  virtual cubeb_input_processing_params RequestedInputProcessingParams(
    123      MediaTrackGraph* aGraph) const = 0;
    124 
    125  /**
    126   * Whether the underlying audio device is used for voice input.
    127   */
    128  virtual bool IsVoiceInput(MediaTrackGraph* aGraph) const = 0;
    129 
    130  /**
    131   * Called when the underlying audio device has changed.
    132   */
    133  virtual void DeviceChanged(MediaTrackGraph* aGraph) = 0;
    134 
    135  /**
    136   * Called when the underlying audio device is being closed.
    137   */
    138  virtual void Disconnect(MediaTrackGraph* aGraph) = 0;
    139 
    140  /**
    141   * Called sync when attempting to set the input processing params on the
    142   * underlying input track. Note that when multiple listeners request distinct
    143   * parameters, aRequestedParams is the aggregated form of those parameters.
    144   */
    145  virtual void NotifySetRequestedInputProcessingParams(
    146      MediaTrackGraph* aGraph, int aGeneration,
    147      cubeb_input_processing_params aRequestedParams) = 0;
    148 
    149  /**
    150   * Called async after an attempt to set the input processing params on the
    151   * underlying input track.
    152   */
    153  virtual void NotifySetRequestedInputProcessingParamsResult(
    154      MediaTrackGraph* aGraph, int aGeneration,
    155      const Result<cubeb_input_processing_params, int>& aResult) = 0;
    156 };
    157 
    158 class AudioDataListener : public AudioDataListenerInterface {
    159 protected:
    160  // Protected destructor, to discourage deletion outside of Release():
    161  virtual ~AudioDataListener() = default;
    162 
    163 public:
    164  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AudioDataListener)
    165 };
    166 
    167 /**
    168 * This is a base class for main-thread listener callbacks.
    169 * This callback is invoked on the main thread when the main-thread-visible
    170 * state of a track has changed.
    171 *
    172 * These methods are called with the media graph monitor held, so
    173 * reentry into general media graph methods is not possible.
    174 * You should do something non-blocking and non-reentrant (e.g. dispatch an
    175 * event) and return. NS_DispatchToCurrentThread would be a good choice.
    176 * The listener is allowed to synchronously remove itself from the track, but
    177 * not add or remove any other listeners.
    178 */
    179 class MainThreadMediaTrackListener {
    180 public:
    181  virtual void NotifyMainThreadTrackEnded() = 0;
    182 };
    183 
    184 /**
    185 * Helper struct used to keep track of memory usage by AudioNodes.
    186 */
    187 struct AudioNodeSizes {
    188  AudioNodeSizes() : mTrack(0), mEngine(0), mNodeType() {}
    189  size_t mTrack;
    190  size_t mEngine;
    191  const char* mNodeType;
    192 };
    193 
    194 /**
    195 * Describes how a track should be disabled.
    196 *
    197 * ENABLED        Not disabled.
    198 * SILENCE_BLACK  Audio data is turned into silence, video frames are made
    199 *                black.
    200 * SILENCE_FREEZE Audio data is turned into silence, video freezes at
    201 *                last frame.
    202 */
    203 enum class DisabledTrackMode { ENABLED, SILENCE_BLACK, SILENCE_FREEZE };
    204 
    205 /**
    206 * A track of audio or video data. The media type must be known at construction
    207 * and cannot change. All tracks progress at the same rate --- "real time".
    208 * Tracks cannot seek. The only operation readers can perform on a track is to
    209 * read the next data.
    210 *
    211 * Consumers of a track can be reading from it at different offsets, but that
    212 * should only happen due to the order in which consumers are being run.
    213 * Those offsets must not diverge in the long term, otherwise we would require
    214 * unbounded buffering.
    215 *
    216 * (DEPRECATED to be removed in bug 1581074)
    217 * Tracks can be in a "blocked" state. While blocked, a track does not
    218 * produce data. A track can be explicitly blocked via the control API,
    219 * or implicitly blocked by whatever's generating it (e.g. an underrun in the
    220 * source resource), or implicitly blocked because something consuming it
    221 * blocks, or implicitly because it has ended.
    222 *
    223 * A track can be in an "ended" state. "Ended" tracks are permanently blocked.
    224 * The "ended" state is terminal.
    225 *
    226 * Transitions into and out of the "blocked" and "ended" states are managed
    227 * by the MediaTrackGraph on the media graph thread.
    228 *
    229 * We buffer media data ahead of the consumers' reading offsets. It is possible
    230 * to have buffered data but still be blocked.
    231 *
    232 * Any track can have its audio or video playing when requested. The media
    233 * track graph plays audio by constructing audio output tracks as necessary.
    234 * Video is played through a DirectMediaTrackListener managed by
    235 * VideoStreamTrack.
    236 *
    237 * The data in a track is managed by mSegment. The segment starts at GraphTime
    238 * mStartTime and encodes its own TrackTime duration.
    239 *
    240 * Tracks are explicitly managed. The client creates them via
    241 * MediaTrackGraph::Create{Source|ForwardedInput}Track, and releases them by
    242 * calling Destroy() when no longer needed (actual destruction will be
    243 * deferred). The actual object is owned by the MediaTrackGraph. The basic idea
    244 * is that main thread objects will keep Tracks alive as long as necessary
    245 * (using the cycle collector to clean up whenever needed).
    246 *
    247 * We make them refcounted only so that track-related messages with
    248 * MediaTrack* pointers can be sent to the main thread safely.
    249 *
    250 * The lifetimes of MediaTracks are controlled from the main thread.
    251 * For MediaTracks exposed to the DOM, the lifetime is controlled by the DOM
    252 * wrapper; the DOM wrappers own their associated MediaTracks. When a DOM
    253 * wrapper is destroyed, it sends a Destroy message for the associated
    254 * MediaTrack and clears its reference (the last main-thread reference to
    255 * the object). When the Destroy message is processed on the graph thread we
    256 * immediately release the affected objects (disentangling them from other
    257 * objects as necessary).
    258 *
    259 * This could cause problems for media processing if a MediaTrack is destroyed
    260 * while a downstream MediaTrack is still using it. Therefore the DOM wrappers
    261 * must keep upstream MediaTracks alive as long as they could be used in the
    262 * media graph.
    263 *
    264 * At any time, however, a set of MediaTrack wrappers could be collected via
    265 * cycle collection. Destroy messages will be sent for those objects in
    266 * arbitrary order and the MediaTrackGraph has to be able to handle this.
    267 */
    268 class MediaTrack : public mozilla::LinkedListElement<MediaTrack> {
    269 public:
    270  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaTrack)
    271 
    272  MediaTrack(TrackRate aSampleRate, MediaSegment::Type aType,
    273             MediaSegment* aSegment);
    274 
    275  // The sample rate of the graph.
    276  const TrackRate mSampleRate;
    277  const MediaSegment::Type mType;
    278 
    279 protected:
    280  // Protected destructor, to discourage deletion outside of Release():
    281  virtual ~MediaTrack();
    282 
    283 public:
    284  /**
    285   * Returns the graph that owns this track.
    286   */
    287  MediaTrackGraphImpl* GraphImpl();
    288  const MediaTrackGraphImpl* GraphImpl() const;
    289  MediaTrackGraph* Graph() { return mGraph; }
    290  const MediaTrackGraph* Graph() const { return mGraph; }
    291  /**
    292   * Sets the graph that owns this track.  Should only be called once.
    293   */
    294  void SetGraphImpl(MediaTrackGraphImpl* aGraph);
    295  void SetGraphImpl(MediaTrackGraph* aGraph);
    296 
    297  // Control API.
    298  void AddAudioOutput(void* aKey, const AudioDeviceInfo* aSink);
    299  void AddAudioOutput(void* aKey, CubebUtils::AudioDeviceID aDeviceID,
    300                      TrackRate aPreferredSampleRate);
    301  void SetAudioOutputVolume(void* aKey, float aVolume);
    302  void RemoveAudioOutput(void* aKey);
    303  // Explicitly suspend. Useful for example if a media element is pausing
    304  // and we need to stop its track emitting its buffered data. As soon as the
    305  // Suspend message reaches the graph, the track stops processing. It
    306  // ignores its inputs and produces silence/no video until Resumed. Its
    307  // current time does not advance.
    308  void Suspend();
    309  void Resume();
    310  // Events will be dispatched by calling methods of aListener.
    311  virtual void AddListener(MediaTrackListener* aListener);
    312  virtual RefPtr<GenericPromise> RemoveListener(MediaTrackListener* aListener);
    313 
    314  /**
    315   * Adds aListener to the source track of this track.
    316   * When the MediaTrackGraph processes the added listener, it will traverse
    317   * the graph and add it to the track's source track.
    318   * Note that the listener will be notified on the MediaTrackGraph thread
    319   * with whether the installation of it at the source was successful or not.
    320   */
    321  void AddDirectListener(DirectMediaTrackListener* aListener);
    322 
    323  /**
    324   * Removes aListener from the source track of this track.
    325   * Note that the listener has already been removed if the link between the
    326   * source and this track has been broken. The caller doesn't have to care
    327   * about this, removing when the source cannot be found, or when the listener
    328   * had already been removed does nothing.
    329   */
    330  void RemoveDirectListener(DirectMediaTrackListener* aListener);
    331 
    332  // A disabled track has video replaced by black, and audio replaced by
    333  // silence.
    334  void SetDisabledTrackMode(DisabledTrackMode aMode);
    335 
    336  // End event will be notified by calling methods of aListener. It is the
    337  // responsibility of the caller to remove aListener before it is destroyed.
    338  void AddMainThreadListener(MainThreadMediaTrackListener* aListener);
    339  // It's safe to call this even if aListener is not currently a listener;
    340  // the call will be ignored.
    341  void RemoveMainThreadListener(MainThreadMediaTrackListener* aListener) {
    342    MOZ_ASSERT(NS_IsMainThread());
    343    MOZ_ASSERT(aListener);
    344    mMainThreadListeners.RemoveElement(aListener);
    345  }
    346 
    347  /**
    348   * Append to the message queue a control message to execute a given lambda
    349   * function with no parameters.  The queue is drained during
    350   * RunInStableState().  The lambda will be executed on the graph thread.
    351   * The lambda will not be executed if the graph has been forced to shut
    352   * down.
    353   **/
    354  template <typename Function>
    355  void QueueControlMessageWithNoShutdown(Function&& aFunction) {
    356    QueueMessage(WrapUnique(
    357        new ControlMessageWithNoShutdown(std::forward<Function>(aFunction))));
    358  }
    359 
    360  enum class IsInShutdown { No, Yes };
    361  /**
    362   * Append to the message queue a control message to execute a given lambda
    363   * function with a single IsInShutdown parameter.  A No argument indicates
    364   * execution on the thread of a graph that is still running.  A Yes argument
    365   * indicates execution on the main thread when the graph has been forced to
    366   * shut down.
    367   **/
    368  template <typename Function>
    369  void QueueControlOrShutdownMessage(Function&& aFunction) {
    370    QueueMessage(WrapUnique(
    371        new ControlOrShutdownMessage(std::forward<Function>(aFunction))));
    372  }
    373 
    374  /**
    375   * Ensure a runnable will run on the main thread after running all pending
    376   * updates that were sent from the graph thread or will be sent before the
    377   * graph thread receives the next graph update.
    378   *
    379   * If the graph has been shut down or destroyed, then the runnable will be
    380   * dispatched to the event queue immediately.  (There are no pending updates
    381   * in this situation.)
    382   *
    383   * Main thread only.
    384   */
    385  void RunAfterPendingUpdates(already_AddRefed<nsIRunnable> aRunnable);
    386 
    387  // Signal that the client is done with this MediaTrack. It will be deleted
    388  // later.
    389  virtual void Destroy();
    390 
    391  // Returns the main-thread's view of how much data has been processed by
    392  // this track.
    393  TrackTime GetCurrentTime() const {
    394    NS_ASSERTION(NS_IsMainThread(), "Call only on main thread");
    395    return mMainThreadCurrentTime;
    396  }
    397  // Return the main thread's view of whether this track has ended.
    398  bool IsEnded() const {
    399    NS_ASSERTION(NS_IsMainThread(), "Call only on main thread");
    400    return mMainThreadEnded;
    401  }
    402 
    403  bool IsDestroyed() const {
    404    NS_ASSERTION(NS_IsMainThread(), "Call only on main thread");
    405    return mMainThreadDestroyed;
    406  }
    407 
    408  uint64_t GetWindowId() const;
    409 
    410  friend class MediaTrackGraphImpl;
    411  friend class MediaInputPort;
    412  friend class AudioNodeExternalInputTrack;
    413 
    414  virtual AudioProcessingTrack* AsAudioProcessingTrack() { return nullptr; }
    415  virtual SourceMediaTrack* AsSourceTrack() { return nullptr; }
    416  virtual ProcessedMediaTrack* AsProcessedTrack() { return nullptr; }
    417  virtual AudioNodeTrack* AsAudioNodeTrack() { return nullptr; }
    418  virtual ForwardedInputTrack* AsForwardedInputTrack() { return nullptr; }
    419  virtual CrossGraphTransmitter* AsCrossGraphTransmitter() { return nullptr; }
    420  virtual CrossGraphReceiver* AsCrossGraphReceiver() { return nullptr; }
    421  virtual DeviceInputTrack* AsDeviceInputTrack() { return nullptr; }
    422  virtual DeviceInputConsumerTrack* AsDeviceInputConsumerTrack() {
    423    return nullptr;
    424  }
    425 
    426  // These Impl methods perform the core functionality of the control methods
    427  // above, on the media graph thread.
    428  /**
    429   * Stop all track activity and disconnect it from all inputs and outputs.
    430   * This must be idempotent.
    431   */
    432  virtual void DestroyImpl();
    433  TrackTime GetEnd() const;
    434 
    435  /**
    436   * Removes all direct listeners and signals to them that they have been
    437   * uninstalled.
    438   */
    439  virtual void RemoveAllDirectListenersImpl() {}
    440  void RemoveAllResourcesAndListenersImpl();
    441 
    442  virtual void AddListenerImpl(already_AddRefed<MediaTrackListener> aListener);
    443  virtual void RemoveListenerImpl(MediaTrackListener* aListener);
    444  virtual void AddDirectListenerImpl(
    445      already_AddRefed<DirectMediaTrackListener> aListener);
    446  virtual void RemoveDirectListenerImpl(DirectMediaTrackListener* aListener);
    447  virtual void SetDisabledTrackModeImpl(DisabledTrackMode aMode);
    448 
    449  void AddConsumer(MediaInputPort* aPort) { mConsumers.AppendElement(aPort); }
    450  void RemoveConsumer(MediaInputPort* aPort) {
    451    mConsumers.RemoveElement(aPort);
    452  }
    453  GraphTime StartTime() const { return mStartTime; }
    454  bool Ended() const { return mEnded; }
    455 
    456  // Returns the current number of channels this track contains if it's an audio
    457  // track. Calling this on a video track will trip assertions. Graph thread
    458  // only.
    459  virtual uint32_t NumberOfChannels() const = 0;
    460 
    461  // The DisabledTrackMode after combining the explicit mode and that of the
    462  // input, if any.
    463  virtual DisabledTrackMode CombinedDisabledMode() const {
    464    return mDisabledMode;
    465  }
    466 
    467  template <class SegmentType>
    468  SegmentType* GetData() const {
    469    if (!mSegment) {
    470      return nullptr;
    471    }
    472    if (mSegment->GetType() != SegmentType::StaticType()) {
    473      return nullptr;
    474    }
    475    return static_cast<SegmentType*>(mSegment.get());
    476  }
    477  MediaSegment* GetData() const { return mSegment.get(); }
    478 
    479  double TrackTimeToSeconds(TrackTime aTime) const {
    480    NS_ASSERTION(0 <= aTime && aTime <= TRACK_TIME_MAX, "Bad time");
    481    return static_cast<double>(aTime) / mSampleRate;
    482  }
    483  int64_t TrackTimeToMicroseconds(TrackTime aTime) const {
    484    NS_ASSERTION(0 <= aTime && aTime <= TRACK_TIME_MAX, "Bad time");
    485    return (aTime * 1000000) / mSampleRate;
    486  }
    487  TrackTime SecondsToNearestTrackTime(double aSeconds) const {
    488    NS_ASSERTION(0 <= aSeconds && aSeconds <= TRACK_TICKS_MAX / TRACK_RATE_MAX,
    489                 "Bad seconds");
    490    return mSampleRate * aSeconds + 0.5;
    491  }
    492  TrackTime MicrosecondsToTrackTimeRoundDown(int64_t aMicroseconds) const {
    493    return (aMicroseconds * mSampleRate) / 1000000;
    494  }
    495 
    496  TrackTicks TimeToTicksRoundUp(TrackRate aRate, TrackTime aTime) const {
    497    return RateConvertTicksRoundUp(aRate, mSampleRate, aTime);
    498  }
    499  TrackTime TicksToTimeRoundDown(TrackRate aRate, TrackTicks aTicks) const {
    500    return RateConvertTicksRoundDown(mSampleRate, aRate, aTicks);
    501  }
    502  /**
    503   * Convert graph time to track time. aTime must be <= mStateComputedTime
    504   * to ensure we know exactly how much time this track will be blocked during
    505   * the interval.
    506   */
    507  TrackTime GraphTimeToTrackTimeWithBlocking(GraphTime aTime) const;
    508  /**
    509   * Convert graph time to track time. This assumes there is no blocking time
    510   * to take account of, which is always true except between a track
    511   * having its blocking time calculated in UpdateGraph and its blocking time
    512   * taken account of in UpdateCurrentTimeForTracks.
    513   */
    514  TrackTime GraphTimeToTrackTime(GraphTime aTime) const;
    515  /**
    516   * Convert track time to graph time. This assumes there is no blocking time
    517   * to take account of, which is always true except between a track
    518   * having its blocking time calculated in UpdateGraph and its blocking time
    519   * taken account of in UpdateCurrentTimeForTracks.
    520   */
    521  GraphTime TrackTimeToGraphTime(TrackTime aTime) const;
    522 
    523  virtual void ApplyTrackDisabling(MediaSegment* aSegment,
    524                                   MediaSegment* aRawSegment = nullptr);
    525 
    526  // Return true if the main thread needs to observe updates from this track.
    527  virtual bool MainThreadNeedsUpdates() const { return true; }
    528 
    529  virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const;
    530  virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
    531 
    532  bool IsSuspended() const { return mSuspendedCount > 0; }
    533  /**
    534   * Increment suspend count and move it to GraphImpl()->mSuspendedTracks if
    535   * necessary.  Graph thread.
    536   */
    537  void IncrementSuspendCount();
    538  /**
    539   * Increment suspend count on aTrack and move it to GraphImpl()->mTracks if
    540   * necessary.  GraphThread.
    541   */
    542  virtual void DecrementSuspendCount();
    543 
    544  void AssertOnGraphThread() const;
    545  void AssertOnGraphThreadOrNotRunning() const;
    546 
    547  /**
    548   * For use during ProcessedMediaTrack::ProcessInput() or
    549   * MediaTrackListener callbacks, when graph state cannot be changed.
    550   * Queues a control message to execute a given lambda function with no
    551   * parameters after processing, at a time when graph state can be changed.
    552   * The lambda will always be executed before handing control of the graph
    553   * to the main thread for shutdown.
    554   * Graph thread.
    555   */
    556  template <typename Function>
    557  void RunAfterProcessing(Function&& aFunction) {
    558    RunMessageAfterProcessing(WrapUnique(
    559        new ControlMessageWithNoShutdown(std::forward<Function>(aFunction))));
    560  }
    561 
    562  class ControlMessageInterface;
    563 
    564 protected:
    565  // Called on graph thread either during destroy handling or before handing
    566  // graph control to the main thread to release tracks.
    567  virtual void OnGraphThreadDone() {}
    568 
    569  // |AdvanceTimeVaryingValuesToCurrentTime| will be override in
    570  // SourceMediaTrack.
    571  virtual void AdvanceTimeVaryingValuesToCurrentTime(GraphTime aCurrentTime,
    572                                                     GraphTime aBlockedTime);
    573 
    574 private:
    575  template <typename Function>
    576  class ControlMessageWithNoShutdown;
    577  template <typename Function>
    578  class ControlOrShutdownMessage;
    579 
    580  void QueueMessage(UniquePtr<ControlMessageInterface> aMessage);
    581  void RunMessageAfterProcessing(UniquePtr<ControlMessageInterface> aMessage);
    582 
    583  void NotifyMainThreadListeners() {
    584    NS_ASSERTION(NS_IsMainThread(), "Call only on main thread");
    585 
    586    for (int32_t i = mMainThreadListeners.Length() - 1; i >= 0; --i) {
    587      mMainThreadListeners[i]->NotifyMainThreadTrackEnded();
    588    }
    589    mMainThreadListeners.Clear();
    590  }
    591 
    592  bool ShouldNotifyTrackEnded() {
    593    NS_ASSERTION(NS_IsMainThread(), "Call only on main thread");
    594    if (!mMainThreadEnded || mEndedNotificationSent) {
    595      return false;
    596    }
    597 
    598    mEndedNotificationSent = true;
    599    return true;
    600  }
    601 
    602 protected:
    603  // Notifies listeners and consumers of the change in disabled mode when the
    604  // current combined mode is different from aMode.
    605  void NotifyIfDisabledModeChangedFrom(DisabledTrackMode aOldMode);
    606 
    607  // This state is all initialized on the main thread but
    608  // otherwise modified only on the media graph thread.
    609 
    610  // Buffered data. The start of the buffer corresponds to mStartTime.
    611  // Conceptually the buffer contains everything this track has ever played,
    612  // but we forget some prefix of the buffered data to bound the space usage.
    613  // Note that this may be null for tracks that never contain data, like
    614  // non-external AudioNodeTracks.
    615  const UniquePtr<MediaSegment> mSegment;
    616 
    617  // The time when the buffered data could be considered to have started
    618  // playing. This increases over time to account for time the track was
    619  // blocked before mCurrentTime.
    620  GraphTime mStartTime;
    621 
    622  // The time until which we last called mSegment->ForgetUpTo().
    623  TrackTime mForgottenTime;
    624 
    625  // True once we've processed mSegment until the end and no more data will be
    626  // added. Note that mSegment might still contain data for the current
    627  // iteration.
    628  bool mEnded;
    629 
    630  // True after track listeners have been notified that this track has ended.
    631  bool mNotifiedEnded;
    632 
    633  // Client-set volume of this track
    634  nsTArray<RefPtr<MediaTrackListener>> mTrackListeners;
    635  nsTArray<MainThreadMediaTrackListener*> mMainThreadListeners;
    636  // This track's associated disabled mode. It can either by disabled by frames
    637  // being replaced by black, or by retaining the previous frame.
    638  DisabledTrackMode mDisabledMode;
    639 
    640  // GraphTime at which this track starts blocking.
    641  // This is only valid up to mStateComputedTime. The track is considered to
    642  // have not been blocked before mCurrentTime (its mStartTime is
    643  // increased as necessary to account for that time instead).
    644  GraphTime mStartBlocking;
    645 
    646  // MediaInputPorts to which this is connected
    647  nsTArray<MediaInputPort*> mConsumers;
    648 
    649  /**
    650   * Number of outstanding suspend operations on this track. Track is
    651   * suspended when this is > 0.
    652   */
    653  int32_t mSuspendedCount;
    654 
    655  // Main-thread views of state
    656  TrackTime mMainThreadCurrentTime;
    657  bool mMainThreadEnded;
    658  bool mEndedNotificationSent;
    659  bool mMainThreadDestroyed;
    660 
    661  // Our media track graph.  null if destroyed on the graph thread.
    662  MediaTrackGraph* mGraph;
    663 };
    664 
    665 /**
    666 * This is a track into which a decoder can write audio or video.
    667 *
    668 * Audio or video can be written on any thread, but you probably want to
    669 * always write from the same thread to avoid unexpected interleavings.
    670 *
    671 * For audio the sample rate of the written data can differ from the sample rate
    672 * of the graph itself. Use SetAppendDataSourceRate to inform the track what
    673 * rate written audio data will be sampled in.
    674 */
    675 class SourceMediaTrack : public MediaTrack {
    676 public:
    677  SourceMediaTrack(MediaSegment::Type aType, TrackRate aSampleRate);
    678 
    679  SourceMediaTrack* AsSourceTrack() override { return this; }
    680 
    681  // Main thread only
    682 
    683  /**
    684   * Enable or disable pulling.
    685   * When pulling is enabled, NotifyPull gets called on the
    686   * MediaTrackListeners for this track during the MediaTrackGraph
    687   * control loop. Pulling is initially disabled. Due to unavoidable race
    688   * conditions, after a call to SetPullingEnabled(false) it is still possible
    689   * for a NotifyPull to occur.
    690   */
    691  void SetPullingEnabled(bool aEnabled);
    692 
    693  // MediaTrackGraph thread only
    694  void DestroyImpl() override;
    695 
    696  // Call these on any thread.
    697  /**
    698   * Call all MediaTrackListeners to request new data via the NotifyPull
    699   * API (if enabled).
    700   * aDesiredUpToTime (in): end time of new data requested.
    701   *
    702   * Returns true if new data is about to be added.
    703   */
    704  bool PullNewData(GraphTime aDesiredUpToTime);
    705 
    706  /**
    707   * Extract any state updates pending in the track, and apply them.
    708   */
    709  void ExtractPendingInput(GraphTime aCurrentTime, GraphTime aDesiredUpToTime);
    710 
    711  /**
    712   * All data appended with AppendData() from this point on will be resampled
    713   * from aRate to the graph rate.
    714   *
    715   * Resampling for video does not make sense and is forbidden.
    716   */
    717  void SetAppendDataSourceRate(TrackRate aRate);
    718 
    719  /**
    720   * Append media data to this track. Ownership of aSegment remains with the
    721   * caller, but aSegment is emptied. Returns 0 if the data was not appended
    722   * because the stream has ended. Returns the duration of the appended data in
    723   * the graph's track rate otherwise.
    724   */
    725  TrackTime AppendData(MediaSegment* aSegment,
    726                       MediaSegment* aRawSegment = nullptr);
    727 
    728  /**
    729   * Clear any data appended with AppendData() that hasn't entered the graph
    730   * yet. Returns the duration of the cleared data in the graph's track rate.
    731   */
    732  TrackTime ClearFutureData();
    733 
    734  /**
    735   * Indicate that this track has ended. Do not do any more API calls affecting
    736   * this track.
    737   */
    738  void End();
    739 
    740  void SetDisabledTrackModeImpl(DisabledTrackMode aMode) override;
    741 
    742  uint32_t NumberOfChannels() const override;
    743 
    744  void RemoveAllDirectListenersImpl() override;
    745 
    746  // The value set here is applied in MoveToSegment so we can avoid the
    747  // buffering delay in applying the change. See Bug 1443511.
    748  void SetVolume(float aVolume);
    749  float GetVolumeLocked() MOZ_REQUIRES(mMutex);
    750 
    751  Mutex& GetMutex() MOZ_RETURN_CAPABILITY(mMutex) { return mMutex; }
    752 
    753  friend class MediaTrackGraphImpl;
    754 
    755 protected:
    756  enum TrackCommands : uint32_t;
    757 
    758  virtual ~SourceMediaTrack();
    759 
    760  /**
    761   * Data to cater for appending media data to this track.
    762   */
    763  struct TrackData {
    764    // Sample rate of the input data.
    765    TrackRate mInputRate;
    766    // Resampler if the rate of the input track does not match the
    767    // MediaTrackGraph's.
    768    nsAutoRef<SpeexResamplerState> mResampler;
    769    uint32_t mResamplerChannelCount;
    770    // Each time the track updates are flushed to the media graph thread,
    771    // the segment buffer is emptied.
    772    UniquePtr<MediaSegment> mData;
    773    // True once the producer has signaled that no more data is coming.
    774    bool mEnded;
    775    // True if the producer of this track is having data pulled by the graph.
    776    bool mPullingEnabled;
    777    // True if the graph has notified this track that it will not be used
    778    // again on the graph thread.
    779    bool mGraphThreadDone;
    780  };
    781 
    782  bool NeedsMixing();
    783 
    784  void ResampleAudioToGraphSampleRate(MediaSegment* aSegment)
    785      MOZ_REQUIRES(mMutex);
    786 
    787  void AddDirectListenerImpl(
    788      already_AddRefed<DirectMediaTrackListener> aListener) override;
    789  void RemoveDirectListenerImpl(DirectMediaTrackListener* aListener) override;
    790 
    791  /**
    792   * Notify direct consumers of new data to this track.
    793   * The data doesn't have to be resampled (though it may be).  This is called
    794   * from AppendData on the thread providing the data, and will call
    795   * the Listeners on this thread.
    796   */
    797  void NotifyDirectConsumers(MediaSegment* aSegment) MOZ_REQUIRES(mMutex);
    798 
    799  void OnGraphThreadDone() override {
    800    MutexAutoLock lock(mMutex);
    801    if (!mUpdateTrack) {
    802      return;
    803    }
    804    mUpdateTrack->mGraphThreadDone = true;
    805    if (!mUpdateTrack->mData) {
    806      return;
    807    }
    808    mUpdateTrack->mData->Clear();
    809  }
    810 
    811  virtual void AdvanceTimeVaryingValuesToCurrentTime(
    812      GraphTime aCurrentTime, GraphTime aBlockedTime) override;
    813 
    814  // This must be acquired *before* MediaTrackGraphImpl's lock, if they are
    815  // held together.
    816  Mutex mMutex;
    817  // protected by mMutex
    818  float mVolume MOZ_GUARDED_BY(mMutex) = 1.0;
    819  UniquePtr<TrackData> mUpdateTrack MOZ_GUARDED_BY(mMutex);
    820  // This track's associated disabled mode for uses on the producing thread.
    821  // It can either by disabled by frames being replaced by black, or by
    822  // retaining the previous frame.
    823  DisabledTrackMode mDirectDisabledMode MOZ_GUARDED_BY(mMutex) =
    824      DisabledTrackMode::ENABLED;
    825  nsTArray<RefPtr<DirectMediaTrackListener>> mDirectTrackListeners
    826      MOZ_GUARDED_BY(mMutex);
    827 };
    828 
    829 /**
    830 * A ref-counted wrapper of a MediaTrack that allows multiple users to share a
    831 * reference to the same MediaTrack with the purpose of being guaranteed that
    832 * the graph it is in is kept alive.
    833 *
    834 * Automatically suspended on creation and destroyed on destruction. Main thread
    835 * only.
    836 */
    837 struct SharedDummyTrack {
    838  NS_INLINE_DECL_REFCOUNTING(SharedDummyTrack)
    839  explicit SharedDummyTrack(MediaTrack* aTrack) : mTrack(aTrack) {
    840    mTrack->Suspend();
    841  }
    842  const RefPtr<MediaTrack> mTrack;
    843 
    844 private:
    845  ~SharedDummyTrack() { mTrack->Destroy(); }
    846 };
    847 
    848 /**
    849 * Represents a connection between a ProcessedMediaTrack and one of its
    850 * input tracks.
    851 * We make these refcounted so that track-related messages with MediaInputPort*
    852 * pointers can be sent to the main thread safely.
    853 *
    854 * When a port's source or destination track dies, the track's DestroyImpl
    855 * calls MediaInputPort::Disconnect to disconnect the port from
    856 * the source and destination tracks.
    857 *
    858 * The lifetimes of MediaInputPort are controlled from the main thread.
    859 * The media graph adds a reference to the port. When a MediaInputPort is no
    860 * longer needed, main-thread code sends a Destroy message for the port and
    861 * clears its reference (the last main-thread reference to the object). When
    862 * the Destroy message is processed on the graph manager thread we disconnect
    863 * the port and drop the graph's reference, destroying the object.
    864 */
    865 class MediaInputPort final {
    866 private:
    867  // Do not call this constructor directly. Instead call
    868  // aDest->AllocateInputPort.
    869  MediaInputPort(MediaTrackGraphImpl* aGraph, MediaTrack* aSource,
    870                 ProcessedMediaTrack* aDest, uint16_t aInputNumber,
    871                 uint16_t aOutputNumber)
    872      : mSource(aSource),
    873        mDest(aDest),
    874        mInputNumber(aInputNumber),
    875        mOutputNumber(aOutputNumber),
    876        mGraph(aGraph) {
    877    MOZ_COUNT_CTOR(MediaInputPort);
    878  }
    879 
    880  // Private destructor, to discourage deletion outside of Release():
    881  MOZ_COUNTED_DTOR(MediaInputPort)
    882 
    883 public:
    884  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaInputPort)
    885 
    886  /**
    887   * Disconnects and destroys the port. The caller must not reference this
    888   * object again. Main thread.
    889   */
    890  void Destroy();
    891 
    892  // The remaining methods and members must always be called on the graph thread
    893  // from within MediaTrackGraph.cpp.
    894 
    895  void Init();
    896  // Called during message processing to trigger removal of this port's source
    897  // and destination tracks.
    898  void Disconnect();
    899 
    900  MediaTrack* GetSource() const;
    901  ProcessedMediaTrack* GetDestination() const;
    902 
    903  uint16_t InputNumber() const { return mInputNumber; }
    904  uint16_t OutputNumber() const { return mOutputNumber; }
    905 
    906  struct InputInterval {
    907    GraphTime mStart;
    908    GraphTime mEnd;
    909    bool mInputIsBlocked;
    910  };
    911  // Find the next time interval starting at or after aTime during which
    912  // aPort->mDest is not blocked and aPort->mSource's blocking status does not
    913  // change. A null aPort returns a blocked interval starting at aTime.
    914  static InputInterval GetNextInputInterval(MediaInputPort const* aPort,
    915                                            GraphTime aTime);
    916 
    917  /**
    918   * Returns the graph that owns this port.
    919   */
    920  MediaTrackGraphImpl* GraphImpl() const;
    921  MediaTrackGraph* Graph() const;
    922 
    923  /**
    924   * Sets the graph that owns this track.  Should only be called once.
    925   */
    926  void SetGraphImpl(MediaTrackGraphImpl* aGraph);
    927 
    928  /**
    929   * Notify the port that the source MediaTrack has been suspended.
    930   */
    931  void Suspended();
    932 
    933  /**
    934   * Notify the port that the source MediaTrack has been resumed.
    935   */
    936  void Resumed();
    937 
    938  size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
    939    size_t amount = 0;
    940 
    941    // Not owned:
    942    // - mSource
    943    // - mDest
    944    // - mGraph
    945    return amount;
    946  }
    947 
    948  size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
    949    return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
    950  }
    951 
    952 private:
    953  friend class ProcessedMediaTrack;
    954  // Never modified after Init()
    955  MediaTrack* mSource;
    956  ProcessedMediaTrack* mDest;
    957  // The input and output numbers are optional, and are currently only used by
    958  // Web Audio.
    959  const uint16_t mInputNumber;
    960  const uint16_t mOutputNumber;
    961 
    962  // Our media track graph
    963  MediaTrackGraphImpl* mGraph;
    964 };
    965 
    966 /**
    967 * This track processes zero or more input tracks in parallel to produce
    968 * its output. The details of how the output is produced are handled by
    969 * subclasses overriding the ProcessInput method.
    970 */
    971 class ProcessedMediaTrack : public MediaTrack {
    972 public:
    973  ProcessedMediaTrack(TrackRate aSampleRate, MediaSegment::Type aType,
    974                      MediaSegment* aSegment)
    975      : MediaTrack(aSampleRate, aType, aSegment),
    976        mAutoend(true),
    977        mCycleMarker(0) {}
    978 
    979  // Control API.
    980  /**
    981   * Allocates a new input port attached to source aTrack.
    982   * This port can be removed by calling MediaInputPort::Destroy().
    983   */
    984  already_AddRefed<MediaInputPort> AllocateInputPort(
    985      MediaTrack* aTrack, uint16_t aInputNumber = 0,
    986      uint16_t aOutputNumber = 0);
    987  /**
    988   * Queue a message to set the autoend flag on this track (defaults to
    989   * true). When this flag is set, and the input track has ended playout
    990   * (including if there is no input track), this track automatically
    991   * enters the ended state.
    992   */
    993  virtual void QueueSetAutoend(bool aAutoend);
    994 
    995  ProcessedMediaTrack* AsProcessedTrack() override { return this; }
    996 
    997  friend class MediaTrackGraphImpl;
    998 
    999  // Do not call these from outside MediaTrackGraph.cpp!
   1000  virtual void AddInput(MediaInputPort* aPort);
   1001  virtual void RemoveInput(MediaInputPort* aPort) {
   1002    mInputs.RemoveElement(aPort) || mSuspendedInputs.RemoveElement(aPort);
   1003  }
   1004  bool HasInputPort(MediaInputPort* aPort) const {
   1005    return mInputs.Contains(aPort) || mSuspendedInputs.Contains(aPort);
   1006  }
   1007  uint32_t InputPortCount() const {
   1008    return mInputs.Length() + mSuspendedInputs.Length();
   1009  }
   1010  void InputSuspended(MediaInputPort* aPort);
   1011  void InputResumed(MediaInputPort* aPort);
   1012  void DestroyImpl() override;
   1013  void DecrementSuspendCount() override;
   1014  /**
   1015   * This gets called after we've computed the blocking states for all
   1016   * tracks (mBlocked is up to date up to mStateComputedTime).
   1017   * Also, we've produced output for all tracks up to this one. If this track
   1018   * is not in a cycle, then all its source tracks have produced data.
   1019   * Generate output from aFrom to aTo, where aFrom < aTo.
   1020   * This will be called on tracks that have ended. Most track types should
   1021   * just return immediately if they're ended, but some may wish to update
   1022   * internal state (see AudioNodeTrack).
   1023   * ProcessInput is allowed to set mEnded only if ALLOW_END is in aFlags. (This
   1024   * flag will be set when aTo >= mStateComputedTime, i.e. when we've produced
   1025   * the last block of data we need to produce.) Otherwise we can get into a
   1026   * situation where we've determined the track should not block before
   1027   * mStateComputedTime, but the track ends before mStateComputedTime, violating
   1028   * the invariant that ended tracks are blocked.
   1029   */
   1030  enum { ALLOW_END = 0x01 };
   1031  virtual void ProcessInput(GraphTime aFrom, GraphTime aTo,
   1032                            uint32_t aFlags) = 0;
   1033  void SetAutoendImpl(bool aAutoend) { mAutoend = aAutoend; }
   1034 
   1035  // Only valid after MediaTrackGraphImpl::UpdateTrackOrder() has run.
   1036  // A DelayNode is considered to break a cycle and so this will not return
   1037  // true for echo loops, only for muted cycles.
   1038  bool InMutedCycle() const { return mCycleMarker; }
   1039 
   1040  // Used by ForwardedInputTrack to propagate the disabled mode along the graph.
   1041  virtual void OnInputDisabledModeChanged(DisabledTrackMode aMode) {}
   1042 
   1043  size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override {
   1044    size_t amount = MediaTrack::SizeOfExcludingThis(aMallocSizeOf);
   1045    // Not owned:
   1046    // - mInputs elements
   1047    // - mSuspendedInputs elements
   1048    amount += mInputs.ShallowSizeOfExcludingThis(aMallocSizeOf);
   1049    amount += mSuspendedInputs.ShallowSizeOfExcludingThis(aMallocSizeOf);
   1050    return amount;
   1051  }
   1052 
   1053  size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override {
   1054    return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   1055  }
   1056 
   1057 protected:
   1058  // This state is all accessed only on the media graph thread.
   1059 
   1060  // The list of all inputs that are not currently suspended.
   1061  nsTArray<MediaInputPort*> mInputs;
   1062  // The list of all inputs that are currently suspended.
   1063  nsTArray<MediaInputPort*> mSuspendedInputs;
   1064  bool mAutoend;
   1065  // After UpdateTrackOrder(), mCycleMarker is either 0 or 1 to indicate
   1066  // whether this track is in a muted cycle.  During ordering it can contain
   1067  // other marker values - see MediaTrackGraphImpl::UpdateTrackOrder().
   1068  uint32_t mCycleMarker;
   1069 };
   1070 
   1071 /**
   1072 * There is a single MediaTrackGraph per window.
   1073 * Additionaly, each OfflineAudioContext object creates its own MediaTrackGraph
   1074 * object too.
   1075 */
   1076 class MediaTrackGraph {
   1077 public:
   1078  // We ensure that the graph current time advances in multiples of
   1079  // IdealAudioBlockSize()/AudioStream::PreferredSampleRate(). A track that
   1080  // never blocks and has the ideal audio rate will produce audio in multiples
   1081  // of the block size.
   1082 
   1083  // Initializing a graph that outputs audio can take quite long on some
   1084  // platforms. Code that want to output audio at some point can express the
   1085  // fact that they will need an audio track at some point by passing
   1086  // AUDIO_THREAD_DRIVER when getting an instance of MediaTrackGraph, so that
   1087  // the graph starts with the right driver.
   1088  enum GraphDriverType {
   1089    AUDIO_THREAD_DRIVER,
   1090    SYSTEM_THREAD_DRIVER,
   1091    OFFLINE_THREAD_DRIVER
   1092  };
   1093  // A MediaTrackGraph running an AudioWorklet must always be run from the
   1094  // same thread, in order to run js. To acheive this, create the graph with
   1095  // a SINGLE_THREAD RunType. DIRECT_DRIVER will run the graph directly off
   1096  // the GraphDriver's thread.
   1097  enum GraphRunType {
   1098    DIRECT_DRIVER,
   1099    SINGLE_THREAD,
   1100  };
   1101  static const uint32_t AUDIO_CALLBACK_DRIVER_SHUTDOWN_TIMEOUT = 20 * 1000;
   1102  static const TrackRate REQUEST_DEFAULT_SAMPLE_RATE = 0;
   1103  constexpr static const CubebUtils::AudioDeviceID DEFAULT_OUTPUT_DEVICE =
   1104      nullptr;
   1105 
   1106  // Main thread only
   1107  static MediaTrackGraph* GetInstanceIfExists(
   1108      nsPIDOMWindowInner* aWindow, TrackRate aSampleRate,
   1109      CubebUtils::AudioDeviceID aPrimaryOutputDeviceID);
   1110  static MediaTrackGraph* GetInstance(
   1111      GraphDriverType aGraphDriverRequested, nsPIDOMWindowInner* aWindow,
   1112      TrackRate aSampleRate, CubebUtils::AudioDeviceID aPrimaryOutputDeviceID);
   1113  static MediaTrackGraph* CreateNonRealtimeInstance(TrackRate aSampleRate);
   1114 
   1115  // Idempotent
   1116  void ForceShutDown();
   1117 
   1118  virtual void OpenAudioInput(DeviceInputTrack* aTrack) = 0;
   1119  virtual void CloseAudioInput(DeviceInputTrack* aTrack) = 0;
   1120 
   1121  // Control API.
   1122  /**
   1123   * Create a track that a media decoder (or some other source of
   1124   * media data, such as a camera) can write to.
   1125   */
   1126  SourceMediaTrack* CreateSourceTrack(MediaSegment::Type aType);
   1127  /**
   1128   * Create a track that will forward data from its input track.
   1129   *
   1130   * A TrackUnionStream can have 0 or 1 input streams. Adding more than that is
   1131   * an error.
   1132   *
   1133   * A TrackUnionStream will end when autoending is enabled (default) and there
   1134   * is no input, or the input's source is ended. If there is no input and
   1135   * autoending is disabled, TrackUnionStream will continue to produce silence
   1136   * for audio or the last video frame for video.
   1137   */
   1138  ProcessedMediaTrack* CreateForwardedInputTrack(MediaSegment::Type aType);
   1139  /**
   1140   * Create a track that will mix all its audio inputs.
   1141   */
   1142  AudioCaptureTrack* CreateAudioCaptureTrack();
   1143 
   1144  CrossGraphTransmitter* CreateCrossGraphTransmitter(
   1145      CrossGraphReceiver* aReceiver);
   1146  CrossGraphReceiver* CreateCrossGraphReceiver(TrackRate aTransmitterRate);
   1147 
   1148  /**
   1149   * Add a new track to the graph.  Main thread.
   1150   */
   1151  void AddTrack(MediaTrack* aTrack);
   1152 
   1153  /* From the main thread, ask the MTG to resolve the returned promise when
   1154   * the device specified has started.
   1155   * A null aDeviceID indicates the default audio output device.
   1156   * The promise is rejected with NS_ERROR_INVALID_ARG if aDeviceID does not
   1157   * correspond to any output devices used by the graph, or
   1158   * NS_ERROR_NOT_AVAILABLE if outputs to the device are removed or
   1159   * NS_ERROR_ILLEGAL_DURING_SHUTDOWN if the graph is force shut down
   1160   * before the promise could be resolved.
   1161   */
   1162  using GraphStartedPromise = GenericPromise;
   1163  virtual RefPtr<GraphStartedPromise> NotifyWhenDeviceStarted(
   1164      CubebUtils::AudioDeviceID aDeviceID) = 0;
   1165 
   1166  /* From the main thread, suspend, resume or close an AudioContext.  Calls
   1167   * are not counted.  Even Resume calls can be more frequent than Suspend
   1168   * calls.
   1169   *
   1170   * aTracks are the tracks of all the AudioNodes of the AudioContext that
   1171   * need to be suspended or resumed.  Suspend and Resume operations on these
   1172   * tracks are counted.  Resume operations must not outnumber Suspends and a
   1173   * track will not resume until the number of Resume operations matches the
   1174   * number of Suspends.  This array may be empty if, for example, this is a
   1175   * second consecutive suspend call and all the nodes are already suspended.
   1176   *
   1177   * This can possibly pause the graph thread, releasing system resources, if
   1178   * all tracks have been suspended/closed.
   1179   *
   1180   * When the operation is complete, the returned promise is resolved.
   1181   */
   1182  using AudioContextOperationPromise =
   1183      MozPromise<dom::AudioContextState, bool, true>;
   1184  RefPtr<AudioContextOperationPromise> ApplyAudioContextOperation(
   1185      MediaTrack* aDestinationTrack, nsTArray<RefPtr<MediaTrack>> aTracks,
   1186      dom::AudioContextOperation aOperation);
   1187 
   1188  bool IsNonRealtime() const;
   1189  /**
   1190   * Start processing non-realtime for a specific number of ticks.
   1191   */
   1192  void StartNonRealtimeProcessing(uint32_t aTicksToProcess);
   1193 
   1194  /**
   1195   * NotifyJSContext() is called on the graph thread before content script
   1196   * runs.
   1197   */
   1198  void NotifyJSContext(JSContext* aCx);
   1199 
   1200  /**
   1201   * Media graph thread only.
   1202   * Dispatches a runnable that will run on the main thread after all
   1203   * main-thread track state has been updated, i.e., during stable state.
   1204   *
   1205   * Should only be called during MediaTrackListener callbacks or during
   1206   * ProcessedMediaTrack::ProcessInput().
   1207   *
   1208   * Note that if called during shutdown the runnable will be ignored and
   1209   * released on main thread.
   1210   */
   1211  void DispatchToMainThreadStableState(already_AddRefed<nsIRunnable> aRunnable);
   1212  /* Called on the graph thread when the input device settings should be
   1213   * reevaluated, for example, if the channel count of the input track should
   1214   * be changed. */
   1215  void ReevaluateInputDevice(CubebUtils::AudioDeviceID aID);
   1216 
   1217  /**
   1218   * Returns graph sample rate in Hz.
   1219   */
   1220  TrackRate GraphRate() const { return mSampleRate; }
   1221  /**
   1222   * Returns the ID of the device used for audio output through an
   1223   * AudioCallbackDriver.  This is the device specified when creating the
   1224   * graph.  Can be called on any thread.
   1225   */
   1226  CubebUtils::AudioDeviceID PrimaryOutputDeviceID() const {
   1227    return mPrimaryOutputDeviceID;
   1228  }
   1229 
   1230  double AudioOutputLatency();
   1231  /* Return whether the clock for the audio output device used for the AEC
   1232   * reverse stream might drift from the clock for this MediaTrackGraph.
   1233   * Graph thread only. */
   1234  bool OutputForAECMightDrift();
   1235  /* Return whether the audio output device used for the aec reverse stream
   1236   * corresponds to the primary output device, explicitly or implicitly,
   1237   * implicitly meaning when the primary output device is the system default
   1238   * output device, and the output device used for the aec reverse stream is
   1239   * explicit and matches the current system default output device.
   1240   * Graph thread only. */
   1241  bool OutputForAECIsPrimary();
   1242 
   1243  void RegisterCaptureTrackForWindow(uint64_t aWindowId,
   1244                                     ProcessedMediaTrack* aCaptureTrack);
   1245  void UnregisterCaptureTrackForWindow(uint64_t aWindowId);
   1246  already_AddRefed<MediaInputPort> ConnectToCaptureTrack(
   1247      uint64_t aWindowId, MediaTrack* aMediaTrack);
   1248 
   1249  void AssertOnGraphThread() const { MOZ_ASSERT(OnGraphThread()); }
   1250  void AssertOnGraphThreadOrNotRunning() const {
   1251    MOZ_ASSERT(OnGraphThreadOrNotRunning());
   1252  }
   1253 
   1254  /**
   1255   * Returns a watchable of the graph's main-thread observable graph time.
   1256   * Main thread only.
   1257   */
   1258  virtual Watchable<GraphTime>& CurrentTime() = 0;
   1259 
   1260  /**
   1261   * Graph thread function to return the time at which all processing has been
   1262   * completed.  Some tracks may have performed processing beyond this time.
   1263   */
   1264  GraphTime ProcessedTime() const;
   1265  /**
   1266   * For Graph thread logging.
   1267   */
   1268  void* CurrentDriver() const;
   1269 
   1270  /* Do not call this directly. For users who need to get a DeviceInputTrack,
   1271   * use DeviceInputTrack::OpenAudio() instead. This should only be used in
   1272   * DeviceInputTrack to get the existing DeviceInputTrack paired with the given
   1273   * device in this graph. Main thread only.*/
   1274  DeviceInputTrack* GetDeviceInputTrackMainThread(
   1275      CubebUtils::AudioDeviceID aID);
   1276 
   1277  /* Do not call this directly. This should only be used in DeviceInputTrack to
   1278   * get the existing NativeInputTrackMain thread only.*/
   1279  NativeInputTrack* GetNativeInputTrackMainThread();
   1280 
   1281  /* Return a positive monotonically increasing graph-unique generation id for
   1282   * AudioInputProcessingParamsRequest::mGeneration. */
   1283  int ProcessingParamsGeneration() { return ++mProcessingParamsGeneration; }
   1284 
   1285 protected:
   1286  explicit MediaTrackGraph(TrackRate aSampleRate,
   1287                           CubebUtils::AudioDeviceID aPrimaryOutputDeviceID)
   1288      : mSampleRate(aSampleRate),
   1289        mPrimaryOutputDeviceID(aPrimaryOutputDeviceID) {
   1290    MOZ_COUNT_CTOR(MediaTrackGraph);
   1291  }
   1292  MOZ_COUNTED_DTOR_VIRTUAL(MediaTrackGraph)
   1293 
   1294  // Intended only for assertions, either on graph thread or not running (in
   1295  // which case we must be on the main thread).
   1296  virtual bool OnGraphThreadOrNotRunning() const = 0;
   1297  virtual bool OnGraphThread() const = 0;
   1298 
   1299  // Intended only for internal assertions. Main thread only.
   1300  virtual bool Destroyed() const = 0;
   1301 
   1302  /**
   1303   * Sample rate at which this graph runs. For real time graphs, this is
   1304   * the rate of the audio mixer. For offline graphs, this is the rate specified
   1305   * at construction.
   1306   */
   1307  const TrackRate mSampleRate;
   1308  /**
   1309   * Device to use for audio output through an AudioCallbackDriver.
   1310   * This is the device specified when creating the graph.
   1311   */
   1312  const CubebUtils::AudioDeviceID mPrimaryOutputDeviceID;
   1313 
   1314  /* A monotonically increasing graph-unique generation for
   1315   * AudioInputProcessingParamsRequest::mGeneration. */
   1316  int mProcessingParamsGeneration = 0;
   1317 };
   1318 
   1319 inline void MediaTrack::AssertOnGraphThread() const {
   1320  Graph()->AssertOnGraphThread();
   1321 }
   1322 inline void MediaTrack::AssertOnGraphThreadOrNotRunning() const {
   1323  Graph()->AssertOnGraphThreadOrNotRunning();
   1324 }
   1325 
   1326 /**
   1327 * This represents a message run on the graph thread to modify track or graph
   1328 * state.  These are passed from main thread to graph thread by
   1329 * QueueControlMessageWithNoShutdown() or QueueControlOrShutdownMessage()
   1330 * through AppendMessage(), or scheduled on the graph thread with
   1331 * RunAfterProcessing().
   1332 */
   1333 class MediaTrack::ControlMessageInterface {
   1334 public:
   1335  MOZ_COUNTED_DEFAULT_CTOR(ControlMessageInterface)
   1336  // All these run on the graph thread unless the graph has been forced to
   1337  // shut down.
   1338  MOZ_COUNTED_DTOR_VIRTUAL(ControlMessageInterface)
   1339  // Do the action of this message on the MediaTrackGraph thread. Any actions
   1340  // affecting graph processing should take effect at mProcessedTime.
   1341  // All track data for times < mProcessedTime has already been
   1342  // computed.
   1343  virtual void Run() = 0;
   1344  // RunDuringShutdown() is only relevant to messages generated on the main
   1345  // thread by QueueControlOrShutdownMessage() or for AppendMessage().
   1346  // When we're shutting down the application, most messages are ignored but
   1347  // some cleanup messages should still be processed (on the main thread).
   1348  // This must not add new control messages to the graph.
   1349  virtual void RunDuringShutdown() {}
   1350 };
   1351 
   1352 template <typename Function>
   1353 class MediaTrack::ControlMessageWithNoShutdown
   1354    : public ControlMessageInterface {
   1355 public:
   1356  explicit ControlMessageWithNoShutdown(Function&& aFunction)
   1357      : mFunction(std::forward<Function>(aFunction)) {}
   1358 
   1359  void Run() override {
   1360    static_assert(std::is_void_v<decltype(mFunction())>,
   1361                  "The lambda must return void!");
   1362    mFunction();
   1363  }
   1364 
   1365 private:
   1366  using StoredFunction = std::decay_t<Function>;
   1367  StoredFunction mFunction;
   1368 };
   1369 
   1370 template <typename Function>
   1371 class MediaTrack::ControlOrShutdownMessage : public ControlMessageInterface {
   1372 public:
   1373  explicit ControlOrShutdownMessage(Function&& aFunction)
   1374      : mFunction(std::forward<Function>(aFunction)) {}
   1375 
   1376  void Run() override {
   1377    static_assert(std::is_void_v<decltype(mFunction(IsInShutdown()))>,
   1378                  "The lambda must return void!");
   1379    mFunction(IsInShutdown::No);
   1380  }
   1381  void RunDuringShutdown() override { mFunction(IsInShutdown::Yes); }
   1382 
   1383 private:
   1384  // The same lambda is used whether or not in shutdown so that captured
   1385  // variables are available in both cases.
   1386  using StoredFunction = std::decay_t<Function>;
   1387  StoredFunction mFunction;
   1388 };
   1389 
   1390 }  // namespace mozilla
   1391 
   1392 #endif /* MOZILLA_MEDIATRACKGRAPH_H_ */