tor-browser

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

MockCubeb.h (28277B)


      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 #ifndef MOCKCUBEB_H_
      6 #define MOCKCUBEB_H_
      7 
      8 #include <atomic>
      9 #include <chrono>
     10 #include <thread>
     11 #include <utility>
     12 
     13 #include "AudioDeviceInfo.h"
     14 #include "AudioGenerator.h"
     15 #include "AudioVerifier.h"
     16 #include "MediaEventSource.h"
     17 #include "mozilla/DataMutex.h"
     18 #include "mozilla/MozPromise.h"
     19 #include "mozilla/Result.h"
     20 #include "mozilla/ResultVariant.h"
     21 #include "mozilla/ThreadSafeWeakPtr.h"
     22 #include "nsTArray.h"
     23 
     24 namespace mozilla {
     25 const uint32_t MAX_OUTPUT_CHANNELS = 2;
     26 const uint32_t MAX_INPUT_CHANNELS = 2;
     27 
     28 struct cubeb_ops {
     29  int (*init)(cubeb** context, char const* context_name);
     30  char const* (*get_backend_id)(cubeb* context);
     31  int (*get_max_channel_count)(cubeb* context, uint32_t* max_channels);
     32  int (*get_min_latency)(cubeb* context, cubeb_stream_params params,
     33                         uint32_t* latency_ms);
     34  int (*get_preferred_sample_rate)(cubeb* context, uint32_t* rate);
     35  int (*get_supported_input_processing_params)(
     36      cubeb* context, cubeb_input_processing_params* params);
     37  int (*enumerate_devices)(cubeb* context, cubeb_device_type type,
     38                           cubeb_device_collection* collection);
     39  int (*device_collection_destroy)(cubeb* context,
     40                                   cubeb_device_collection* collection);
     41  void (*destroy)(cubeb* context);
     42  int (*stream_init)(cubeb* context, cubeb_stream** stream,
     43                     char const* stream_name, cubeb_devid input_device,
     44                     cubeb_stream_params* input_stream_params,
     45                     cubeb_devid output_device,
     46                     cubeb_stream_params* output_stream_params,
     47                     unsigned int latency, cubeb_data_callback data_callback,
     48                     cubeb_state_callback state_callback, void* user_ptr);
     49  void (*stream_destroy)(cubeb_stream* stream);
     50  int (*stream_start)(cubeb_stream* stream);
     51  int (*stream_stop)(cubeb_stream* stream);
     52  int (*stream_get_position)(cubeb_stream* stream, uint64_t* position);
     53  int (*stream_get_latency)(cubeb_stream* stream, uint32_t* latency);
     54  int (*stream_get_input_latency)(cubeb_stream* stream, uint32_t* latency);
     55  int (*stream_set_volume)(cubeb_stream* stream, float volumes);
     56  int (*stream_set_name)(cubeb_stream* stream, char const* stream_name);
     57  int (*stream_get_current_device)(cubeb_stream* stream,
     58                                   cubeb_device** const device);
     59  int (*stream_set_input_mute)(cubeb_stream* stream, int mute);
     60  int (*stream_set_input_processing_params)(
     61      cubeb_stream* stream, cubeb_input_processing_params params);
     62  int (*stream_device_destroy)(cubeb_stream* stream, cubeb_device* device);
     63  int (*stream_register_device_changed_callback)(
     64      cubeb_stream* stream,
     65      cubeb_device_changed_callback device_changed_callback);
     66  int (*register_device_collection_changed)(
     67      cubeb* context, cubeb_device_type devtype,
     68      cubeb_device_collection_changed_callback callback, void* user_ptr);
     69 };
     70 
     71 // Keep those and the struct definition in sync with cubeb.h and
     72 // cubeb-internal.h
     73 void cubeb_mock_destroy(cubeb* context);
     74 static int cubeb_mock_get_supported_input_processing_params(
     75    cubeb* context, cubeb_input_processing_params* params);
     76 static int cubeb_mock_enumerate_devices(cubeb* context, cubeb_device_type type,
     77                                        cubeb_device_collection* out);
     78 
     79 static int cubeb_mock_device_collection_destroy(
     80    cubeb* context, cubeb_device_collection* collection);
     81 
     82 static int cubeb_mock_register_device_collection_changed(
     83    cubeb* context, cubeb_device_type devtype,
     84    cubeb_device_collection_changed_callback callback, void* user_ptr);
     85 
     86 static int cubeb_mock_stream_init(
     87    cubeb* context, cubeb_stream** stream, char const* stream_name,
     88    cubeb_devid input_device, cubeb_stream_params* input_stream_params,
     89    cubeb_devid output_device, cubeb_stream_params* output_stream_params,
     90    unsigned int latency, cubeb_data_callback data_callback,
     91    cubeb_state_callback state_callback, void* user_ptr);
     92 
     93 static int cubeb_mock_stream_start(cubeb_stream* stream);
     94 
     95 static int cubeb_mock_stream_stop(cubeb_stream* stream);
     96 
     97 static int cubeb_mock_stream_get_position(cubeb_stream* stream,
     98                                          uint64_t* position);
     99 
    100 static void cubeb_mock_stream_destroy(cubeb_stream* stream);
    101 
    102 static char const* cubeb_mock_get_backend_id(cubeb* context);
    103 
    104 static int cubeb_mock_stream_set_volume(cubeb_stream* stream, float volume);
    105 
    106 static int cubeb_mock_stream_set_name(cubeb_stream* stream,
    107                                      char const* stream_name);
    108 
    109 static int cubeb_mock_stream_set_input_processing_params(
    110    cubeb_stream* stream, cubeb_input_processing_params);
    111 
    112 static int cubeb_mock_stream_register_device_changed_callback(
    113    cubeb_stream* stream,
    114    cubeb_device_changed_callback device_changed_callback);
    115 
    116 static int cubeb_mock_get_min_latency(cubeb* context,
    117                                      cubeb_stream_params params,
    118                                      uint32_t* latency_ms);
    119 
    120 static int cubeb_mock_get_preferred_sample_rate(cubeb* context, uint32_t* rate);
    121 
    122 static int cubeb_mock_get_max_channel_count(cubeb* context,
    123                                            uint32_t* max_channels);
    124 
    125 // Mock cubeb impl, only supports device enumeration for now.
    126 cubeb_ops const mock_ops = {
    127    /*.init =*/NULL,
    128    /*.get_backend_id =*/cubeb_mock_get_backend_id,
    129    /*.get_max_channel_count =*/cubeb_mock_get_max_channel_count,
    130    /*.get_min_latency =*/cubeb_mock_get_min_latency,
    131    /*.get_preferred_sample_rate =*/cubeb_mock_get_preferred_sample_rate,
    132    /*.get_supported_input_processing_params =*/
    133    cubeb_mock_get_supported_input_processing_params,
    134    /*.enumerate_devices =*/cubeb_mock_enumerate_devices,
    135    /*.device_collection_destroy =*/cubeb_mock_device_collection_destroy,
    136    /*.destroy =*/cubeb_mock_destroy,
    137    /*.stream_init =*/cubeb_mock_stream_init,
    138    /*.stream_destroy =*/cubeb_mock_stream_destroy,
    139    /*.stream_start =*/cubeb_mock_stream_start,
    140    /*.stream_stop =*/cubeb_mock_stream_stop,
    141    /*.stream_get_position =*/cubeb_mock_stream_get_position,
    142    /*.stream_get_latency =*/NULL,
    143    /*.stream_get_input_latency =*/NULL,
    144    /*.stream_set_volume =*/cubeb_mock_stream_set_volume,
    145    /*.stream_set_name =*/cubeb_mock_stream_set_name,
    146    /*.stream_get_current_device =*/NULL,
    147 
    148    /*.stream_set_input_mute =*/NULL,
    149    /*.stream_set_input_processing_params =*/
    150    cubeb_mock_stream_set_input_processing_params,
    151    /*.stream_device_destroy =*/NULL,
    152    /*.stream_register_device_changed_callback =*/
    153    cubeb_mock_stream_register_device_changed_callback,
    154    /*.register_device_collection_changed =*/
    155    cubeb_mock_register_device_collection_changed};
    156 
    157 class SmartMockCubebStream;
    158 
    159 // Represents the fake cubeb_stream. The context instance is needed to
    160 // provide access on cubeb_ops struct.
    161 class MockCubebStream {
    162  friend class MockCubeb;
    163 
    164  // These members need to have the exact same memory layout as a real
    165  // cubeb_stream, so that AsMock() returns a pointer to this that can be used
    166  // as a cubeb_stream.
    167  cubeb* context;
    168  void* mUserPtr;
    169 
    170 public:
    171  enum class KeepProcessing { No, Yes, InvalidState };
    172  enum class RunningMode { Automatic, Manual };
    173 
    174  MockCubebStream(cubeb* aContext, char const* aStreamName,
    175                  cubeb_devid aInputDevice,
    176                  cubeb_stream_params* aInputStreamParams,
    177                  cubeb_devid aOutputDevice,
    178                  cubeb_stream_params* aOutputStreamParams,
    179                  cubeb_data_callback aDataCallback,
    180                  cubeb_state_callback aStateCallback, void* aUserPtr,
    181                  SmartMockCubebStream* aSelf, RunningMode aRunningMode,
    182                  bool aFrozenStart);
    183 
    184  ~MockCubebStream();
    185 
    186  int Start() MOZ_EXCLUDES(mMutex);
    187  int Stop() MOZ_EXCLUDES(mMutex);
    188  uint64_t Position() MOZ_EXCLUDES(mMutex);
    189  void Destroy() MOZ_EXCLUDES(mMutex);
    190  int SetName(char const* aName) MOZ_EXCLUDES(mMutex);
    191  int RegisterDeviceChangedCallback(
    192      cubeb_device_changed_callback aDeviceChangedCallback)
    193      MOZ_EXCLUDES(mMutex);
    194  int SetInputProcessingParams(cubeb_input_processing_params aParams);
    195 
    196  cubeb_stream* AsCubebStream() MOZ_EXCLUDES(mMutex);
    197  static MockCubebStream* AsMock(cubeb_stream* aStream);
    198 
    199  char const* StreamName() const MOZ_EXCLUDES(mMutex) {
    200    MutexAutoLock l(mMutex);
    201    return mName.get();
    202  }
    203  cubeb_devid GetInputDeviceID() const;
    204  cubeb_devid GetOutputDeviceID() const;
    205 
    206  uint32_t InputChannels() const MOZ_EXCLUDES(mMutex);
    207  uint32_t OutputChannels() const MOZ_EXCLUDES(mMutex);
    208  uint32_t SampleRate() const MOZ_EXCLUDES(mMutex);
    209  uint32_t InputFrequency() const MOZ_EXCLUDES(mMutex);
    210  Maybe<cubeb_state> State() const MOZ_EXCLUDES(mMutex);
    211 
    212  void SetDriftFactor(float aDriftFactor) MOZ_EXCLUDES(mMutex);
    213  void ForceError() MOZ_EXCLUDES(mMutex);
    214  void ForceDeviceChanged() MOZ_EXCLUDES(mMutex);
    215  void Thaw() MOZ_EXCLUDES(mMutex);
    216 
    217  // For RunningMode::Manual, drive this MockCubebStream forward.
    218  KeepProcessing ManualDataCallback(long aNrFrames) MOZ_EXCLUDES(mMutex);
    219 
    220  // For RunningMode::Manual, notify the client of a DeviceChanged event
    221  // synchronously.
    222  void NotifyDeviceChangedNow() MOZ_EXCLUDES(mMutex);
    223 
    224  // Enable input recording for this driver. This is best called before
    225  // the thread is running, but is safe to call whenever.
    226  void SetOutputRecordingEnabled(bool aEnabled) MOZ_EXCLUDES(mMutex);
    227  // Enable input recording for this driver. This is best called before
    228  // the thread is running, but is safe to call whenever.
    229  void SetInputRecordingEnabled(bool aEnabled) MOZ_EXCLUDES(mMutex);
    230  // Get the recorded output from this stream. This doesn't copy, and therefore
    231  // only works once.
    232  nsTArray<AudioDataValue>&& TakeRecordedOutput() MOZ_EXCLUDES(mMutex);
    233  // Get the recorded input from this stream. This doesn't copy, and therefore
    234  // only works once.
    235  nsTArray<AudioDataValue>&& TakeRecordedInput() MOZ_EXCLUDES(mMutex);
    236 
    237  MediaEventSource<nsCString>& NameSetEvent();
    238  MediaEventSource<cubeb_state>& StateEvent();
    239  MediaEventSource<uint32_t>& FramesProcessedEvent();
    240  // Notified when frames are processed after first non-silent output
    241  MediaEventSource<uint32_t>& FramesVerifiedEvent();
    242  // Notified when the stream is Stop()ed
    243  MediaEventSource<std::tuple<uint64_t, float, uint32_t>>&
    244  OutputVerificationEvent();
    245  MediaEventSource<void>& ErrorForcedEvent();
    246  MediaEventSource<void>& DeviceChangeForcedEvent();
    247 
    248 private:
    249  cubeb_stream* AsCubebStreamLocked() MOZ_REQUIRES(mMutex);
    250  static MockCubebStream* AsMockLocked(cubeb_stream* aStream);
    251  uint32_t InputChannelsLocked() const MOZ_REQUIRES(mMutex);
    252  uint32_t OutputChannelsLocked() const MOZ_REQUIRES(mMutex);
    253  uint32_t SampleRateLocked() const MOZ_REQUIRES(mMutex);
    254  uint32_t InputFrequencyLocked() const MOZ_REQUIRES(mMutex);
    255  KeepProcessing Process(long aNrFrames) MOZ_REQUIRES(mMutex);
    256  KeepProcessing Process10Ms();
    257 
    258 public:
    259  const RunningMode mRunningMode;
    260  const bool mHasInput;
    261  const bool mHasOutput;
    262  SmartMockCubebStream* const mSelf;
    263 
    264 private:
    265  void NotifyState(cubeb_state aState) MOZ_REQUIRES(mMutex);
    266  void NotifyDeviceChanged() MOZ_EXCLUDES(mMutex);
    267 
    268  static constexpr long kMaxNrFrames = 1920;
    269  // Mutex guarding most members to ensure state is in sync.
    270  mutable Mutex mMutex{"MockCubebStream::mMutex"};
    271  // Monitor used to block start until mFrozenStart is false.
    272  Monitor mFrozenStartMonitor MOZ_ACQUIRED_BEFORE(mMutex);
    273  // Whether this stream should wait for an explicit start request before
    274  // starting.
    275  bool mFrozenStart MOZ_GUARDED_BY(mFrozenStartMonitor);
    276  // The stream's most recently issued state change, if any has occurred.
    277  // Used to abort a frozen start if cubeb_stream_start() is called currently
    278  // with a blocked cubeb_stream_start() call.
    279  Maybe<cubeb_state> mState MOZ_GUARDED_BY(mMutex);
    280  // Whether or not the output-side of this stream (what is written from the
    281  // callback output buffer) is recorded in an internal buffer. The data is then
    282  // available via `GetRecordedOutput`.
    283  bool mOutputRecordingEnabled MOZ_GUARDED_BY(mMutex) = false;
    284  // Whether or not the input-side of this stream (what is written from the
    285  // callback input buffer) is recorded in an internal buffer. The data is then
    286  // available via `TakeRecordedInput`.
    287  bool mInputRecordingEnabled MOZ_GUARDED_BY(mMutex) = false;
    288  // The audio buffer used on data callback.
    289  AudioDataValue mOutputBuffer[MAX_OUTPUT_CHANNELS *
    290                               kMaxNrFrames] MOZ_GUARDED_BY(mMutex) = {};
    291  AudioDataValue mInputBuffer[MAX_INPUT_CHANNELS * kMaxNrFrames] MOZ_GUARDED_BY(
    292      mMutex) = {};
    293  // The audio callback
    294  const cubeb_data_callback mDataCallback = nullptr;
    295  // The stream state callback
    296  const cubeb_state_callback mStateCallback = nullptr;
    297  // The device changed callback
    298  cubeb_device_changed_callback mDeviceChangedCallback MOZ_GUARDED_BY(mMutex) =
    299      nullptr;
    300  // A name for this stream
    301  nsCString mName MOZ_GUARDED_BY(mMutex);
    302  // The stream params
    303  cubeb_stream_params mOutputParams MOZ_GUARDED_BY(mMutex) = {};
    304  cubeb_stream_params mInputParams MOZ_GUARDED_BY(mMutex) = {};
    305  /* Device IDs */
    306  const cubeb_devid mInputDeviceID;
    307  const cubeb_devid mOutputDeviceID;
    308 
    309  float mDriftFactor MOZ_GUARDED_BY(mMutex) = 1.0;
    310  bool mForceErrorState MOZ_GUARDED_BY(mMutex) = false;
    311  bool mForceDeviceChanged MOZ_GUARDED_BY(mMutex) = false;
    312  bool mDestroyed MOZ_GUARDED_BY(mMutex) = false;
    313  uint64_t mPosition MOZ_GUARDED_BY(mMutex) = 0;
    314  AudioGenerator<AudioDataValue> mAudioGenerator MOZ_GUARDED_BY(mMutex);
    315  AudioVerifier<AudioDataValue> mAudioVerifier MOZ_GUARDED_BY(mMutex);
    316 
    317  MediaEventProducer<nsCString> mNameSetEvent;
    318  MediaEventProducer<cubeb_state> mStateEvent;
    319  MediaEventProducer<uint32_t> mFramesProcessedEvent;
    320  MediaEventProducer<uint32_t> mFramesVerifiedEvent;
    321  MediaEventProducer<std::tuple<uint64_t, float, uint32_t>>
    322      mOutputVerificationEvent;
    323  MediaEventProducer<void> mErrorForcedEvent;
    324  MediaEventProducer<void> mDeviceChangedForcedEvent;
    325  // The recorded data, copied from the output_buffer of the callback.
    326  // Interleaved.
    327  nsTArray<AudioDataValue> mRecordedOutput MOZ_GUARDED_BY(mMutex);
    328  // The recorded data, copied from the input buffer of the callback.
    329  // Interleaved.
    330  nsTArray<AudioDataValue> mRecordedInput MOZ_GUARDED_BY(mMutex);
    331 };
    332 
    333 inline std::ostream& operator<<(std::ostream& aStream,
    334                                const MockCubebStream::KeepProcessing& aVal) {
    335  switch (aVal) {
    336    case MockCubebStream::KeepProcessing::Yes:
    337      aStream << "KeepProcessing::Yes";
    338      return aStream;
    339    case MockCubebStream::KeepProcessing::No:
    340      aStream << "KeepProcessing::No";
    341      return aStream;
    342    case MockCubebStream::KeepProcessing::InvalidState:
    343      aStream << "KeepProcessing::InvalidState";
    344      return aStream;
    345  }
    346  aStream << "KeepProcessing(invalid " << static_cast<uint32_t>(aVal) << ")";
    347  return aStream;
    348 }
    349 
    350 class SmartMockCubebStream
    351    : public MockCubebStream,
    352      public SupportsThreadSafeWeakPtr<SmartMockCubebStream> {
    353 public:
    354  MOZ_DECLARE_REFCOUNTED_TYPENAME(SmartMockCubebStream)
    355  SmartMockCubebStream(cubeb* aContext, char const* aStreamName,
    356                       cubeb_devid aInputDevice,
    357                       cubeb_stream_params* aInputStreamParams,
    358                       cubeb_devid aOutputDevice,
    359                       cubeb_stream_params* aOutputStreamParams,
    360                       cubeb_data_callback aDataCallback,
    361                       cubeb_state_callback aStateCallback, void* aUserPtr,
    362                       RunningMode aRunningMode, bool aFrozenStart)
    363      : MockCubebStream(aContext, aStreamName, aInputDevice, aInputStreamParams,
    364                        aOutputDevice, aOutputStreamParams, aDataCallback,
    365                        aStateCallback, aUserPtr, this, aRunningMode,
    366                        aFrozenStart) {}
    367 };
    368 
    369 // This class has two facets: it is both a fake cubeb backend that is intended
    370 // to be used for testing, and passed to Gecko code that expects a normal
    371 // backend, but is also controllable by the test code to decide what the backend
    372 // should do, depending on what is being tested.
    373 class MockCubeb {
    374  // This needs to have the exact same memory layout as a real cubeb backend.
    375  // It's very important for the `ops` member to be the very first member of
    376  // the class, and for MockCubeb to not have any virtual members (to avoid
    377  // having a vtable), so that AsMock() returns a pointer to this that can be
    378  // used as a cubeb backend.
    379  const cubeb_ops* ops;
    380  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MockCubeb);
    381 
    382 public:
    383  using RunningMode = MockCubebStream::RunningMode;
    384 
    385  MockCubeb();
    386  explicit MockCubeb(RunningMode aRunningMode);
    387  // Cubeb backend implementation
    388  // This allows passing this class as a cubeb* instance.
    389  // cubeb_destroy(context) should eventually be called on the return value
    390  // iff this method is called.
    391  cubeb* AsCubebContext();
    392  static MockCubeb* AsMock(cubeb* aContext);
    393  void Destroy();
    394  // Fill in the collection parameter with all devices of aType.
    395  int EnumerateDevices(cubeb_device_type aType,
    396                       cubeb_device_collection* aCollection);
    397  // Clear the collection parameter and deallocate its related memory space.
    398  int DestroyDeviceCollection(cubeb_device_collection* aCollection);
    399 
    400  // For a given device type, add a callback, called with a user pointer, when
    401  // the device collection for this backend changes (i.e. a device has been
    402  // removed or added).
    403  int RegisterDeviceCollectionChangeCallback(
    404      cubeb_device_type aDevType,
    405      cubeb_device_collection_changed_callback aCallback, void* aUserPtr);
    406 
    407  Result<cubeb_input_processing_params, int> SupportedInputProcessingParams()
    408      const;
    409  void SetSupportedInputProcessingParams(cubeb_input_processing_params aParams,
    410                                         int aRv);
    411  // Set the rv to be returned when SetInputProcessingParams for any stream of
    412  // this context would apply the params to the stream, i.e. after passing the
    413  // supported-params check.
    414  void SetInputProcessingApplyRv(int aRv);
    415  int InputProcessingApplyRv() const;
    416 
    417  // Control API
    418 
    419  // Add an input or output device to this backend. This calls the device
    420  // collection invalidation callback if needed.
    421  void AddDevice(cubeb_device_info aDevice);
    422  // Remove a specific input or output device to this backend, returns true if
    423  // a device was removed. This calls the device collection invalidation
    424  // callback if needed.
    425  bool RemoveDevice(cubeb_devid aId);
    426  // Remove all input or output devices from this backend, without calling the
    427  // callback. This is meant to clean up in between tests.
    428  void ClearDevices(cubeb_device_type aType);
    429  // Set the device with the given id as preferred. The current preferred device
    430  // of the same device type will be removed. Does nothing if a device with the
    431  // given id doesn't exist.
    432  void SetPreferredDevice(cubeb_devid aId, cubeb_device_type aType);
    433 
    434  // This allows simulating a backend that does not support setting a device
    435  // collection invalidation callback, to be able to test the fallback path.
    436  void SetSupportDeviceChangeCallback(bool aSupports);
    437 
    438  // This causes the next stream init with this context to return failure;
    439  void ForceStreamInitError();
    440 
    441  // Makes MockCubebStreams starting after this point wait for AllowStart().
    442  // Callers must ensure they get a hold of the stream through StreamInitEvent
    443  // to be able to start them.
    444  void SetStreamStartFreezeEnabled(bool aEnabled);
    445 
    446  // Helper class that automatically unforces a forced audio thread on release.
    447  class AudioThreadAutoUnforcer {
    448    NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AudioThreadAutoUnforcer)
    449 
    450   public:
    451    explicit AudioThreadAutoUnforcer(MockCubeb* aContext)
    452        : mContext(aContext) {}
    453 
    454   protected:
    455    virtual ~AudioThreadAutoUnforcer() { mContext->UnforceAudioThread(); }
    456    MockCubeb* mContext;
    457  };
    458 
    459  // Creates the audio thread if one is not available. The audio thread remains
    460  // forced until UnforceAudioThread is called. The returned promise is resolved
    461  // when the audio thread is running. With this, a test can ensure starting
    462  // audio streams is deterministically fast across platforms for more accurate
    463  // results.
    464  using ForcedAudioThreadPromise =
    465      MozPromise<RefPtr<AudioThreadAutoUnforcer>, nsresult, false>;
    466  RefPtr<ForcedAudioThreadPromise> ForceAudioThread();
    467 
    468  // Allows a forced audio thread to stop.
    469  void UnforceAudioThread();
    470 
    471  int StreamInit(cubeb* aContext, cubeb_stream** aStream,
    472                 char const* aStreamName, cubeb_devid aInputDevice,
    473                 cubeb_stream_params* aInputStreamParams,
    474                 cubeb_devid aOutputDevice,
    475                 cubeb_stream_params* aOutputStreamParams,
    476                 cubeb_data_callback aDataCallback,
    477                 cubeb_state_callback aStateCallback, void* aUserPtr);
    478 
    479  void StreamDestroy(MockCubebStream* aStream);
    480 
    481  void GoFaster();
    482  void DontGoFaster();
    483 
    484  MediaEventSource<RefPtr<SmartMockCubebStream>>& StreamInitEvent();
    485  MediaEventSource<RefPtr<SmartMockCubebStream>>& StreamDestroyEvent();
    486 
    487  // MockCubeb specific API
    488  void StartStream(MockCubebStream* aStream);
    489  void StopStream(MockCubebStream* aStream);
    490 
    491  // Simulates the audio thread. The thread is created at Start and destroyed
    492  // at Stop. At next StreamStart a new thread is created.
    493  static void ThreadFunction_s(MockCubeb* aContext) {
    494    aContext->ThreadFunction();
    495  }
    496 
    497  void ThreadFunction();
    498 
    499 private:
    500  ~MockCubeb();
    501  // The callback to call when the device list has been changed.
    502  cubeb_device_collection_changed_callback
    503      mInputDeviceCollectionChangeCallback = nullptr;
    504  cubeb_device_collection_changed_callback
    505      mOutputDeviceCollectionChangeCallback = nullptr;
    506  // The pointer to pass in the callback.
    507  void* mInputDeviceCollectionChangeUserPtr = nullptr;
    508  void* mOutputDeviceCollectionChangeUserPtr = nullptr;
    509  // Whether or not this backend supports device collection change
    510  // notification via a system callback. If not, Gecko is expected to re-query
    511  // the list every time.
    512  bool mSupportsDeviceCollectionChangedCallback = true;
    513  std::pair<cubeb_input_processing_params, int>
    514      mSupportedInputProcessingParams = std::make_pair(
    515          CUBEB_INPUT_PROCESSING_PARAM_NONE, CUBEB_ERROR_NOT_SUPPORTED);
    516  int mInputProcessingParamsApplyRv = CUBEB_OK;
    517  const RunningMode mRunningMode;
    518  Atomic<bool> mStreamInitErrorState;
    519  // Whether new MockCubebStreams should be frozen on start.
    520  Atomic<bool> mStreamStartFreezeEnabled{false};
    521  // Whether the audio thread is forced, i.e., whether it remains active even
    522  // with no live streams.
    523  Atomic<bool> mForcedAudioThread{false};
    524  Atomic<bool> mHasCubebContext{false};
    525  Atomic<bool> mDestroyed{false};
    526  MozPromiseHolder<ForcedAudioThreadPromise> mForcedAudioThreadPromise;
    527  // Our input and output devices.
    528  nsTArray<cubeb_device_info> mInputDevices;
    529  nsTArray<cubeb_device_info> mOutputDevices;
    530 
    531  // The streams that are currently running.
    532  DataMutex<nsTArray<RefPtr<SmartMockCubebStream>>> mLiveStreams{
    533      "MockCubeb::mLiveStreams"};
    534  // Whether we've launched the detached thread that simulates the audio
    535  // thread, shared across MockCubebStreams to avoid unintended drift. This
    536  // should only be read and written within the mLiveStreams DataMutex locked
    537  // critical section.
    538  bool mFakeAudioThreadRunning = false;
    539  // Whether to run the fake audio thread in fast mode, not caring about wall
    540  // clock time. false is default and means data is processed every 10ms. When
    541  // true we sleep(0) between iterations instead of 10ms.
    542  std::atomic<bool> mFastMode{false};
    543 
    544  MediaEventProducer<RefPtr<SmartMockCubebStream>> mStreamInitEvent;
    545  MediaEventProducer<RefPtr<SmartMockCubebStream>> mStreamDestroyEvent;
    546 };
    547 
    548 int cubeb_mock_enumerate_devices(cubeb* context, cubeb_device_type type,
    549                                 cubeb_device_collection* out) {
    550  return MockCubeb::AsMock(context)->EnumerateDevices(type, out);
    551 }
    552 
    553 int cubeb_mock_device_collection_destroy(cubeb* context,
    554                                         cubeb_device_collection* collection) {
    555  return MockCubeb::AsMock(context)->DestroyDeviceCollection(collection);
    556 }
    557 
    558 int cubeb_mock_register_device_collection_changed(
    559    cubeb* context, cubeb_device_type devtype,
    560    cubeb_device_collection_changed_callback callback, void* user_ptr) {
    561  return MockCubeb::AsMock(context)->RegisterDeviceCollectionChangeCallback(
    562      devtype, callback, user_ptr);
    563 }
    564 
    565 int cubeb_mock_get_supported_input_processing_params(
    566    cubeb* context, cubeb_input_processing_params* params) {
    567  Result<cubeb_input_processing_params, int> res =
    568      MockCubeb::AsMock(context)->SupportedInputProcessingParams();
    569  if (res.isErr()) {
    570    *params = CUBEB_INPUT_PROCESSING_PARAM_NONE;
    571    return res.unwrapErr();
    572  }
    573  *params = res.unwrap();
    574  return CUBEB_OK;
    575 }
    576 
    577 int cubeb_mock_stream_init(
    578    cubeb* context, cubeb_stream** stream, char const* stream_name,
    579    cubeb_devid input_device, cubeb_stream_params* input_stream_params,
    580    cubeb_devid output_device, cubeb_stream_params* output_stream_params,
    581    unsigned int latency, cubeb_data_callback data_callback,
    582    cubeb_state_callback state_callback, void* user_ptr) {
    583  return MockCubeb::AsMock(context)->StreamInit(
    584      context, stream, stream_name, input_device, input_stream_params,
    585      output_device, output_stream_params, data_callback, state_callback,
    586      user_ptr);
    587 }
    588 
    589 int cubeb_mock_stream_start(cubeb_stream* stream) {
    590  return MockCubebStream::AsMock(stream)->Start();
    591 }
    592 
    593 int cubeb_mock_stream_stop(cubeb_stream* stream) {
    594  return MockCubebStream::AsMock(stream)->Stop();
    595 }
    596 
    597 int cubeb_mock_stream_get_position(cubeb_stream* stream, uint64_t* position) {
    598  *position = MockCubebStream::AsMock(stream)->Position();
    599  return CUBEB_OK;
    600 }
    601 
    602 void cubeb_mock_stream_destroy(cubeb_stream* stream) {
    603  MockCubebStream::AsMock(stream)->Destroy();
    604 }
    605 
    606 static char const* cubeb_mock_get_backend_id(cubeb* context) {
    607 #if defined(XP_MACOSX)
    608  return "audiounit";
    609 #elif defined(XP_WIN)
    610  return "wasapi";
    611 #elif defined(ANDROID)
    612  return "opensl";
    613 #elif defined(__OpenBSD__)
    614  return "sndio";
    615 #else
    616  return "pulse";
    617 #endif
    618 }
    619 
    620 static int cubeb_mock_stream_set_volume(cubeb_stream* stream, float volume) {
    621  return CUBEB_OK;
    622 }
    623 
    624 static int cubeb_mock_stream_set_name(cubeb_stream* stream,
    625                                      char const* stream_name) {
    626  return MockCubebStream::AsMock(stream)->SetName(stream_name);
    627  return CUBEB_OK;
    628 }
    629 
    630 int cubeb_mock_stream_register_device_changed_callback(
    631    cubeb_stream* stream,
    632    cubeb_device_changed_callback device_changed_callback) {
    633  return MockCubebStream::AsMock(stream)->RegisterDeviceChangedCallback(
    634      device_changed_callback);
    635 }
    636 
    637 static int cubeb_mock_stream_set_input_processing_params(
    638    cubeb_stream* stream, cubeb_input_processing_params params) {
    639  return MockCubebStream::AsMock(stream)->SetInputProcessingParams(params);
    640 }
    641 
    642 int cubeb_mock_get_min_latency(cubeb* context, cubeb_stream_params params,
    643                               uint32_t* latency_ms) {
    644  *latency_ms = 10;
    645  return CUBEB_OK;
    646 }
    647 
    648 int cubeb_mock_get_preferred_sample_rate(cubeb* context, uint32_t* rate) {
    649  *rate = 44100;
    650  return CUBEB_OK;
    651 }
    652 
    653 int cubeb_mock_get_max_channel_count(cubeb* context, uint32_t* max_channels) {
    654  *max_channels = MAX_OUTPUT_CHANNELS;
    655  return CUBEB_OK;
    656 }
    657 
    658 void PrintDevice(cubeb_device_info aInfo);
    659 
    660 void PrintDevice(AudioDeviceInfo* aInfo);
    661 
    662 cubeb_device_info DeviceTemplate(cubeb_devid aId, cubeb_device_type aType,
    663                                 const char* name);
    664 
    665 cubeb_device_info DeviceTemplate(cubeb_devid aId, cubeb_device_type aType);
    666 
    667 void AddDevices(MockCubeb* mock, uint32_t device_count,
    668                cubeb_device_type deviceType);
    669 
    670 }  // namespace mozilla
    671 
    672 #endif  // MOCKCUBEB_H_