tor-browser

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

GraphDriver.h (35244B)


      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 GRAPHDRIVER_H_
      7 #define GRAPHDRIVER_H_
      8 
      9 #include <thread>
     10 
     11 #include "AudioBufferUtils.h"
     12 #include "AudioMixer.h"
     13 #include "AudioSegment.h"
     14 #include "SelfRef.h"
     15 #include "WavDumper.h"
     16 #include "mozilla/Atomics.h"
     17 #include "mozilla/DataMutex.h"
     18 #include "mozilla/StaticPtr.h"
     19 #include "mozilla/TaskQueue.h"
     20 #include "mozilla/dom/AudioContext.h"
     21 #include "nsAutoRef.h"
     22 #include "nsIThread.h"
     23 
     24 struct cubeb_stream;
     25 
     26 template <>
     27 class nsAutoRefTraits<cubeb_stream> : public nsPointerRefTraits<cubeb_stream> {
     28 public:
     29  static void Release(cubeb_stream* aStream) { cubeb_stream_destroy(aStream); }
     30 };
     31 
     32 namespace mozilla {
     33 /**
     34 * Assume we can run an iteration of the MediaTrackGraph loop in this much time
     35 * or less.
     36 * We try to run the control loop at this rate.
     37 */
     38 static const int MEDIA_GRAPH_TARGET_PERIOD_MS = 10;
     39 /**
     40 * The SystemClockDriver does not necessarily wake up as precisely as an
     41 * AudioCallbackDriver.  SleepConditionVariableSRW() has been observed to wake
     42 * almost 30ms late on Windows 10 2009 systems, which implies a lower timer
     43 * resolution than the 15.6ms default system-wide timer resolution in Windows.
     44 * https://download.microsoft.com/download/3/0/2/3027d574-c433-412a-a8b6-5e0a75d5b237/timer-resolution.docx
     45 *
     46 * Allow a SystemClockDriver to try to catch up when rendering is up to this
     47 * many milliseconds late, so that rendered time is close to clock time.  When
     48 * later than this threshold, SystemClockDriver will declare bankruptcy and
     49 * re-sync target render time with a new clock time.
     50 */
     51 static const int SYSTEM_CLOCK_BANKRUPTCY_THRESHOLD_MS = 30;
     52 /**
     53 * After starting a fallback driver, wait this long before attempting to re-init
     54 * the audio stream the first time.
     55 */
     56 static const int AUDIO_INITIAL_FALLBACK_BACKOFF_STEP_MS = 10;
     57 
     58 /**
     59 * The backoff step duration for when to next attempt to re-init the audio
     60 * stream is capped at this value.
     61 */
     62 static const int AUDIO_MAX_FALLBACK_BACKOFF_STEP_MS = 1000;
     63 
     64 class AudioCallbackDriver;
     65 class GraphDriver;
     66 class MediaTrack;
     67 class OfflineClockDriver;
     68 class SystemClockDriver;
     69 
     70 namespace dom {
     71 enum class AudioContextOperation : uint8_t;
     72 }
     73 
     74 struct GraphInterface : public nsISupports {
     75  /**
     76   * Object returned from OneIteration() instructing the iterating GraphDriver
     77   * what to do.
     78   *
     79   * - If the result is StillProcessing: keep the iterations coming.
     80   * - If the result is Stop: the driver potentially updates its internal state
     81   *   and interacts with the graph (e.g., NotifyOutputData), then it must call
     82   *   Stopped() exactly once.
     83   * - If the result is SwitchDriver: the driver updates internal state as for
     84   *   the Stop result, then it must call Switched() exactly once and start
     85   *   NextDriver().
     86   */
     87  class IterationResult final {
     88    struct Undefined {};
     89    struct StillProcessing {};
     90    struct Stop {
     91      explicit Stop(RefPtr<Runnable> aStoppedRunnable)
     92          : mStoppedRunnable(std::move(aStoppedRunnable)) {}
     93      Stop(const Stop&) = delete;
     94      Stop(Stop&& aOther) noexcept
     95          : mStoppedRunnable(std::move(aOther.mStoppedRunnable)) {}
     96      ~Stop() { MOZ_ASSERT(!mStoppedRunnable); }
     97      RefPtr<Runnable> mStoppedRunnable;
     98      void Stopped() {
     99        mStoppedRunnable->Run();
    100        mStoppedRunnable = nullptr;
    101      }
    102    };
    103    struct SwitchDriver {
    104      SwitchDriver(RefPtr<GraphDriver> aDriver,
    105                   RefPtr<Runnable> aSwitchedRunnable)
    106          : mDriver(std::move(aDriver)),
    107            mSwitchedRunnable(std::move(aSwitchedRunnable)) {}
    108      SwitchDriver(const SwitchDriver&) = delete;
    109      SwitchDriver(SwitchDriver&& aOther) noexcept
    110          : mDriver(std::move(aOther.mDriver)),
    111            mSwitchedRunnable(std::move(aOther.mSwitchedRunnable)) {}
    112      ~SwitchDriver() { MOZ_ASSERT(!mSwitchedRunnable); }
    113      RefPtr<GraphDriver> mDriver;
    114      RefPtr<Runnable> mSwitchedRunnable;
    115      void Switched() {
    116        mSwitchedRunnable->Run();
    117        mSwitchedRunnable = nullptr;
    118      }
    119    };
    120    Variant<Undefined, StillProcessing, Stop, SwitchDriver> mResult;
    121 
    122    explicit IterationResult(StillProcessing&& aArg)
    123        : mResult(std::move(aArg)) {}
    124    explicit IterationResult(Stop&& aArg) : mResult(std::move(aArg)) {}
    125    explicit IterationResult(SwitchDriver&& aArg) : mResult(std::move(aArg)) {}
    126 
    127   public:
    128    IterationResult() : mResult(Undefined()) {}
    129    IterationResult(const IterationResult&) = delete;
    130    IterationResult(IterationResult&&) = default;
    131 
    132    IterationResult& operator=(const IterationResult&) = delete;
    133    IterationResult& operator=(IterationResult&&) = default;
    134 
    135    static IterationResult CreateStillProcessing() {
    136      return IterationResult(StillProcessing());
    137    }
    138    static IterationResult CreateStop(RefPtr<Runnable> aStoppedRunnable) {
    139      return IterationResult(Stop(std::move(aStoppedRunnable)));
    140    }
    141    static IterationResult CreateSwitchDriver(
    142        RefPtr<GraphDriver> aDriver, RefPtr<Runnable> aSwitchedRunnable) {
    143      return IterationResult(
    144          SwitchDriver(std::move(aDriver), std::move(aSwitchedRunnable)));
    145    }
    146 
    147    bool IsStillProcessing() const { return mResult.is<StillProcessing>(); }
    148    bool IsStop() const { return mResult.is<Stop>(); }
    149    bool IsSwitchDriver() const { return mResult.is<SwitchDriver>(); }
    150 
    151    void Stopped() {
    152      MOZ_ASSERT(IsStop());
    153      mResult.as<Stop>().Stopped();
    154    }
    155 
    156    GraphDriver* NextDriver() const {
    157      if (!IsSwitchDriver()) {
    158        return nullptr;
    159      }
    160      return mResult.as<SwitchDriver>().mDriver;
    161    }
    162 
    163    void Switched() {
    164      MOZ_ASSERT(IsSwitchDriver());
    165      mResult.as<SwitchDriver>().Switched();
    166    }
    167  };
    168 
    169  /* Called on the graph thread after an AudioCallbackDriver with an input
    170   * stream has stopped. */
    171  virtual void NotifyInputStopped() = 0;
    172  /* Called on the graph thread when there is new input data for listeners. This
    173   * is the raw audio input for this MediaTrackGraph. */
    174  virtual void NotifyInputData(const AudioDataValue* aBuffer, size_t aFrames,
    175                               TrackRate aRate, uint32_t aChannels,
    176                               uint32_t aAlreadyBuffered) = 0;
    177  /* Called on the main thread after an AudioCallbackDriver has attempted an
    178   * operation to set the processing params matching aGeneration on the cubeb
    179   * stream. */
    180  virtual void NotifySetRequestedInputProcessingParamsResult(
    181      AudioCallbackDriver* aDriver, int aGeneration,
    182      Result<cubeb_input_processing_params, int>&& aResult) = 0;
    183  /* Called every time there are changes to input/output audio devices like
    184   * plug/unplug etc. This can be called on any thread, and posts a message to
    185   * the main thread so that it can post a message to the graph thread. */
    186  virtual void DeviceChanged() = 0;
    187  /* Called by GraphDriver to iterate the graph. Mixed audio output from the
    188   * graph is passed into aMixerReceiver, if it is non-null. */
    189  virtual IterationResult OneIteration(
    190      GraphTime aStateComputedEnd, MixerCallbackReceiver* aMixerReceiver) = 0;
    191 #ifdef DEBUG
    192  /* True if we're on aDriver's thread, or if we're on mGraphRunner's thread
    193   * and mGraphRunner is currently run by aDriver. */
    194  virtual bool InDriverIteration(const GraphDriver* aDriver) const = 0;
    195 #endif
    196 };
    197 
    198 /**
    199 * A driver is responsible for the scheduling of the processing, the thread
    200 * management, and give the different clocks to a MediaTrackGraph. This is an
    201 * abstract base class. A MediaTrackGraph can be driven by an
    202 * OfflineClockDriver, if the graph is offline, or a SystemClockDriver or an
    203 * AudioCallbackDriver, if the graph is real time.
    204 * A MediaTrackGraph holds an owning reference to its driver.
    205 *
    206 * The lifetime of drivers is a complicated affair. Here are the different
    207 * scenarii that can happen:
    208 *
    209 * Starting a MediaTrackGraph with an AudioCallbackDriver
    210 * - A new thread T is created, from the main thread.
    211 * - On this thread T, cubeb is initialized if needed, and a cubeb_stream is
    212 *   created and started
    213 * - The thread T posts a message to the main thread to terminate itself.
    214 * - The graph runs off the audio thread
    215 *
    216 * Starting a MediaTrackGraph with a SystemClockDriver:
    217 * - A new thread T is created from the main thread.
    218 * - The graph runs off this thread.
    219 *
    220 * Switching from a SystemClockDriver to an AudioCallbackDriver:
    221 * - At the end of the MTG iteration, the graph tells the current driver to
    222 *   switch to an AudioCallbackDriver, which is created and initialized on the
    223 *   graph thread.
    224 * - At the end of the MTG iteration, the SystemClockDriver transfers its timing
    225 *   info and a reference to itself to the AudioCallbackDriver. It then starts
    226 *   the AudioCallbackDriver.
    227 * - When the AudioCallbackDriver starts, it:
    228 *   - Starts a fallback SystemClockDriver that runs until the
    229 *     AudioCallbackDriver is running, in case it takes a long time to start (it
    230 *     could block on I/O, e.g., negotiating a bluetooth connection).
    231 *   - Checks if it has been switched from a SystemClockDriver, and if that is
    232 *     the case, sends a message to the main thread to shut the
    233 *     SystemClockDriver thread down.
    234 * - When the AudioCallbackDriver is running, data callbacks are blocked. The
    235 *   fallback driver detects this in its callback and stops itself. The first
    236 *   DataCallback after the fallback driver had stopped goes through.
    237 * - The graph now runs off an audio callback.
    238 *
    239 * Switching from an AudioCallbackDriver to a SystemClockDriver:
    240 * - At the end of the MTG iteration, the graph tells the current driver to
    241 *   switch to a SystemClockDriver.
    242 * - the AudioCallbackDriver transfers its timing info and a reference to itself
    243 *   to the SystemClockDriver. A new SystemClockDriver is started from the
    244 *   current audio thread.
    245 * - When starting, the SystemClockDriver checks if it has been switched from an
    246 *   AudioCallbackDriver. If yes, it creates a new temporary thread to release
    247 *   the cubeb_streams. This temporary thread closes the cubeb_stream, and then
    248 *   dispatches a message to the main thread to be terminated.
    249 * - The graph now runs off a normal thread.
    250 *
    251 * Two drivers cannot run at the same time for the same graph. The thread safety
    252 * of the different members of drivers, and their access pattern is documented
    253 * next to the members themselves.
    254 */
    255 class GraphDriver {
    256 public:
    257  using IterationResult = GraphInterface::IterationResult;
    258 
    259  GraphDriver(GraphInterface* aGraphInterface, GraphDriver* aPreviousDriver,
    260              uint32_t aSampleRate);
    261 
    262  NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
    263 
    264  /* Start the graph, init the driver, start the thread.
    265   * A driver cannot be started twice, it must be shutdown
    266   * before being started again. */
    267  virtual void Start() = 0;
    268  /* Shutdown GraphDriver */
    269  MOZ_CAN_RUN_SCRIPT virtual void Shutdown() = 0;
    270  /* Set the UTF-8 name for system audio streams.
    271   * Graph thread, or main thread if the graph is not running. */
    272  virtual void SetStreamName(const nsACString& aStreamName);
    273  /* Rate at which the GraphDriver runs, in ms. This can either be user
    274   * controlled (because we are using a {System,Offline}ClockDriver, and decide
    275   * how often we want to wakeup/how much we want to process per iteration), or
    276   * it can be indirectly set by the latency of the audio backend, and the
    277   * number of buffers of this audio backend: say we have four buffers, and 40ms
    278   * latency, we will get a callback approximately every 10ms. */
    279  virtual TimeDuration IterationDuration() = 0;
    280  /*
    281   * Signaled by the graph when it needs another iteration. Goes unhandled for
    282   * GraphDrivers that are not able to sleep indefinitely (i.e., all drivers but
    283   * ThreadedDriver). Can be called on any thread.
    284   */
    285  virtual void EnsureNextIteration() = 0;
    286 
    287  // Those are simply for accessing the associated pointer. Graph thread only,
    288  // or if one is not running, main thread.
    289  GraphDriver* PreviousDriver();
    290  void SetPreviousDriver(GraphDriver* aPreviousDriver);
    291 
    292  virtual AudioCallbackDriver* AsAudioCallbackDriver() { return nullptr; }
    293  virtual const AudioCallbackDriver* AsAudioCallbackDriver() const {
    294    return nullptr;
    295  }
    296 
    297  virtual OfflineClockDriver* AsOfflineClockDriver() { return nullptr; }
    298  virtual const OfflineClockDriver* AsOfflineClockDriver() const {
    299    return nullptr;
    300  }
    301 
    302  virtual SystemClockDriver* AsSystemClockDriver() { return nullptr; }
    303  virtual const SystemClockDriver* AsSystemClockDriver() const {
    304    return nullptr;
    305  }
    306 
    307  /**
    308   * Set the state of the driver so it can start at the right point in time,
    309   * after switching from another driver.
    310   *
    311   * aIterationTimeStamp is the system clock time from when rendering began in
    312   * the most recent iteration.  An audio callback is assumed invoked soon
    313   * after the end of the provided portion of the platform audio buffer
    314   * becomes available for reading or writing, and so provides a clock edge
    315   * such that aCurrentTimeStamp advances consistently with the output time of
    316   * the end of the set of frames rendered in each iteration.  Actual audio
    317   * output time of the last data written would be at least a platform buffer
    318   * length after a write buffer portion becomes available.
    319   */
    320  void SetState(const nsACString& aStreamName, GraphTime aStateComputedTime,
    321                TimeStamp aIterationTimeStamp);
    322 
    323  GraphInterface* Graph() const { return mGraphInterface; }
    324 
    325 #ifdef DEBUG
    326  // True if the current thread is currently iterating the MTG.
    327  bool InIteration() const;
    328 #endif
    329  // True if the current thread is the GraphDriver's thread.
    330  virtual bool OnThread() const = 0;
    331  // GraphDriver's thread has started and the thread is running.
    332  virtual bool ThreadRunning() const = 0;
    333 
    334  double MediaTimeToSeconds(MediaTime aTime) const {
    335    NS_ASSERTION(aTime > -TRACK_TIME_MAX && aTime <= TRACK_TIME_MAX,
    336                 "Bad time");
    337    return static_cast<double>(aTime) / mSampleRate;
    338  }
    339 
    340  TimeDuration MediaTimeToTimeDuration(MediaTime aTime) const {
    341    return TimeDuration::FromSeconds(MediaTimeToSeconds(aTime));
    342  }
    343 
    344  GraphTime SecondsToMediaTime(double aS) const {
    345    NS_ASSERTION(0 <= aS && aS <= TRACK_TICKS_MAX / TRACK_RATE_MAX,
    346                 "Bad seconds");
    347    return mSampleRate * aS;
    348  }
    349 
    350  GraphTime MillisecondsToMediaTime(int32_t aMS) const {
    351    return RateConvertTicksRoundDown(mSampleRate, 1000, aMS);
    352  }
    353 
    354 protected:
    355  // The UTF-8 name for system audio streams.  Graph thread.
    356  nsCString mStreamName;
    357  // Time until which the graph has processed data.
    358  GraphTime mStateComputedTime = 0;
    359  // The system clock time when the iteration should or would start if these
    360  // start times advance consistently with the number of frames rendered by
    361  // the graph in each iteration.
    362  // Initially null, if no previous driver exists to provide a reference time
    363  // through SetState().
    364  // SystemClockDriver advances this before waiting to render the next
    365  // iteration.
    366  // AudioCallbackDriver sets this to approximately now at the start of each
    367  // iteration when !HasFallback().
    368  // Unused by OfflineClockDriver.
    369  TimeStamp mTargetIterationTimeStamp;
    370  // The GraphInterface this driver is currently iterating.
    371  const RefPtr<GraphInterface> mGraphInterface;
    372  // The sample rate for the graph, and in case of an audio driver, also for the
    373  // cubeb stream.
    374  const uint32_t mSampleRate;
    375 
    376  // This is non-null only when this driver has recently switched from an other
    377  // driver, and has not cleaned it up yet (for example because the audio stream
    378  // is currently calling the callback during initialization).
    379  //
    380  // This is written to when changing driver, from the previous driver's thread,
    381  // or a thread created for the occasion. This is read each time we need to
    382  // check whether we're changing driver (in Switching()), from the graph
    383  // thread.
    384  // This must be accessed using the {Set,Get}PreviousDriver methods.
    385  RefPtr<GraphDriver> mPreviousDriver;
    386 
    387  virtual ~GraphDriver() = default;
    388 };
    389 
    390 class MediaTrackGraphInitThreadRunnable;
    391 
    392 /**
    393 * This class is a driver that manages its own thread.
    394 */
    395 class ThreadedDriver : public GraphDriver {
    396  class IterationWaitHelper {
    397    Monitor mMonitor MOZ_UNANNOTATED;
    398    // The below members are guarded by mMonitor.
    399 
    400    // Whether another iteration is required either to process control
    401    // messages or to render.
    402    // Drivers do not pass on this state when switching to another driver,
    403    // so always perform at least one iteration.
    404    bool mNeedAnotherIteration = true;
    405    TimeStamp mWakeTime;
    406 
    407   public:
    408    IterationWaitHelper() : mMonitor("IterationWaitHelper::mMonitor") {}
    409 
    410    /**
    411     * If another iteration is needed we wait for aDuration, otherwise we wait
    412     * for a wake-up. If a wake-up occurs before aDuration time has passed, we
    413     * wait for aDuration nonetheless.
    414     */
    415    void WaitForNextIterationAtLeast(TimeDuration aDuration) {
    416      MonitorAutoLock lock(mMonitor);
    417      TimeStamp now = TimeStamp::Now();
    418      mWakeTime = now + aDuration;
    419      while (true) {
    420        if (mNeedAnotherIteration && now >= mWakeTime) {
    421          break;
    422        }
    423        if (mNeedAnotherIteration) {
    424          lock.Wait(mWakeTime - now);
    425        } else {
    426          lock.Wait(TimeDuration::Forever());
    427        }
    428        now = TimeStamp::Now();
    429      }
    430      mWakeTime = TimeStamp();
    431      mNeedAnotherIteration = false;
    432    }
    433 
    434    /**
    435     * Sets mNeedAnotherIteration to true and notifies the monitor, in case a
    436     * driver is currently waiting.
    437     */
    438    void EnsureNextIteration() {
    439      MonitorAutoLock lock(mMonitor);
    440      mNeedAnotherIteration = true;
    441      lock.Notify();
    442    }
    443  };
    444 
    445 public:
    446  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ThreadedDriver, override);
    447 
    448  ThreadedDriver(GraphInterface* aGraphInterface, GraphDriver* aPreviousDriver,
    449                 uint32_t aSampleRate);
    450 
    451  void EnsureNextIteration() override;
    452  void Start() override;
    453  MOZ_CAN_RUN_SCRIPT void Shutdown() override;
    454  /**
    455   * Runs main control loop on the graph thread. Normally a single invocation
    456   * of this runs for the entire lifetime of the graph thread.
    457   */
    458  virtual void RunThread();
    459  friend class MediaTrackGraphInitThreadRunnable;
    460  TimeDuration IterationDuration() override;
    461 
    462  nsIThread* Thread() const { return mThread; }
    463 
    464  bool OnThread() const override {
    465    return !mThread || mThread->IsOnCurrentThread();
    466  }
    467 
    468  bool ThreadRunning() const override { return mThreadRunning; }
    469 
    470 protected:
    471  /* Waits until it's time to process more data. */
    472  void WaitForNextIteration();
    473  /* Return the implementation-dependent time that the ThreadedDriver should
    474   * wait for the next iteration.  Called only once per iteration;
    475   * SystemClockDriver advances it's target iteration time stamp.*/
    476  virtual TimeDuration NextIterationWaitDuration() = 0;
    477  /* When the graph wakes up to do an iteration, implementations return the
    478   * range of time that will be processed. */
    479  virtual MediaTime GetIntervalForIteration() = 0;
    480 
    481  virtual ~ThreadedDriver();
    482 
    483  nsCOMPtr<nsIThread> mThread;
    484 
    485 private:
    486  // This is true if the thread is running. It is false
    487  // before starting the thread and after stopping it.
    488  Atomic<bool> mThreadRunning;
    489 
    490  // Any thread.
    491  IterationWaitHelper mWaitHelper;
    492 };
    493 
    494 /**
    495 * A SystemClockDriver drives a GraphInterface using a system clock, and waits
    496 * using a monitor, between each iteration.
    497 */
    498 class SystemClockDriver final : public ThreadedDriver {
    499 public:
    500  SystemClockDriver(GraphInterface* aGraphInterface,
    501                    GraphDriver* aPreviousDriver, uint32_t aSampleRate);
    502  virtual ~SystemClockDriver();
    503  SystemClockDriver* AsSystemClockDriver() override { return this; }
    504  const SystemClockDriver* AsSystemClockDriver() const override { return this; }
    505  const TimeStamp& IterationTimeStamp() const {
    506    return mTargetIterationTimeStamp;
    507  }
    508 
    509 protected:
    510  /* Return the TimeDuration to wait before the next rendering iteration. */
    511  TimeDuration NextIterationWaitDuration() override;
    512  MediaTime GetIntervalForIteration() override;
    513 
    514 private:
    515  // Those are only modified (after initialization) on the graph thread. The
    516  // graph thread does not run during the initialization.
    517  TimeStamp mInitialTimeStamp;
    518 };
    519 
    520 /**
    521 * An OfflineClockDriver runs the graph as fast as possible, without waiting
    522 * between iteration.
    523 */
    524 class OfflineClockDriver final : public ThreadedDriver {
    525 public:
    526  OfflineClockDriver(GraphInterface* aGraphInterface, uint32_t aSampleRate);
    527  virtual ~OfflineClockDriver();
    528  OfflineClockDriver* AsOfflineClockDriver() override { return this; }
    529  const OfflineClockDriver* AsOfflineClockDriver() const override {
    530    return this;
    531  }
    532 
    533  void RunThread() override;
    534 
    535  void SetTickCountToRender(uint32_t aTicksToProcess) {
    536    MOZ_ASSERT(InIteration());
    537    MOZ_ASSERT(mEndTime == 0);
    538    mEndTime = aTicksToProcess;
    539  }
    540 
    541 protected:
    542  TimeDuration NextIterationWaitDuration() override { return TimeDuration(); }
    543  MediaTime GetIntervalForIteration() override;
    544 
    545 private:
    546  // The graph will advance up to this time.  Graph thread.
    547  GraphTime mEndTime = 0;
    548 };
    549 
    550 enum class AudioInputType { Unknown, Voice };
    551 
    552 struct AudioInputProcessingParamsRequest {
    553  int mGeneration{};
    554  cubeb_input_processing_params mParams{};
    555 };
    556 
    557 /**
    558 * This is a graph driver that is based on callback functions called by the
    559 * audio api. This ensures minimal audio latency, because it means there is no
    560 * buffering happening: the audio is generated inside the callback.
    561 *
    562 * This design is less flexible than running our own thread:
    563 * - We have no control over the thread:
    564 * - It cannot block, and it has to run for a shorter amount of time than the
    565 *   buffer it is going to fill, or an under-run is going to occur (short burst
    566 *   of silence in the final audio output).
    567 * - We can't know for sure when the callback function is going to be called
    568 *   (although we compute an estimation so we can schedule video frames)
    569 * - Creating and shutting the thread down is a blocking operation, that can
    570 *   take _seconds_ in some cases (because IPC has to be set up, and
    571 *   sometimes hardware components are involved and need to be warmed up)
    572 * - We have no control on how much audio we generate, we have to return exactly
    573 *   the number of frames asked for by the callback. Since for the Web Audio
    574 *   API, we have to do block processing at 128 frames per block, we need to
    575 *   keep a little spill buffer to store the extra frames.
    576 */
    577 class AudioCallbackDriver final : public GraphDriver,
    578                                  public MixerCallbackReceiver {
    579  using IterationResult = GraphInterface::IterationResult;
    580  enum class FallbackDriverState;
    581  class FallbackWrapper;
    582 
    583 public:
    584  NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DELETE_ON_EVENT_TARGET(
    585      AudioCallbackDriver, mCubebOperationThread, override);
    586 
    587  /** If aInputChannelCount is zero, then this driver is output-only. */
    588  AudioCallbackDriver(
    589      GraphInterface* aGraphInterface, GraphDriver* aPreviousDriver,
    590      uint32_t aSampleRate, uint32_t aOutputChannelCount,
    591      uint32_t aInputChannelCount, CubebUtils::AudioDeviceID aOutputDeviceID,
    592      CubebUtils::AudioDeviceID aInputDeviceID, AudioInputType aAudioInputType,
    593      Maybe<AudioInputProcessingParamsRequest> aRequestedInputProcessingParams);
    594 
    595  void Start() override;
    596  MOZ_CAN_RUN_SCRIPT void Shutdown() override;
    597  void SetStreamName(const nsACString& aStreamName) override;
    598 
    599  /* Static wrapper function cubeb calls back. */
    600  static long DataCallback_s(cubeb_stream* aStream, void* aUser,
    601                             const void* aInputBuffer, void* aOutputBuffer,
    602                             long aFrames);
    603  static void StateCallback_s(cubeb_stream* aStream, void* aUser,
    604                              cubeb_state aState);
    605  static void DeviceChangedCallback_s(void* aUser);
    606 
    607  /* This function is called by the underlying audio backend when a refill is
    608   * needed. This is what drives the whole graph when it is used to output
    609   * audio. If the return value is exactly aFrames, this function will get
    610   * called again. If it is less than aFrames, the stream will go in draining
    611   * mode, and this function will not be called again. */
    612  long DataCallback(const AudioDataValue* aInputBuffer,
    613                    AudioDataValue* aOutputBuffer, long aFrames);
    614  /* This function is called by the underlying audio backend, but is only used
    615   * for informational purposes at the moment. */
    616  void StateCallback(cubeb_state aState);
    617  /* This is an approximation of the number of millisecond there are between two
    618   * iterations of the graph. */
    619  TimeDuration IterationDuration() override;
    620  /* If the audio stream has started, this does nothing. There will be another
    621   * iteration. If there is an active fallback driver, we forward the call so it
    622   * can wake up. */
    623  void EnsureNextIteration() override;
    624 
    625  /* This function gets called when the graph has produced the audio frames for
    626   * this iteration. */
    627  void MixerCallback(AudioChunk* aMixedBuffer, uint32_t aSampleRate) override;
    628 
    629  AudioCallbackDriver* AsAudioCallbackDriver() override { return this; }
    630  const AudioCallbackDriver* AsAudioCallbackDriver() const override {
    631    return this;
    632  }
    633 
    634  uint32_t OutputChannelCount() const { return mOutputChannelCount; }
    635 
    636  uint32_t InputChannelCount() const { return mInputChannelCount; }
    637 
    638  CubebUtils::AudioDeviceID InputDeviceID() const { return mInputDeviceID; }
    639 
    640  AudioInputType InputDevicePreference() const {
    641    if (mInputDevicePreference == CUBEB_DEVICE_PREF_VOICE) {
    642      return AudioInputType::Voice;
    643    }
    644    return AudioInputType::Unknown;
    645  }
    646 
    647  /* Get the latest input processing params request from this driver, so
    648   * that an external caller can decide whether it is necessary to call the
    649   * setter, since it may allocate or dispatch. */
    650  const AudioInputProcessingParamsRequest& RequestedInputProcessingParams()
    651      const;
    652 
    653  /* Set the input processing params requested from this driver. */
    654  void RequestInputProcessingParams(AudioInputProcessingParamsRequest);
    655 
    656  std::thread::id ThreadId() const { return mAudioThreadIdInCb.load(); }
    657 
    658  /* Called at the beginning of the audio callback to check if the thread id has
    659   * changed. */
    660  bool CheckThreadIdChanged();
    661 
    662  bool OnThread() const override {
    663    return mAudioThreadIdInCb.load() == std::this_thread::get_id();
    664  }
    665 
    666  /* Returns true if this driver has started (perhaps with a fallback driver)
    667   * and not yet stopped. */
    668  bool ThreadRunning() const override {
    669    return mAudioStreamState == AudioStreamState::Running ||
    670           mFallbackDriverState == FallbackDriverState::Running;
    671  }
    672 
    673  /* Whether the underlying cubeb stream has been started and has not stopped
    674   * or errored. */
    675  bool IsStarted() { return mAudioStreamState > AudioStreamState::Starting; };
    676 
    677  // Returns the output latency for the current audio output stream.
    678  TimeDuration AudioOutputLatency();
    679 
    680  /* Returns true if this driver has a fallback driver and handover to the audio
    681   * callback has not been completed. */
    682  bool HasFallback() const;
    683  /* Returns true if this driver is currently driven by the fallback driver. */
    684  bool OnFallback() const;
    685 
    686 private:
    687  /**
    688   * On certain MacBookPro, the microphone is located near the left speaker.
    689   * We need to pan the sound output to the right speaker if we are using the
    690   * mic and the built-in speaker, or we will have terrible echo.  */
    691  void PanOutputIfNeeded(bool aMicrophoneActive);
    692  /**
    693   * This is called when the output device used by the cubeb stream changes. */
    694  void DeviceChangedCallback();
    695  /* Start the cubeb stream */
    696  bool StartStream();
    697  friend class MediaTrackGraphInitThreadRunnable;
    698  void Init(const nsCString& aStreamName);
    699  void SetCubebStreamName(const nsCString& aStreamName);
    700  void Stop();
    701  /* After the requested input processing params has changed, this applies them
    702   * on the cubeb stream. */
    703  void SetInputProcessingParams(AudioInputProcessingParamsRequest aRequest);
    704  /* Calls FallbackToSystemClockDriver() if in FallbackDriverState::None.
    705   * Returns Ok(true) if the fallback driver was started, or the old
    706   * FallbackDriverState in an Err otherwise. */
    707  Result<bool, FallbackDriverState> TryStartingFallbackDriver();
    708  /* Fall back to a SystemClockDriver using a normal thread. If needed, the
    709   * graph will try to re-open an audio stream later. */
    710  void FallbackToSystemClockDriver();
    711  /* Called by the fallback driver when it has fully stopped, after finishing
    712   * its last iteration. If it stopped after the audio stream started, aState
    713   * will be None. If it stopped after the graph told it to stop, or switch,
    714   * aState will be Stopped. Hands over state to the audio driver that may
    715   * iterate the graph after this has been called. */
    716  void FallbackDriverStopped(GraphTime aStateComputedTime,
    717                             TimeStamp aIterationTimeStamp,
    718                             FallbackDriverState aState);
    719 
    720  /* Called at the end of the fallback driver's iteration to see whether we
    721   * should attempt to start the AudioStream again. */
    722  void MaybeStartAudioStream();
    723 
    724  /* This is true when the method is executed on CubebOperation thread pool. */
    725  bool OnCubebOperationThread() {
    726    return mCubebOperationThread->IsOnCurrentThreadInfallible();
    727  }
    728 
    729  /* MediaTrackGraphs are always down/up mixed to output channels. */
    730  const uint32_t mOutputChannelCount;
    731  /* The size of this buffer comes from the fact that some audio backends can
    732   * call back with a number of frames lower than one block (128 frames), so we
    733   * need to keep at most two block in the SpillBuffer, because we always round
    734   * up to block boundaries during an iteration.
    735   * This is only ever accessed on the audio callback thread. */
    736  SpillBuffer<AudioDataValue, WEBAUDIO_BLOCK_SIZE * 2> mScratchBuffer;
    737  /* Wrapper to ensure we write exactly the number of frames we need in the
    738   * audio buffer cubeb passes us. This is only ever accessed on the audio
    739   * callback thread. */
    740  AudioCallbackBufferWrapper<AudioDataValue> mBuffer;
    741  // mAudioStream (a cubeb_stream) has a bare pointer to the cubeb context, so
    742  // we hold a strong reference on its behalf.
    743  RefPtr<CubebUtils::CubebHandle> mCubeb;
    744  /* cubeb stream for this graph. This is non-null after a successful
    745   * cubeb_stream_init(). CubebOperation thread only. */
    746  nsAutoRef<cubeb_stream> mAudioStream;
    747  /* The number of input channels from cubeb. Set before opening cubeb. If it is
    748   * zero then the driver is output-only. */
    749  const uint32_t mInputChannelCount;
    750  /**
    751   * Devices to use for cubeb input & output, or nullptr for default device.
    752   */
    753  const CubebUtils::AudioDeviceID mOutputDeviceID;
    754  const CubebUtils::AudioDeviceID mInputDeviceID;
    755  /* Whether the current or a future audio callback will be the first callback
    756   * to iterate the graph.  Used only from DataCallback().
    757   * Initialized on transition from AudioStreamState::Starting to Running. */
    758  MOZ_INIT_OUTSIDE_CTOR bool mFirstCallbackIteration;
    759  /* Approximation of the time between two callbacks. This is used to schedule
    760   * video frames. This is in milliseconds. Only even used (after
    761   * inizatialization) on the audio callback thread. */
    762  uint32_t mIterationDurationMS;
    763 
    764  struct AutoInCallback {
    765    explicit AutoInCallback(AudioCallbackDriver* aDriver);
    766    ~AutoInCallback();
    767    AudioCallbackDriver* mDriver;
    768  };
    769 
    770  static already_AddRefed<TaskQueue> CreateTaskQueue();
    771 
    772  /* Shared thread pool with up to one thread for off-main-thread
    773   * initialization and shutdown of the audio stream and for other tasks that
    774   * must run serially for access to mAudioStream. */
    775  const RefPtr<TaskQueue> mCubebOperationThread;
    776  cubeb_device_pref mInputDevicePreference;
    777  /* Params that have been attempted to set on mAudioStream, after filtering by
    778   * supported processing params. Cubeb operation thread only. */
    779  cubeb_input_processing_params mConfiguredInputProcessingParams =
    780      CUBEB_INPUT_PROCESSING_PARAM_NONE;
    781  /* The input processing params and generation requested from this audio
    782   * driver. Once started, audio callback thread only. */
    783  AudioInputProcessingParamsRequest mInputProcessingRequest;
    784  /* Contains the id of the audio thread, from profiler_current_thread_id. */
    785  std::atomic<ProfilerThreadId> mAudioThreadId;
    786  /* This allows implementing AutoInCallback. This is equal to the current
    787   * thread id when in an audio callback, and is an invalid thread id otherwise.
    788   */
    789  std::atomic<std::thread::id> mAudioThreadIdInCb;
    790  /* State of the audio stream, see inline comments. */
    791  enum class AudioStreamState {
    792    /* There is no cubeb_stream or mAudioStream is in CUBEB_STATE_ERROR or
    793     * CUBEB_STATE_STOPPED and no pending task exists to Init() a new
    794     * cubeb_stream. */
    795    None,
    796    /* A task to Init() a new cubeb_stream is pending. */
    797    Pending,
    798    /* cubeb_start_stream() is about to be or has been called on mAudioStream.
    799     * Any previous cubeb_streams have been destroyed. */
    800    Starting,
    801    /* mAudioStream has advertised it will change device. In this state we
    802       ignore all data callbacks until the fallback driver has started. */
    803    ChangingDevice,
    804    /* mAudioStream is running. */
    805    Running,
    806    /* mAudioStream is draining, and will soon stop. */
    807    Stopping
    808  };
    809  Atomic<AudioStreamState> mAudioStreamState{AudioStreamState::None};
    810  /* State of the fallback driver, see inline comments. */
    811  enum class FallbackDriverState {
    812    /* There is no fallback driver. */
    813    None,
    814    /* There is a fallback driver trying to iterate us. */
    815    Running,
    816    /* There was a fallback driver and the graph stopped it. No audio callback
    817       may iterate the graph. */
    818    Stopped,
    819  };
    820  Atomic<FallbackDriverState> mFallbackDriverState{FallbackDriverState::None};
    821  /* SystemClockDriver used as fallback if this AudioCallbackDriver fails to
    822   * init or start. */
    823  DataMutex<RefPtr<FallbackWrapper>> mFallback;
    824  /* If using a fallback driver, this is the duration to wait after failing to
    825   * start it before attempting to start it again. */
    826  TimeDuration mNextReInitBackoffStep;
    827  /* If using a fallback driver, this is the next time we'll try to start the
    828   * audio stream. */
    829  TimeStamp mNextReInitAttempt;
    830  /* The time mAudioStreamState was changed to ChangingDevice.
    831   * Synchronized by the mAudioStreamState atomic, i.e. written *before* writing
    832   * the atomic, and read *after* reading the atomic. */
    833  TimeStamp mChangingDeviceStartTime;
    834 #ifdef XP_MACOSX
    835  /* When using the built-in speakers on macbook pro (13 and 15, all models),
    836   * it's best to hard pan the audio on the right, to avoid feedback into the
    837   * microphone that is located next to the left speaker.  */
    838  Atomic<bool> mNeedsPanning;
    839 #endif
    840 
    841  WavDumper mInputStreamFile;
    842  WavDumper mOutputStreamFile;
    843 
    844  virtual ~AudioCallbackDriver();
    845  const bool mSandboxed = false;
    846 };
    847 
    848 }  // namespace mozilla
    849 
    850 #endif  // GRAPHDRIVER_H_