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_