diff options
Diffstat (limited to 'dom/media/gtest/MockCubeb.h')
-rw-r--r-- | dom/media/gtest/MockCubeb.h | 184 |
1 files changed, 129 insertions, 55 deletions
diff --git a/dom/media/gtest/MockCubeb.h b/dom/media/gtest/MockCubeb.h index ed6342a779..15689a4a4e 100644 --- a/dom/media/gtest/MockCubeb.h +++ b/dom/media/gtest/MockCubeb.h @@ -11,12 +11,15 @@ #include "MediaEventSource.h" #include "mozilla/DataMutex.h" #include "mozilla/MozPromise.h" +#include "mozilla/Result.h" +#include "mozilla/ResultVariant.h" #include "mozilla/ThreadSafeWeakPtr.h" #include "nsTArray.h" #include <thread> #include <atomic> #include <chrono> +#include <utility> namespace mozilla { const uint32_t MAX_OUTPUT_CHANNELS = 2; @@ -68,6 +71,8 @@ struct cubeb_ops { // Keep those and the struct definition in sync with cubeb.h and // cubeb-internal.h void cubeb_mock_destroy(cubeb* context); +static int cubeb_mock_get_supported_input_processing_params( + cubeb* context, cubeb_input_processing_params* params); static int cubeb_mock_enumerate_devices(cubeb* context, cubeb_device_type type, cubeb_device_collection* out); @@ -101,6 +106,9 @@ static int cubeb_mock_stream_set_volume(cubeb_stream* stream, float volume); static int cubeb_mock_stream_set_name(cubeb_stream* stream, char const* stream_name); +static int cubeb_mock_stream_set_input_processing_params( + cubeb_stream* stream, cubeb_input_processing_params); + static int cubeb_mock_stream_register_device_changed_callback( cubeb_stream* stream, cubeb_device_changed_callback device_changed_callback); @@ -122,7 +130,7 @@ cubeb_ops const mock_ops = { /*.get_min_latency =*/cubeb_mock_get_min_latency, /*.get_preferred_sample_rate =*/cubeb_mock_get_preferred_sample_rate, /*.get_supported_input_processing_params =*/ - NULL, + cubeb_mock_get_supported_input_processing_params, /*.enumerate_devices =*/cubeb_mock_enumerate_devices, /*.device_collection_destroy =*/cubeb_mock_device_collection_destroy, /*.destroy =*/cubeb_mock_destroy, @@ -139,7 +147,7 @@ cubeb_ops const mock_ops = { /*.stream_set_input_mute =*/NULL, /*.stream_set_input_processing_params =*/ - NULL, + cubeb_mock_stream_set_input_processing_params, /*.stream_device_destroy =*/NULL, /*.stream_register_device_changed_callback =*/ cubeb_mock_stream_register_device_changed_callback, @@ -160,7 +168,7 @@ class MockCubebStream { void* mUserPtr; public: - enum class KeepProcessing { No, Yes }; + enum class KeepProcessing { No, Yes, InvalidState }; enum class RunningMode { Automatic, Manual }; MockCubebStream(cubeb* aContext, char const* aStreamName, @@ -175,50 +183,56 @@ class MockCubebStream { ~MockCubebStream(); - int Start(); - int Stop(); - uint64_t Position(); - void Destroy(); - int SetName(char const* aName); + int Start() MOZ_EXCLUDES(mMutex); + int Stop() MOZ_EXCLUDES(mMutex); + uint64_t Position() MOZ_EXCLUDES(mMutex); + void Destroy() MOZ_EXCLUDES(mMutex); + int SetName(char const* aName) MOZ_EXCLUDES(mMutex); int RegisterDeviceChangedCallback( - cubeb_device_changed_callback aDeviceChangedCallback); + cubeb_device_changed_callback aDeviceChangedCallback) + MOZ_EXCLUDES(mMutex); + int SetInputProcessingParams(cubeb_input_processing_params aParams); - cubeb_stream* AsCubebStream(); + cubeb_stream* AsCubebStream() MOZ_EXCLUDES(mMutex); static MockCubebStream* AsMock(cubeb_stream* aStream); - char const* StreamName() const { return mName.get(); } + char const* StreamName() const MOZ_EXCLUDES(mMutex) { + MutexAutoLock l(mMutex); + return mName.get(); + } cubeb_devid GetInputDeviceID() const; cubeb_devid GetOutputDeviceID() const; - uint32_t InputChannels() const; - uint32_t OutputChannels() const; - uint32_t SampleRate() const; - uint32_t InputFrequency() const; + uint32_t InputChannels() const MOZ_EXCLUDES(mMutex); + uint32_t OutputChannels() const MOZ_EXCLUDES(mMutex); + uint32_t SampleRate() const MOZ_EXCLUDES(mMutex); + uint32_t InputFrequency() const MOZ_EXCLUDES(mMutex); + Maybe<cubeb_state> State() const MOZ_EXCLUDES(mMutex); - void SetDriftFactor(float aDriftFactor); - void ForceError(); - void ForceDeviceChanged(); - void Thaw(); + void SetDriftFactor(float aDriftFactor) MOZ_EXCLUDES(mMutex); + void ForceError() MOZ_EXCLUDES(mMutex); + void ForceDeviceChanged() MOZ_EXCLUDES(mMutex); + void Thaw() MOZ_EXCLUDES(mMutex); // For RunningMode::Manual, drive this MockCubebStream forward. - KeepProcessing ManualDataCallback(long aNrFrames); + KeepProcessing ManualDataCallback(long aNrFrames) MOZ_EXCLUDES(mMutex); // For RunningMode::Manual, notify the client of a DeviceChanged event // synchronously. - void NotifyDeviceChangedNow(); + void NotifyDeviceChangedNow() MOZ_EXCLUDES(mMutex); // Enable input recording for this driver. This is best called before // the thread is running, but is safe to call whenever. - void SetOutputRecordingEnabled(bool aEnabled); + void SetOutputRecordingEnabled(bool aEnabled) MOZ_EXCLUDES(mMutex); // Enable input recording for this driver. This is best called before // the thread is running, but is safe to call whenever. - void SetInputRecordingEnabled(bool aEnabled); + void SetInputRecordingEnabled(bool aEnabled) MOZ_EXCLUDES(mMutex); // Get the recorded output from this stream. This doesn't copy, and therefore // only works once. - nsTArray<AudioDataValue>&& TakeRecordedOutput(); + nsTArray<AudioDataValue>&& TakeRecordedOutput() MOZ_EXCLUDES(mMutex); // Get the recorded input from this stream. This doesn't copy, and therefore // only works once. - nsTArray<AudioDataValue>&& TakeRecordedInput(); + nsTArray<AudioDataValue>&& TakeRecordedInput() MOZ_EXCLUDES(mMutex); MediaEventSource<nsCString>& NameSetEvent(); MediaEventSource<cubeb_state>& StateEvent(); @@ -232,7 +246,13 @@ class MockCubebStream { MediaEventSource<void>& DeviceChangeForcedEvent(); private: - KeepProcessing Process(long aNrFrames); + cubeb_stream* AsCubebStreamLocked() MOZ_REQUIRES(mMutex); + static MockCubebStream* AsMockLocked(cubeb_stream* aStream); + uint32_t InputChannelsLocked() const MOZ_REQUIRES(mMutex); + uint32_t OutputChannelsLocked() const MOZ_REQUIRES(mMutex); + uint32_t SampleRateLocked() const MOZ_REQUIRES(mMutex); + uint32_t InputFrequencyLocked() const MOZ_REQUIRES(mMutex); + KeepProcessing Process(long aNrFrames) MOZ_REQUIRES(mMutex); KeepProcessing Process10Ms(); public: @@ -242,52 +262,58 @@ class MockCubebStream { SmartMockCubebStream* const mSelf; private: - void NotifyState(cubeb_state aState); - void NotifyDeviceChanged(); + void NotifyState(cubeb_state aState) MOZ_REQUIRES(mMutex); + void NotifyDeviceChanged() MOZ_EXCLUDES(mMutex); static constexpr long kMaxNrFrames = 1920; + // Mutex guarding most members to ensure state is in sync. + mutable Mutex mMutex{"MockCubebStream::mMutex"}; // Monitor used to block start until mFrozenStart is false. - Monitor mFrozenStartMonitor MOZ_UNANNOTATED; + Monitor mFrozenStartMonitor MOZ_ACQUIRED_BEFORE(mMutex); // Whether this stream should wait for an explicit start request before - // starting. Protected by FrozenStartMonitor. - bool mFrozenStart; + // starting. + bool mFrozenStart MOZ_GUARDED_BY(mFrozenStartMonitor); + // The stream's most recently issued state change, if any has occurred. // Used to abort a frozen start if cubeb_stream_start() is called currently // with a blocked cubeb_stream_start() call. - std::atomic_bool mStreamStop{true}; + Maybe<cubeb_state> mState MOZ_GUARDED_BY(mMutex); // Whether or not the output-side of this stream (what is written from the // callback output buffer) is recorded in an internal buffer. The data is then // available via `GetRecordedOutput`. - std::atomic_bool mOutputRecordingEnabled{false}; + bool mOutputRecordingEnabled MOZ_GUARDED_BY(mMutex) = false; // Whether or not the input-side of this stream (what is written from the // callback input buffer) is recorded in an internal buffer. The data is then // available via `TakeRecordedInput`. - std::atomic_bool mInputRecordingEnabled{false}; + bool mInputRecordingEnabled MOZ_GUARDED_BY(mMutex) = false; // The audio buffer used on data callback. - AudioDataValue mOutputBuffer[MAX_OUTPUT_CHANNELS * kMaxNrFrames] = {}; - AudioDataValue mInputBuffer[MAX_INPUT_CHANNELS * kMaxNrFrames] = {}; + AudioDataValue mOutputBuffer[MAX_OUTPUT_CHANNELS * + kMaxNrFrames] MOZ_GUARDED_BY(mMutex) = {}; + AudioDataValue mInputBuffer[MAX_INPUT_CHANNELS * kMaxNrFrames] MOZ_GUARDED_BY( + mMutex) = {}; // The audio callback - cubeb_data_callback mDataCallback = nullptr; + const cubeb_data_callback mDataCallback = nullptr; // The stream state callback - cubeb_state_callback mStateCallback = nullptr; + const cubeb_state_callback mStateCallback = nullptr; // The device changed callback - cubeb_device_changed_callback mDeviceChangedCallback = nullptr; + cubeb_device_changed_callback mDeviceChangedCallback MOZ_GUARDED_BY(mMutex) = + nullptr; // A name for this stream - nsCString mName; + nsCString mName MOZ_GUARDED_BY(mMutex); // The stream params - cubeb_stream_params mOutputParams = {}; - cubeb_stream_params mInputParams = {}; + cubeb_stream_params mOutputParams MOZ_GUARDED_BY(mMutex) = {}; + cubeb_stream_params mInputParams MOZ_GUARDED_BY(mMutex) = {}; /* Device IDs */ - cubeb_devid mInputDeviceID; - cubeb_devid mOutputDeviceID; - - std::atomic<float> mDriftFactor{1.0}; - std::atomic_bool mFastMode{false}; - std::atomic_bool mForceErrorState{false}; - std::atomic_bool mForceDeviceChanged{false}; - std::atomic_bool mDestroyed{false}; - std::atomic<uint64_t> mPosition{0}; - AudioGenerator<AudioDataValue> mAudioGenerator; - AudioVerifier<AudioDataValue> mAudioVerifier; + const cubeb_devid mInputDeviceID; + const cubeb_devid mOutputDeviceID; + + float mDriftFactor MOZ_GUARDED_BY(mMutex) = 1.0; + bool mFastMode MOZ_GUARDED_BY(mMutex) = false; + bool mForceErrorState MOZ_GUARDED_BY(mMutex) = false; + bool mForceDeviceChanged MOZ_GUARDED_BY(mMutex) = false; + bool mDestroyed MOZ_GUARDED_BY(mMutex) = false; + uint64_t mPosition MOZ_GUARDED_BY(mMutex) = 0; + AudioGenerator<AudioDataValue> mAudioGenerator MOZ_GUARDED_BY(mMutex); + AudioVerifier<AudioDataValue> mAudioVerifier MOZ_GUARDED_BY(mMutex); MediaEventProducer<nsCString> mNameSetEvent; MediaEventProducer<cubeb_state> mStateEvent; @@ -299,12 +325,29 @@ class MockCubebStream { MediaEventProducer<void> mDeviceChangedForcedEvent; // The recorded data, copied from the output_buffer of the callback. // Interleaved. - nsTArray<AudioDataValue> mRecordedOutput; + nsTArray<AudioDataValue> mRecordedOutput MOZ_GUARDED_BY(mMutex); // The recorded data, copied from the input buffer of the callback. // Interleaved. - nsTArray<AudioDataValue> mRecordedInput; + nsTArray<AudioDataValue> mRecordedInput MOZ_GUARDED_BY(mMutex); }; +inline std::ostream& operator<<(std::ostream& aStream, + const MockCubebStream::KeepProcessing& aVal) { + switch (aVal) { + case MockCubebStream::KeepProcessing::Yes: + aStream << "KeepProcessing::Yes"; + return aStream; + case MockCubebStream::KeepProcessing::No: + aStream << "KeepProcessing::No"; + return aStream; + case MockCubebStream::KeepProcessing::InvalidState: + aStream << "KeepProcessing::InvalidState"; + return aStream; + } + aStream << "KeepProcessing(invalid " << static_cast<uint32_t>(aVal) << ")"; + return aStream; +} + class SmartMockCubebStream : public MockCubebStream, public SupportsThreadSafeWeakPtr<SmartMockCubebStream> { @@ -362,6 +405,16 @@ class MockCubeb { cubeb_device_type aDevType, cubeb_device_collection_changed_callback aCallback, void* aUserPtr); + Result<cubeb_input_processing_params, int> SupportedInputProcessingParams() + const; + void SetSupportedInputProcessingParams(cubeb_input_processing_params aParams, + int aRv); + // Set the rv to be returned when SetInputProcessingParams for any stream of + // this context would apply the params to the stream, i.e. after passing the + // supported-params check. + void SetInputProcessingApplyRv(int aRv); + int InputProcessingApplyRv() const; + // Control API // Add an input or output device to this backend. This calls the device @@ -455,6 +508,10 @@ class MockCubeb { // notification via a system callback. If not, Gecko is expected to re-query // the list every time. bool mSupportsDeviceCollectionChangedCallback = true; + std::pair<cubeb_input_processing_params, int> + mSupportedInputProcessingParams = std::make_pair( + CUBEB_INPUT_PROCESSING_PARAM_NONE, CUBEB_ERROR_NOT_SUPPORTED); + int mInputProcessingParamsApplyRv = CUBEB_OK; const RunningMode mRunningMode; Atomic<bool> mStreamInitErrorState; // Whether new MockCubebStreams should be frozen on start. @@ -502,6 +559,18 @@ int cubeb_mock_register_device_collection_changed( devtype, callback, user_ptr); } +int cubeb_mock_get_supported_input_processing_params( + cubeb* context, cubeb_input_processing_params* params) { + Result<cubeb_input_processing_params, int> res = + MockCubeb::AsMock(context)->SupportedInputProcessingParams(); + if (res.isErr()) { + *params = CUBEB_INPUT_PROCESSING_PARAM_NONE; + return res.unwrapErr(); + } + *params = res.unwrap(); + return CUBEB_OK; +} + int cubeb_mock_stream_init( cubeb* context, cubeb_stream** stream, char const* stream_name, cubeb_devid input_device, cubeb_stream_params* input_stream_params, @@ -562,6 +631,11 @@ int cubeb_mock_stream_register_device_changed_callback( device_changed_callback); } +static int cubeb_mock_stream_set_input_processing_params( + cubeb_stream* stream, cubeb_input_processing_params params) { + return MockCubebStream::AsMock(stream)->SetInputProcessingParams(params); +} + int cubeb_mock_get_min_latency(cubeb* context, cubeb_stream_params params, uint32_t* latency_ms) { *latency_ms = 10; |