tor-browser

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

MediaTrackGraphImpl.h (45348B)


      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_MEDIATRACKGRAPHIMPL_H_
      7 #define MOZILLA_MEDIATRACKGRAPHIMPL_H_
      8 
      9 #include <atomic>
     10 
     11 #include "AsyncLogger.h"
     12 #include "AudioMixer.h"
     13 #include "DeviceInputTrack.h"
     14 #include "GraphDriver.h"
     15 #include "MediaEventSource.h"
     16 #include "MediaTrackGraph.h"
     17 #include "mozilla/Atomics.h"
     18 #include "mozilla/Monitor.h"
     19 #include "mozilla/TimeStamp.h"
     20 #include "mozilla/UniquePtr.h"
     21 #include "nsClassHashtable.h"
     22 #include "nsIMemoryReporter.h"
     23 #include "nsINamed.h"
     24 #include "nsIRunnable.h"
     25 #include "nsIThreadInternal.h"
     26 #include "nsITimer.h"
     27 
     28 namespace mozilla {
     29 
     30 namespace media {
     31 class ShutdownBlocker;
     32 }
     33 
     34 class AudioContextOperationControlMessage;
     35 class CubebDeviceEnumerator;
     36 template <typename T>
     37 class LinkedList;
     38 class GraphRunner;
     39 
     40 class DeviceInputTrackManager {
     41 public:
     42  DeviceInputTrackManager() = default;
     43 
     44  // Returns the current NativeInputTrack.
     45  NativeInputTrack* GetNativeInputTrack();
     46  // Returns the DeviceInputTrack paired with the device of aID if it exists.
     47  // Otherwise, returns nullptr.
     48  DeviceInputTrack* GetDeviceInputTrack(CubebUtils::AudioDeviceID aID);
     49  // Returns the first added NonNativeInputTrack if any. Otherwise, returns
     50  // nullptr.
     51  NonNativeInputTrack* GetFirstNonNativeInputTrack();
     52  // Adds DeviceInputTrack to the managing list.
     53  void Add(DeviceInputTrack* aTrack);
     54  // Removes DeviceInputTrack from the managing list.
     55  void Remove(DeviceInputTrack* aTrack);
     56 
     57 private:
     58  RefPtr<NativeInputTrack> mNativeInputTrack;
     59  nsTArray<RefPtr<NonNativeInputTrack>> mNonNativeInputTracks;
     60 };
     61 
     62 /**
     63 * A per-track update message passed from the media graph thread to the
     64 * main thread.
     65 */
     66 struct TrackUpdate {
     67  RefPtr<MediaTrack> mTrack;
     68  TrackTime mNextMainThreadCurrentTime;
     69  bool mNextMainThreadEnded;
     70 };
     71 
     72 /**
     73 * This represents a message run on the graph thread to modify track or graph
     74 * state.  These are passed from main thread to graph thread through
     75 * AppendMessage().  A ControlMessage often has a weak reference to a
     76 * particular affected track.
     77 */
     78 class ControlMessage : public MediaTrack::ControlMessageInterface {
     79 public:
     80  explicit ControlMessage(MediaTrack* aTrack) : mTrack(aTrack) {
     81    MOZ_ASSERT(NS_IsMainThread());
     82    MOZ_RELEASE_ASSERT(!aTrack || !aTrack->IsDestroyed());
     83  }
     84 
     85  MediaTrack* GetTrack() { return mTrack; }
     86 
     87 protected:
     88  // We do not hold a reference to mTrack. The graph will be holding a reference
     89  // to the track until the Destroy message is processed. The last message
     90  // referencing a track is the Destroy message for that track.
     91  MediaTrack* const mTrack;
     92 };
     93 
     94 class MessageBlock {
     95 public:
     96  nsTArray<UniquePtr<MediaTrack::ControlMessageInterface>> mMessages;
     97 };
     98 
     99 /**
    100 * The implementation of a media track graph. This class is private to this
    101 * file. It's not in the anonymous namespace because MediaTrack needs to
    102 * be able to friend it.
    103 *
    104 * There can be multiple MediaTrackGraph per process: one per document.
    105 * Additionaly, each OfflineAudioContext object creates its own MediaTrackGraph
    106 * object too.
    107 */
    108 class MediaTrackGraphImpl : public MediaTrackGraph,
    109                            public GraphInterface,
    110                            public nsIMemoryReporter,
    111                            public nsIObserver,
    112                            public nsIThreadObserver,
    113                            public nsITimerCallback,
    114                            public nsINamed {
    115 public:
    116  using ControlMessageInterface = MediaTrack::ControlMessageInterface;
    117 
    118  NS_DECL_THREADSAFE_ISUPPORTS
    119  NS_DECL_NSIMEMORYREPORTER
    120  NS_DECL_NSIOBSERVER
    121  NS_DECL_NSITHREADOBSERVER
    122  NS_DECL_NSITIMERCALLBACK
    123  NS_DECL_NSINAMED
    124 
    125  /**
    126   * Use aGraphDriverRequested with SYSTEM_THREAD_DRIVER or AUDIO_THREAD_DRIVER
    127   * to create a MediaTrackGraph which provides support for real-time audio
    128   * and/or video.  Set it to OFFLINE_THREAD_DRIVER in order to create a
    129   * non-realtime instance which just churns through its inputs and produces
    130   * output.  Those objects currently only support audio, and are used to
    131   * implement OfflineAudioContext.  They do not support MediaTrack inputs.
    132   */
    133  explicit MediaTrackGraphImpl(uint64_t aWindowID, TrackRate aSampleRate,
    134                               CubebUtils::AudioDeviceID aOutputDeviceID,
    135                               nsISerialEventTarget* aMainThread);
    136 
    137  static MediaTrackGraphImpl* GetInstance(
    138      GraphDriverType aGraphDriverRequested, uint64_t aWindowID,
    139      TrackRate aSampleRate, CubebUtils::AudioDeviceID aPrimaryOutputDeviceID,
    140      nsISerialEventTarget* aMainThread);
    141  static MediaTrackGraphImpl* GetInstanceIfExists(
    142      uint64_t aWindowID, TrackRate aSampleRate,
    143      CubebUtils::AudioDeviceID aPrimaryOutputDeviceID);
    144  static MediaTrackGraph* CreateNonRealtimeInstance(TrackRate aSampleRate);
    145  // For GraphHashSet:
    146  struct Lookup;
    147  operator Lookup() const;
    148 
    149  // Intended only for assertions, either on graph thread or not running (in
    150  // which case we must be on the main thread).
    151  bool OnGraphThreadOrNotRunning() const override;
    152  bool OnGraphThread() const override;
    153 
    154  bool Destroyed() const override;
    155 
    156 #ifdef DEBUG
    157  /**
    158   * True if we're on aDriver's thread, or if we're on mGraphRunner's thread
    159   * and mGraphRunner is currently run by aDriver.
    160   */
    161  bool InDriverIteration(const GraphDriver* aDriver) const override;
    162 #endif
    163 
    164  /**
    165   * Unregisters memory reporting and deletes this instance. This should be
    166   * called instead of calling the destructor directly.
    167   */
    168  void Destroy();
    169 
    170  // Main thread only.
    171  /**
    172   * This runs every time we need to sync state from the media graph thread
    173   * to the main thread while the main thread is not in the middle
    174   * of a script. It runs during a "stable state" (per HTML5) or during
    175   * an event posted to the main thread.
    176   * The boolean affects which boolean controlling runnable dispatch is cleared
    177   */
    178  void RunInStableState(bool aSourceIsMTG);
    179  /**
    180   * Ensure a runnable to run RunInStableState is posted to the appshell to
    181   * run at the next stable state (per HTML5).
    182   * See EnsureStableStateEventPosted.
    183   */
    184  void EnsureRunInStableState();
    185  /**
    186   * Called to apply a TrackUpdate to its track.
    187   */
    188  void ApplyTrackUpdate(TrackUpdate* aUpdate) MOZ_REQUIRES(mMonitor);
    189  /**
    190   * Append a control message to the message queue. This queue is drained
    191   * during RunInStableState; the messages will run on the graph thread.
    192   */
    193  virtual void AppendMessage(UniquePtr<ControlMessageInterface> aMessage);
    194  /**
    195   * Append to the message queue a control message to execute a given lambda
    196   * function with no parameters.  The lambda will be executed on the graph
    197   * thread.  The lambda will not be executed if the graph has been forced to
    198   * shut down.
    199   **/
    200  template <typename Function>
    201  void QueueControlMessageWithNoShutdown(Function&& aFunction) {
    202    AppendMessage(WrapUnique(new MediaTrack::ControlMessageWithNoShutdown(
    203        std::forward<Function>(aFunction))));
    204  }
    205  /**
    206   * Append to the message queue a control message to execute a given lambda
    207   * function with a single IsInShutdown parameter.  A No argument indicates
    208   * execution on the thread of a graph that is still running.  A Yes argument
    209   * indicates execution on the main thread when the graph has been forced to
    210   * shut down.
    211   **/
    212  template <typename Function>
    213  void QueueControlOrShutdownMessage(Function&& aFunction) {
    214    AppendMessage(WrapUnique(new MediaTrack::ControlOrShutdownMessage(
    215        std::forward<Function>(aFunction))));
    216  }
    217  /* Add or remove an audio output for this track.  At most one output may be
    218   * registered per key.  aPreferredSampleRate is the rate preferred by the
    219   * output device; it may be zero to indicate the preferred rate for the
    220   * default device; it is unused when aDeviceID is the graph's primary output.
    221   */
    222  void RegisterAudioOutput(MediaTrack* aTrack, void* aKey,
    223                           CubebUtils::AudioDeviceID aDeviceID,
    224                           TrackRate aPreferredSampleRate);
    225  void UnregisterAudioOutput(MediaTrack* aTrack, void* aKey);
    226 
    227  void SetAudioOutputVolume(MediaTrack* aTrack, void* aKey, float aVolume);
    228  /* Manage the creation and destruction of CrossGraphReceivers.
    229   * aPreferredSampleRate is the rate preferred by the output device. */
    230  void IncrementOutputDeviceRefCnt(CubebUtils::AudioDeviceID aDeviceID,
    231                                   TrackRate aPreferredSampleRate);
    232  void DecrementOutputDeviceRefCnt(CubebUtils::AudioDeviceID aDeviceID);
    233  /* Send a control message to update mOutputDevices for main thread changes to
    234   * mAudioOutputParams. */
    235  void UpdateAudioOutput(MediaTrack* aTrack,
    236                         CubebUtils::AudioDeviceID aDeviceID);
    237  /**
    238   * Dispatches a runnable from any thread to the correct main thread for this
    239   * MediaTrackGraph.
    240   */
    241  void Dispatch(already_AddRefed<nsIRunnable>&& aRunnable);
    242 
    243  /**
    244   * Make this MediaTrackGraph enter forced-shutdown state. This state
    245   * will be noticed by the media graph thread, which will shut down all tracks
    246   * and other state controlled by the media graph thread.
    247   * This is called during application shutdown, and on document unload if an
    248   * AudioContext is using the graph.
    249   */
    250  void ForceShutDown();
    251 
    252  /**
    253   * Sets mShutdownBlocker and makes it block shutdown.
    254   * Main thread only. Not idempotent. Returns true if a blocker was added,
    255   * false if this failed.
    256   */
    257  bool AddShutdownBlocker();
    258 
    259  /**
    260   * Removes mShutdownBlocker and unblocks shutdown.
    261   * Main thread only. Idempotent.
    262   */
    263  void RemoveShutdownBlocker();
    264 
    265  /**
    266   * Called before the thread runs.
    267   */
    268  void Init(GraphDriverType aDriverRequested, GraphRunType aRunTypeRequested,
    269            uint32_t aChannelCount);
    270 
    271  /**
    272   * Respond to CollectReports with sizes collected on the graph thread.
    273   */
    274  static void FinishCollectReports(
    275      nsIHandleReportCallback* aHandleReport, nsISupports* aData,
    276      const nsTArray<AudioNodeSizes>& aAudioTrackSizes);
    277 
    278  // The following methods run on the graph thread (or possibly the main thread
    279  // if mLifecycleState > LIFECYCLE_RUNNING)
    280  void CollectSizesForMemoryReport(
    281      already_AddRefed<nsIHandleReportCallback> aHandleReport,
    282      already_AddRefed<nsISupports> aHandlerData);
    283 
    284  /**
    285   * Returns true if this MediaTrackGraph should keep running
    286   */
    287  bool UpdateMainThreadState();
    288 
    289  /**
    290   * Proxy method called by GraphDriver to iterate the graph.
    291   * If this graph was created with GraphRunType SINGLE_THREAD, mGraphRunner
    292   * will take care of calling OneIterationImpl from its thread. Otherwise,
    293   * OneIterationImpl is called directly. Mixed audio output from the graph is
    294   * passed into aMixerReceiver, if it is non-null.
    295   */
    296  IterationResult OneIteration(GraphTime aStateTime,
    297                               MixerCallbackReceiver* aMixerReceiver) override;
    298 
    299  /**
    300   * Returns true if this MediaTrackGraph should keep running
    301   */
    302  IterationResult OneIterationImpl(GraphTime aStateTime,
    303                                   MixerCallbackReceiver* aMixerReceiver);
    304 
    305  /**
    306   * Called from the driver, when the graph thread is about to stop, to tell
    307   * the main thread to attempt to begin cleanup.  The main thread may either
    308   * shutdown or revive the graph depending on whether it receives new
    309   * messages.
    310   */
    311  void SignalMainThreadCleanup();
    312 
    313  /**
    314   * Ensure there is an event posted to the main thread to run RunInStableState.
    315   * mMonitor must be held.
    316   * See EnsureRunInStableState
    317   */
    318  void EnsureStableStateEventPosted() MOZ_REQUIRES(mMonitor);
    319  /**
    320   * Generate messages to the main thread to update it for all state changes.
    321   * mMonitor must be held.
    322   */
    323  void PrepareUpdatesToMainThreadState(bool aFinalUpdate)
    324      MOZ_REQUIRES(mMonitor);
    325  /**
    326   * If we are rendering in non-realtime mode, we don't want to send messages to
    327   * the main thread at each iteration for performance reasons. We instead
    328   * notify the main thread at the same rate
    329   */
    330  bool ShouldUpdateMainThread();
    331  // The following methods are the various stages of RunThread processing.
    332  /**
    333   * Advance all track state to mStateComputedTime.
    334   */
    335  void UpdateCurrentTimeForTracks(GraphTime aPrevCurrentTime);
    336  /**
    337   * Process chunks for all tracks and raise events for properties that have
    338   * changed, such as principalId.
    339   */
    340  void ProcessChunkMetadata(GraphTime aPrevCurrentTime);
    341  /**
    342   * Process chunks for the given track and interval, and raise events for
    343   * properties that have changed, such as principalHandle.
    344   */
    345  template <typename C, typename Chunk>
    346  void ProcessChunkMetadataForInterval(MediaTrack* aTrack, C& aSegment,
    347                                       TrackTime aStart, TrackTime aEnd);
    348  /**
    349   * Process graph messages in mFrontMessageQueue.
    350   */
    351  void RunMessagesInQueue();
    352  /**
    353   * Update track processing order and recompute track blocking until
    354   * aEndBlockingDecisions.
    355   */
    356  void UpdateGraph(GraphTime aEndBlockingDecisions);
    357 
    358  void SwapMessageQueues() {
    359    MonitorAutoLock lock(mMonitor);
    360    MOZ_ASSERT(OnGraphThreadOrNotRunning());
    361    MOZ_ASSERT(mFrontMessageQueue.IsEmpty());
    362    mFrontMessageQueue.SwapElements(mBackMessageQueue);
    363  }
    364  /**
    365   * Do all the processing and play the audio and video, from
    366   * mProcessedTime to mStateComputedTime.
    367   */
    368  void Process(MixerCallbackReceiver* aMixerReceiver);
    369 
    370  /**
    371   * For use during ProcessedMediaTrack::ProcessInput() or
    372   * MediaTrackListener callbacks, when graph state cannot be changed.
    373   * Schedules |aMessage| to run after processing, at a time when graph state
    374   * can be changed.  Graph thread.
    375   */
    376  void RunMessageAfterProcessing(UniquePtr<ControlMessageInterface> aMessage);
    377 
    378  /* From the main thread, ask the MTG to resolve the returned promise when
    379   * the device specified has started.
    380   * A null aDeviceID indicates the default audio output device.
    381   * The promise is rejected with NS_ERROR_INVALID_ARG if aDeviceID does not
    382   * correspond to any output devices used by the graph, or
    383   * NS_ERROR_NOT_AVAILABLE if outputs to the device are removed or
    384   * NS_ERROR_ILLEGAL_DURING_SHUTDOWN if the graph is force shut down
    385   * before the promise could be resolved.
    386   */
    387  using GraphStartedPromise = GenericPromise;
    388  RefPtr<GraphStartedPromise> NotifyWhenDeviceStarted(
    389      CubebUtils::AudioDeviceID aDeviceID) override;
    390 
    391  /**
    392   * Resolve the GraphStartedPromise when the driver has started processing on
    393   * the audio thread after the device has started.
    394   * (Audio is initially processed in the FallbackDriver's thread while the
    395   * device is starting up.)
    396   */
    397  void NotifyWhenPrimaryDeviceStarted(
    398      MozPromiseHolder<GraphStartedPromise>&& aHolder);
    399 
    400  /**
    401   * Apply an AudioContext operation (suspend/resume/close), on the graph
    402   * thread.
    403   */
    404  void ApplyAudioContextOperationImpl(
    405      AudioContextOperationControlMessage* aMessage);
    406 
    407  /**
    408   * Determine if we have any audio tracks, or are about to add any audiotracks.
    409   */
    410  bool AudioTrackPresent();
    411 
    412  /**
    413   * Schedules a replacement GraphDriver in mNextDriver, if necessary.
    414   */
    415  void CheckDriver();
    416 
    417  /**
    418   * Sort mTracks so that every track not in a cycle is after any tracks
    419   * it depends on, and every track in a cycle is marked as being in a cycle.
    420   */
    421  void UpdateTrackOrder();
    422 
    423  /**
    424   * Returns smallest value of t such that t is a multiple of
    425   * WEBAUDIO_BLOCK_SIZE and t >= aTime.
    426   */
    427  static GraphTime RoundUpToEndOfAudioBlock(GraphTime aTime);
    428  /**
    429   * Returns smallest value of t such that t is a multiple of
    430   * WEBAUDIO_BLOCK_SIZE and t > aTime.
    431   */
    432  static GraphTime RoundUpToNextAudioBlock(GraphTime aTime);
    433  /**
    434   * Produce data for all tracks >= aTrackIndex for the current time interval.
    435   * Advances block by block, each iteration producing data for all tracks
    436   * for a single block.
    437   * This is called whenever we have an AudioNodeTrack in the graph.
    438   */
    439  void ProduceDataForTracksBlockByBlock(uint32_t aTrackIndex,
    440                                        TrackRate aSampleRate);
    441  /**
    442   * If aTrack will underrun between aTime, and aEndBlockingDecisions, returns
    443   * the time at which the underrun will start. Otherwise return
    444   * aEndBlockingDecisions.
    445   */
    446  GraphTime WillUnderrun(MediaTrack* aTrack, GraphTime aEndBlockingDecisions);
    447 
    448  /**
    449   * Given a graph time aTime, convert it to a track time taking into
    450   * account the time during which aTrack is scheduled to be blocked.
    451   */
    452  TrackTime GraphTimeToTrackTimeWithBlocking(const MediaTrack* aTrack,
    453                                             GraphTime aTime) const;
    454 
    455 protected:
    456  /**
    457   * Set mOutputDeviceForAEC to indicate the audio output to be passed as the
    458   * reverse stream for audio echo cancellation.  Graph thread.
    459   */
    460  void SelectOutputDeviceForAEC();
    461  /**
    462   * Queue audio (mix of track audio and silence for blocked intervals)
    463   * to the audio output track. Returns the number of frames played.
    464   */
    465  struct TrackAndVolume;
    466  TrackTime PlayAudio(const TrackAndVolume& aOutput, GraphTime aPlayedTime,
    467                      uint32_t aOutputChannelCount);
    468 
    469 public:
    470  /* Runs off a message on the graph thread when something requests audio from
    471   * an input audio device of ID aID, and delivers the input audio frames to
    472   * aListener. */
    473  void OpenAudioInputImpl(DeviceInputTrack* aTrack);
    474  /* Called on the main thread when something requests audio from an input
    475   * audio device aID. */
    476  virtual void OpenAudioInput(DeviceInputTrack* aTrack) override;
    477 
    478  /* Runs off a message on the graph when input audio from aID is not needed
    479   * anymore, for a particular track. It can be that other tracks still need
    480   * audio from this audio input device. */
    481  void CloseAudioInputImpl(DeviceInputTrack* aTrack);
    482  /* Called on the main thread when input audio from aID is not needed
    483   * anymore, for a particular track. It can be that other tracks still need
    484   * audio from this audio input device. */
    485  virtual void CloseAudioInput(DeviceInputTrack* aTrack) override;
    486 
    487  void UnregisterAllAudioOutputs(MediaTrack* aTrack);
    488 
    489  /* Called on the graph thread when the input device settings should be
    490   * reevaluated, for example, if the channel count of the input track should
    491   * be changed. */
    492  void ReevaluateInputDevice(CubebUtils::AudioDeviceID aID);
    493 
    494  /* Called on the graph thread when there is new output data for listeners.
    495   * This is the mixed audio output of this MediaTrackGraph. */
    496  void NotifyOutputData(const AudioChunk& aChunk);
    497  /* Called on the graph thread after an AudioCallbackDriver with an input
    498   * stream has stopped. */
    499  void NotifyInputStopped() override;
    500  /* Called on the graph thread when there is new input data for listeners. This
    501   * is the raw audio input for this MediaTrackGraph. */
    502  void NotifyInputData(const AudioDataValue* aBuffer, size_t aFrames,
    503                       TrackRate aRate, uint32_t aChannels,
    504                       uint32_t aAlreadyBuffered) override;
    505  /* Called on the main thread after an AudioCallbackDriver has attempted an
    506   * operation to set aRequestedParams on the cubeb stream. */
    507  void NotifySetRequestedInputProcessingParamsResult(
    508      AudioCallbackDriver* aDriver, int aGeneration,
    509      Result<cubeb_input_processing_params, int>&& aResult) override;
    510  /* Called every time there are changes to input/output audio devices like
    511   * plug/unplug etc. This can be called on any thread, and posts a message to
    512   * the main thread so that it can post a message to the graph thread. */
    513  void DeviceChanged() override;
    514  /* Called every time there are changes to input/output audio devices. This is
    515   * called on the graph thread. */
    516  void DeviceChangedImpl();
    517 
    518  /**
    519   * Compute how much track data we would like to buffer for aTrack.
    520   */
    521  TrackTime GetDesiredBufferEnd(MediaTrack* aTrack);
    522  /**
    523   * Returns true when there are no active tracks.
    524   */
    525  bool IsEmpty() const {
    526    MOZ_ASSERT(
    527        OnGraphThreadOrNotRunning() ||
    528        (NS_IsMainThread() &&
    529         LifecycleStateRef() >= LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP));
    530    return mTracks.IsEmpty() && mSuspendedTracks.IsEmpty() && mPortCount == 0;
    531  }
    532 
    533  /**
    534   * Add aTrack to the graph and initializes its graph-specific state.
    535   */
    536  void AddTrackGraphThread(MediaTrack* aTrack);
    537  /**
    538   * Remove aTrack from the graph. Ensures that pending messages about the
    539   * track back to the main thread are flushed.
    540   */
    541  void RemoveTrackGraphThread(MediaTrack* aTrack);
    542  /**
    543   * Remove a track from the graph. Main thread.
    544   */
    545  void RemoveTrack(MediaTrack* aTrack);
    546  /**
    547   * Remove aPort from the graph and release it.
    548   */
    549  void DestroyPort(MediaInputPort* aPort);
    550  /**
    551   * Mark the media track order as dirty.
    552   */
    553  void SetTrackOrderDirty() {
    554    MOZ_ASSERT(OnGraphThreadOrNotRunning());
    555    mTrackOrderDirty = true;
    556  }
    557 
    558 protected:
    559  // Get the current maximum channel count required for a device.
    560  // aDevice is an element of mOutputDevices.  Graph thread only.
    561  struct OutputDeviceEntry;
    562  uint32_t AudioOutputChannelCount(const OutputDeviceEntry& aDevice) const;
    563  // Get the current maximum channel count for audio output through an
    564  // AudioCallbackDriver.  Graph thread only.
    565  uint32_t PrimaryOutputChannelCount() const;
    566 
    567 public:
    568  // Set a new maximum channel count. Graph thread only.
    569  void SetMaxOutputChannelCount(uint32_t aMaxChannelCount);
    570 
    571  double AudioOutputLatency();
    572  /* Return whether the clock for the audio output device used for the AEC
    573   * reverse stream might drift from the clock for this MediaTrackGraph. */
    574  bool OutputForAECMightDrift() {
    575    AssertOnGraphThread();
    576    return mOutputDeviceForAEC != PrimaryOutputDeviceID();
    577  }
    578  /* Return whether the audio output device used for the aec reverse stream
    579   * corresponds to the primary output device, explicitly or implicitly.
    580   * Implicitly meaning when the primary output device is the system default
    581   * output device, and the output device used for the aec reverse stream is
    582   * explicit and matches the current system default output device. */
    583  bool OutputForAECIsPrimary() {
    584    AssertOnGraphThread();
    585    if (mOutputDeviceForAEC == PrimaryOutputDeviceID()) {
    586      // Output device for AEC is explicitly the primary output device, which is
    587      // used for the duplex stream of the graph driver.
    588      return true;
    589    }
    590    // The output device for AEC is still considered primary if the primary
    591    // output device is set to follow the system default output device, and the
    592    // output device for AEC is explicitly the current system default output
    593    // device.
    594    return PrimaryOutputDeviceID() == DEFAULT_OUTPUT_DEVICE &&
    595           mOutputDeviceForAEC == mDefaultOutputDeviceID;
    596  }
    597  CubebUtils::AudioDeviceID DefaultOutputDeviceID() const {
    598    return mDefaultOutputDeviceID.load(std::memory_order_relaxed);
    599  }
    600  /**
    601   * Update whether the enumerator is set up for default output device tracking,
    602   * based on presence of input devices.
    603   * Marked virtual for unittests. Main thread only.
    604   */
    605  virtual void UpdateEnumeratorDefaultDeviceTracking();
    606  /**
    607   * Update the tracked default output device from the enumerator.
    608   * Main thread only.
    609   */
    610  void UpdateDefaultDevice();
    611  /**
    612   * The audio input channel count for a MediaTrackGraph is the max of all the
    613   * channel counts requested by the listeners. The max channel count is
    614   * delivered to the listeners themselves, and they take care of downmixing.
    615   */
    616  uint32_t AudioInputChannelCount(CubebUtils::AudioDeviceID aID);
    617 
    618  AudioInputType AudioInputDevicePreference(CubebUtils::AudioDeviceID aID);
    619 
    620  double MediaTimeToSeconds(GraphTime aTime) const {
    621    NS_ASSERTION(aTime > -TRACK_TIME_MAX && aTime <= TRACK_TIME_MAX,
    622                 "Bad time");
    623    return static_cast<double>(aTime) / GraphRate();
    624  }
    625 
    626  /**
    627   * Signal to the graph that the thread has paused indefinitly,
    628   * or resumed.
    629   */
    630  void PausedIndefinitly();
    631  void ResumedFromPaused();
    632 
    633  /**
    634   * Not safe to call off the MediaTrackGraph thread unless monitor is held!
    635   */
    636  GraphDriver* CurrentDriver() const MOZ_NO_THREAD_SAFETY_ANALYSIS {
    637 #ifdef DEBUG
    638    if (!OnGraphThreadOrNotRunning()) {
    639      mMonitor.AssertCurrentThreadOwns();
    640    }
    641 #endif
    642    return mDriver;
    643  }
    644 
    645  /**
    646   * Effectively set the new driver, while we are switching.
    647   * It is only safe to call this at the very end of an iteration, when there
    648   * has been a SwitchAtNextIteration call during the iteration. The driver
    649   * should return and pass the control to the new driver shortly after.
    650   * Monitor must be held.
    651   */
    652  void SetCurrentDriver(GraphDriver* aDriver) {
    653    MOZ_ASSERT_IF(mGraphDriverRunning, InDriverIteration(mDriver));
    654    MOZ_ASSERT_IF(!mGraphDriverRunning, NS_IsMainThread());
    655    MonitorAutoLock lock(GetMonitor());
    656    mDriver = aDriver;
    657  }
    658 
    659  GraphDriver* NextDriver() const {
    660    MOZ_ASSERT(OnGraphThread());
    661    return mNextDriver;
    662  }
    663 
    664  bool Switching() const { return NextDriver(); }
    665 
    666  void SwitchAtNextIteration(GraphDriver* aNextDriver);
    667 
    668  Monitor& GetMonitor() { return mMonitor; }
    669 
    670  void EnsureNextIteration() { CurrentDriver()->EnsureNextIteration(); }
    671 
    672  // Capture API. This allows to get a mixed-down output for a window.
    673  void RegisterCaptureTrackForWindow(uint64_t aWindowId,
    674                                     ProcessedMediaTrack* aCaptureTrack);
    675  void UnregisterCaptureTrackForWindow(uint64_t aWindowId);
    676  already_AddRefed<MediaInputPort> ConnectToCaptureTrack(
    677      uint64_t aWindowId, MediaTrack* aMediaTrack);
    678 
    679  Watchable<GraphTime>& CurrentTime() override;
    680 
    681  /**
    682   * Interrupt any JS running on the graph thread.
    683   * Called on the main thread when shutting down the graph.
    684   */
    685  void InterruptJS();
    686 
    687  class TrackSet {
    688   public:
    689    class iterator {
    690     public:
    691      explicit iterator(MediaTrackGraphImpl& aGraph)
    692          : mGraph(&aGraph), mArrayNum(-1), mArrayIndex(0) {
    693        ++(*this);
    694      }
    695      iterator() : mGraph(nullptr), mArrayNum(2), mArrayIndex(0) {}
    696      MediaTrack* operator*() { return Array()->ElementAt(mArrayIndex); }
    697      iterator operator++() {
    698        ++mArrayIndex;
    699        while (mArrayNum < 2 &&
    700               (mArrayNum < 0 || mArrayIndex >= Array()->Length())) {
    701          ++mArrayNum;
    702          mArrayIndex = 0;
    703        }
    704        return *this;
    705      }
    706      bool operator==(const iterator& aOther) const {
    707        return mArrayNum == aOther.mArrayNum &&
    708               mArrayIndex == aOther.mArrayIndex;
    709      }
    710      bool operator!=(const iterator& aOther) const {
    711        return !(*this == aOther);
    712      }
    713 
    714     private:
    715      nsTArray<MediaTrack*>* Array() {
    716        return mArrayNum == 0 ? &mGraph->mTracks : &mGraph->mSuspendedTracks;
    717      }
    718      MediaTrackGraphImpl* mGraph;
    719      int mArrayNum;
    720      uint32_t mArrayIndex;
    721    };
    722 
    723    explicit TrackSet(MediaTrackGraphImpl& aGraph) : mGraph(aGraph) {}
    724    iterator begin() { return iterator(mGraph); }
    725    iterator end() { return iterator(); }
    726 
    727   private:
    728    MediaTrackGraphImpl& mGraph;
    729  };
    730  TrackSet AllTracks() { return TrackSet(*this); }
    731 
    732  // Data members
    733 
    734  /**
    735   * The ID of the inner Window which uses this graph, or zero for offline
    736   * graphs.
    737   */
    738  const uint64_t mWindowID;
    739  /*
    740   * If set, the GraphRunner class handles handing over data from audio
    741   * callbacks to a common single thread, shared across GraphDrivers.
    742   */
    743  RefPtr<GraphRunner> mGraphRunner;
    744 
    745  /**
    746   * Main-thread view of the number of tracks in this graph, for lifetime
    747   * management.
    748   *
    749   * When this becomes zero, the graph is marked as forbidden to add more
    750   * tracks to. It will be shut down shortly after.
    751   */
    752  size_t mMainThreadTrackCount = 0;
    753 
    754  /**
    755   * Main-thread view of the number of ports in this graph, to catch bugs.
    756   *
    757   * When this becomes zero, and mMainThreadTrackCount is 0, the graph is
    758   * marked as forbidden to add more control messages to. It will be shut down
    759   * shortly after.
    760   */
    761  size_t mMainThreadPortCount = 0;
    762 
    763  /**
    764   * Graphs own owning references to their driver, until shutdown. When a driver
    765   * switch occur, previous driver is either deleted, or it's ownership is
    766   * passed to a event that will take care of the asynchronous cleanup, as
    767   * audio track can take some time to shut down.
    768   * Accessed on both the main thread and the graph thread; both read and write.
    769   * Must hold monitor to access it.
    770   */
    771  RefPtr<GraphDriver> mDriver;
    772 
    773  // Set during an iteration to switch driver after the iteration has finished.
    774  // Should the current iteration be the last iteration, the next driver will be
    775  // discarded. Access through SwitchAtNextIteration()/NextDriver(). Graph
    776  // thread only.
    777  RefPtr<GraphDriver> mNextDriver;
    778 
    779  // The following state is managed on the graph thread only, unless
    780  // mLifecycleState > LIFECYCLE_RUNNING in which case the graph thread
    781  // is not running and this state can be used from the main thread.
    782 
    783  /**
    784   * The graph keeps a reference to each track.
    785   * References are maintained manually to simplify reordering without
    786   * unnecessary thread-safe refcount changes.
    787   * Must satisfy OnGraphThreadOrNotRunning().
    788   */
    789  nsTArray<MediaTrack*> mTracks;
    790  /**
    791   * This stores MediaTracks that are part of suspended AudioContexts.
    792   * mTracks and mSuspendTracks are disjoint sets: a track is either suspended
    793   * or not suspended. Suspended tracks are not ordered in UpdateTrackOrder,
    794   * and are therefore not doing any processing.
    795   * Must satisfy OnGraphThreadOrNotRunning().
    796   */
    797  nsTArray<MediaTrack*> mSuspendedTracks;
    798  /**
    799   * Tracks from mFirstCycleBreaker to the end of mTracks produce output before
    800   * they receive input.  They correspond to DelayNodes that are in cycles.
    801   */
    802  uint32_t mFirstCycleBreaker;
    803  /**
    804   * Blocking decisions have been computed up to this time.
    805   * Between each iteration, this is the same as mProcessedTime.
    806   */
    807  GraphTime mStateComputedTime = 0;
    808  /**
    809   * All track contents have been computed up to this time.
    810   * The next batch of updates from the main thread will be processed
    811   * at this time.  This is behind mStateComputedTime during processing.
    812   */
    813  GraphTime mProcessedTime = 0;
    814  /**
    815   * The graph should stop processing at this time.
    816   */
    817  GraphTime mEndTime;
    818  /**
    819   * Date of the last time we updated the main thread with the graph state.
    820   */
    821  TimeStamp mLastMainThreadUpdate;
    822  /**
    823   * Number of active MediaInputPorts
    824   */
    825  int32_t mPortCount;
    826  /**
    827   * Runnables to run after the next update to main thread state, but that are
    828   * still waiting for the next iteration to finish.
    829   */
    830  nsTArray<nsCOMPtr<nsIRunnable>> mPendingUpdateRunnables;
    831 
    832  /**
    833   * List of resume operations waiting for a switch to an AudioCallbackDriver.
    834   */
    835  class PendingResumeOperation {
    836   public:
    837    explicit PendingResumeOperation(
    838        AudioContextOperationControlMessage* aMessage);
    839    void Apply(MediaTrackGraphImpl* aGraph);
    840    void Abort();
    841    MediaTrack* DestinationTrack() const { return mDestinationTrack; }
    842 
    843   private:
    844    RefPtr<MediaTrack> mDestinationTrack;
    845    nsTArray<RefPtr<MediaTrack>> mTracks;
    846    MozPromiseHolder<AudioContextOperationPromise> mHolder;
    847  };
    848  AutoTArray<PendingResumeOperation, 1> mPendingResumeOperations;
    849 
    850  // mMonitor guards the data below.
    851  // MediaTrackGraph normally does its work without holding mMonitor, so it is
    852  // not safe to just grab mMonitor from some thread and start monkeying with
    853  // the graph. Instead, communicate with the graph thread using provided
    854  // mechanisms such as the control message queue.
    855  Monitor mMonitor;
    856 
    857  // Data guarded by mMonitor (must always be accessed with mMonitor held,
    858  // regardless of the value of mLifecycleState).
    859 
    860  /**
    861   * State to copy to main thread
    862   */
    863  nsTArray<TrackUpdate> mTrackUpdates MOZ_GUARDED_BY(mMonitor);
    864  /**
    865   * Runnables to run after the next update to main thread state.
    866   */
    867  nsTArray<nsCOMPtr<nsIRunnable>> mUpdateRunnables MOZ_GUARDED_BY(mMonitor);
    868  /**
    869   * A list of batches of messages to process. Each batch is processed
    870   * as an atomic unit.
    871   */
    872  /*
    873   * Message queue processed by the MTG thread during an iteration.
    874   * Accessed on graph thread only.
    875   */
    876  nsTArray<MessageBlock> mFrontMessageQueue;
    877  /*
    878   * Message queue in which the main thread appends messages.
    879   * Access guarded by mMonitor.
    880   */
    881  nsTArray<MessageBlock> mBackMessageQueue MOZ_GUARDED_BY(mMonitor);
    882 
    883  /* True if there will messages to process if we swap the message queues. */
    884  bool MessagesQueued() const MOZ_REQUIRES(mMonitor) {
    885    mMonitor.AssertCurrentThreadOwns();
    886    return !mBackMessageQueue.IsEmpty();
    887  }
    888  /**
    889   * This enum specifies where this graph is in its lifecycle. This is used
    890   * to control shutdown.
    891   * Shutdown is tricky because it can happen in two different ways:
    892   * 1) Shutdown due to inactivity. RunThread() detects that it has no
    893   * pending messages and no tracks, and exits. The next RunInStableState()
    894   * checks if there are new pending messages from the main thread (true only
    895   * if new track creation raced with shutdown); if there are, it revives
    896   * RunThread(), otherwise it commits to shutting down the graph. New track
    897   * creation after this point will create a new graph. An async event is
    898   * dispatched to Shutdown() the graph's threads and then delete the graph
    899   * object.
    900   * 2) Forced shutdown at application shutdown, completion of a non-realtime
    901   * graph, or document unload. A flag is set, RunThread() detects the flag
    902   * and exits, the next RunInStableState() detects the flag, and dispatches
    903   * the async event to Shutdown() the graph's threads. However the graph
    904   * object is not deleted. New messages for the graph are processed
    905   * synchronously on the main thread if necessary. When the last track is
    906   * destroyed, the graph object is deleted.
    907   *
    908   * This should be kept in sync with the LifecycleState_str array in
    909   * MediaTrackGraph.cpp
    910   */
    911  enum LifecycleState {
    912    // The graph thread hasn't started yet.
    913    LIFECYCLE_THREAD_NOT_STARTED,
    914    // RunThread() is running normally.
    915    LIFECYCLE_RUNNING,
    916    // In the following states, the graph thread is not running so
    917    // all "graph thread only" state in this class can be used safely
    918    // on the main thread.
    919    // RunThread() has exited and we're waiting for the next
    920    // RunInStableState(), at which point we can clean up the main-thread
    921    // side of the graph.
    922    LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP,
    923    // RunInStableState() posted a ShutdownRunnable, and we're waiting for it
    924    // to shut down the graph thread(s).
    925    LIFECYCLE_WAITING_FOR_THREAD_SHUTDOWN,
    926    // Graph threads have shut down but we're waiting for remaining tracks
    927    // to be destroyed. Only happens during application shutdown and on
    928    // completed non-realtime graphs, since normally we'd only shut down a
    929    // realtime graph when it has no tracks.
    930    LIFECYCLE_WAITING_FOR_TRACK_DESTRUCTION
    931  };
    932 
    933  /**
    934   * Modified only in mMonitor.  Transitions to
    935   * LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP occur on the graph thread at
    936   * the end of an iteration.  All other transitions occur on the main thread.
    937   */
    938  LifecycleState mLifecycleState MOZ_GUARDED_BY(mMonitor);
    939  LifecycleState& LifecycleStateRef() MOZ_NO_THREAD_SAFETY_ANALYSIS {
    940 #if DEBUG
    941    if (mGraphDriverRunning) {
    942      mMonitor.AssertCurrentThreadOwns();
    943    } else {
    944      MOZ_ASSERT(NS_IsMainThread());
    945    }
    946 #endif
    947    return mLifecycleState;
    948  }
    949  const LifecycleState& LifecycleStateRef() const
    950      MOZ_NO_THREAD_SAFETY_ANALYSIS {
    951 #if DEBUG
    952    if (mGraphDriverRunning) {
    953      mMonitor.AssertCurrentThreadOwns();
    954    } else {
    955      MOZ_ASSERT(NS_IsMainThread());
    956    }
    957 #endif
    958    return mLifecycleState;
    959  }
    960 
    961  /**
    962   * True once the graph thread has received the message from ForceShutDown().
    963   * This is checked in the decision to shut down the
    964   * graph thread so that control messages dispatched before forced shutdown
    965   * are processed on the graph thread.
    966   * Only set on the graph thread.
    967   * Can be read safely on the thread currently owning the graph, as indicated
    968   * by mLifecycleState.
    969   */
    970  bool mForceShutDownReceived = false;
    971  /**
    972   * true when InterruptJS() has been called, because shutdown (normal or
    973   * forced) has commenced.  Set on the main thread under mMonitor and read on
    974   * the graph thread under mMonitor.
    975   **/
    976  bool mInterruptJSCalled MOZ_GUARDED_BY(mMonitor) = false;
    977 
    978  /**
    979   * Remove this blocker to unblock shutdown.
    980   * Only accessed on the main thread.
    981   **/
    982  RefPtr<media::ShutdownBlocker> mShutdownBlocker;
    983 
    984  /**
    985   * True when we have posted an event to the main thread to run
    986   * RunInStableState() and the event hasn't run yet.
    987   * Accessed on both main and MTG thread, mMonitor must be held.
    988   */
    989  bool mPostedRunInStableStateEvent MOZ_GUARDED_BY(mMonitor);
    990 
    991  /**
    992   * The JSContext of the graph thread.  Set under mMonitor on only the graph
    993   * or GraphRunner thread.  Once set this does not change until reset when
    994   * the thread is about to exit.  Read under mMonitor on the main thread to
    995   * interrupt running JS for forced shutdown.
    996   **/
    997  JSContext* mJSContext MOZ_GUARDED_BY(mMonitor) = nullptr;
    998 
    999  // Main thread only
   1000 
   1001  /**
   1002   * Messages posted by the current event loop task. These are forwarded to
   1003   * the media graph thread during RunInStableState. We can't forward them
   1004   * immediately because we want all messages between stable states to be
   1005   * processed as an atomic batch.
   1006   */
   1007  nsTArray<UniquePtr<ControlMessageInterface>> mCurrentTaskMessageQueue;
   1008  /**
   1009   * True from when RunInStableState sets mLifecycleState to LIFECYCLE_RUNNING,
   1010   * until RunInStableState has determined that mLifecycleState is >
   1011   * LIFECYCLE_RUNNING.
   1012   */
   1013  Atomic<bool> mGraphDriverRunning;
   1014  /**
   1015   * True when a stable state runner has been posted to the appshell to run
   1016   * RunInStableState at the next stable state.
   1017   * Only accessed on the main thread.
   1018   */
   1019  bool mPostedRunInStableState;
   1020  /**
   1021   * True when processing real-time audio/video.  False when processing
   1022   * non-realtime audio.
   1023   */
   1024  bool mRealtime;
   1025  /**
   1026   * True when a change has happened which requires us to recompute the track
   1027   * blocking order.
   1028   */
   1029  bool mTrackOrderDirty;
   1030  const RefPtr<nsISerialEventTarget> mMainThread;
   1031 
   1032  // used to limit graph shutdown time
   1033  // Only accessed on the main thread.
   1034  nsCOMPtr<nsITimer> mShutdownTimer;
   1035 
   1036 protected:
   1037  virtual ~MediaTrackGraphImpl();
   1038 
   1039  MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
   1040 
   1041  // Set a new native iput device when the current native input device is close.
   1042  // Main thread only.
   1043  void SetNewNativeInput();
   1044 
   1045  /**
   1046   * This class uses manual memory management, and all pointers to it are raw
   1047   * pointers. However, in order for it to implement nsIMemoryReporter, it needs
   1048   * to implement nsISupports and so be ref-counted. So it maintains a single
   1049   * nsRefPtr to itself, giving it a ref-count of 1 during its entire lifetime,
   1050   * and Destroy() nulls this self-reference in order to trigger self-deletion.
   1051   */
   1052  RefPtr<MediaTrackGraphImpl> mSelfRef;
   1053 
   1054  struct WindowAndTrack {
   1055    uint64_t mWindowId;
   1056    RefPtr<ProcessedMediaTrack> mCaptureTrackSink;
   1057  };
   1058  /**
   1059   * Track for window audio capture.
   1060   */
   1061  nsTArray<WindowAndTrack> mWindowCaptureTracks;
   1062 
   1063  /**
   1064   * Main thread unordered record of audio outputs, keyed by Track and output
   1065   * key.  Used to determine when an output device is no longer in use and to
   1066   * record the volumes corresponding to each key.  An array is used as a
   1067   * simple hash table, on the assumption that the number of outputs is small.
   1068   */
   1069  struct TrackAndKey {
   1070    MOZ_UNSAFE_REF("struct exists only if track exists") MediaTrack* mTrack;
   1071    void* mKey;
   1072  };
   1073  struct TrackKeyDeviceAndVolume {
   1074    MOZ_UNSAFE_REF("struct exists only if track exists")
   1075    MediaTrack* const mTrack;
   1076    void* const mKey;
   1077    const CubebUtils::AudioDeviceID mDeviceID;
   1078    float mVolume;
   1079 
   1080    bool operator==(const TrackAndKey& aTrackAndKey) const {
   1081      return mTrack == aTrackAndKey.mTrack && mKey == aTrackAndKey.mKey;
   1082    }
   1083  };
   1084  nsTArray<TrackKeyDeviceAndVolume> mAudioOutputParams;
   1085  /**
   1086   * Main thread record of which audio output devices are active, keyed by
   1087   * AudioDeviceID, and their CrossGraphReceivers if any.
   1088   * mOutputDeviceRefCnts[0] always exists and corresponds to the primary
   1089   * audio output device, which an AudioCallbackDriver will use if active.
   1090   * mCount may be zero for the first entry only.  */
   1091  struct DeviceReceiverAndCount {
   1092    const CubebUtils::AudioDeviceID mDeviceID;
   1093    // For secondary devices, mReceiver receives audio output.
   1094    // Null for the primary output device, fed by an AudioCallbackDriver.
   1095    const RefPtr<CrossGraphReceiver> mReceiver;
   1096    size_t mRefCnt;  // number of mAudioOutputParams entries with this device
   1097 
   1098    bool operator==(CubebUtils::AudioDeviceID aDeviceID) const {
   1099      return mDeviceID == aDeviceID;
   1100    }
   1101  };
   1102  nsTArray<DeviceReceiverAndCount> mOutputDeviceRefCnts;
   1103  /**
   1104   * Graph thread record of devices to which audio outputs are mixed, keyed by
   1105   * AudioDeviceID.  All tracks that have an audio output to each device are
   1106   * grouped for mixing their outputs to a single stream.
   1107   * mOutputDevices[0] always exists and corresponds to the primary audio
   1108   * output device, which an AudioCallbackDriver will use if active.
   1109   * An AudioCallbackDriver may be active when no audio outputs have audio
   1110   * outputs.
   1111   */
   1112  struct TrackAndVolume {
   1113    MOZ_UNSAFE_REF("struct exists only if track exists")
   1114    MediaTrack* const mTrack;
   1115    float mVolume;
   1116 
   1117    bool operator==(const MediaTrack* aTrack) const { return mTrack == aTrack; }
   1118  };
   1119  struct OutputDeviceEntry {
   1120    const CubebUtils::AudioDeviceID mDeviceID;
   1121    // For secondary devices, mReceiver receives audio output.
   1122    // Null for the primary output device, fed by an AudioCallbackDriver.
   1123    const RefPtr<CrossGraphReceiver> mReceiver;
   1124    /**
   1125     * Mapping from MediaTrack to volume for all tracks that have their audio
   1126     * output mixed and written to this output device.
   1127     */
   1128    nsTArray<TrackAndVolume> mTrackOutputs;
   1129 
   1130    bool operator==(CubebUtils::AudioDeviceID aDeviceID) const {
   1131      return mDeviceID == aDeviceID;
   1132    }
   1133  };
   1134  nsTArray<OutputDeviceEntry> mOutputDevices;
   1135  /**
   1136   * mOutputDeviceForAEC identifies the audio output to be passed as the
   1137   * reverse stream for audio echo cancellation.  Used only if a microphone is
   1138   * active.  Graph thread.
   1139   */
   1140  CubebUtils::AudioDeviceID mOutputDeviceForAEC = nullptr;
   1141 
   1142  /**
   1143   * Global volume scale. Used when running tests so that the output is not too
   1144   * loud.
   1145   */
   1146  const float mGlobalVolume;
   1147 
   1148 #ifdef DEBUG
   1149  /**
   1150   * Used to assert when AppendMessage() runs control messages synchronously.
   1151   */
   1152  bool mCanRunMessagesSynchronously;
   1153 #endif
   1154 
   1155  /**
   1156   * The graph's main-thread observable graph time.
   1157   * Updated by the stable state runnable after each iteration.
   1158   */
   1159  Watchable<GraphTime> mMainThreadGraphTime;
   1160 
   1161  /**
   1162   * Set based on mProcessedTime at end of iteration.
   1163   * Read by stable state runnable on main thread. Protected by mMonitor.
   1164   */
   1165  GraphTime mNextMainThreadGraphTime MOZ_GUARDED_BY(mMonitor) = 0;
   1166 
   1167  /**
   1168   * Cached audio output latency, in seconds. Main thread only. This is reset
   1169   * whenever the audio device running this MediaTrackGraph changes.
   1170   */
   1171  double mAudioOutputLatency;
   1172 
   1173  /**
   1174   * The max audio output channel count the default audio output device
   1175   * supports. This is cached here because it can be expensive to query. The
   1176   * cache is invalidated when the device is changed. This is initialized in the
   1177   * ctor, and the read/write only on the graph thread.
   1178   */
   1179  uint32_t mMaxOutputChannelCount;
   1180 
   1181 public:
   1182  /**
   1183   * Manage the native or non-native input device in graph. Main thread only.
   1184   */
   1185  DeviceInputTrackManager mDeviceInputTrackManagerMainThread;
   1186 
   1187  /**
   1188   * An enumerator for tracking the system default output device. Set only while
   1189   * an input track is present in the graph, as the system default output device
   1190   * is used for AEC decisions. Main thread only.
   1191   */
   1192  RefPtr<CubebDeviceEnumerator> mEnumeratorMainThread;
   1193 
   1194 protected:
   1195  /**
   1196   * Manage the native or non-native input device in graph. Graph thread only.
   1197   */
   1198  DeviceInputTrackManager mDeviceInputTrackManagerGraphThread;
   1199  MediaEventListener mOutputDevicesChangedListener;
   1200  /**
   1201   * The system's current default device. When PrimaryOutputDeviceID() is
   1202   * nullptr, this is what it maps to. There will be a delay between a user
   1203   * changing their default device, to this device ID being up to date.
   1204   */
   1205  std::atomic<CubebUtils::AudioDeviceID> mDefaultOutputDeviceID = {nullptr};
   1206  /**
   1207   * The mixer that the graph mixes into during an iteration. This is here
   1208   * rather than on the stack so that its buffer is not allocated each
   1209   * iteration. Graph thread only.
   1210   */
   1211  AudioMixer mMixer;
   1212 };
   1213 
   1214 }  // namespace mozilla
   1215 
   1216 #endif /* MEDIATRACKGRAPHIMPL_H_ */