From 59203c63bb777a3bacec32fb8830fba33540e809 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 12 Jun 2024 07:35:29 +0200 Subject: Adding upstream version 127.0. Signed-off-by: Daniel Baumann --- dom/media/gtest/MockCubeb.cpp | 301 ++++++++++++++++++++++++++++++------------ 1 file changed, 213 insertions(+), 88 deletions(-) (limited to 'dom/media/gtest/MockCubeb.cpp') diff --git a/dom/media/gtest/MockCubeb.cpp b/dom/media/gtest/MockCubeb.cpp index ae3a676ac8..9d61ccf4b5 100644 --- a/dom/media/gtest/MockCubeb.cpp +++ b/dom/media/gtest/MockCubeb.cpp @@ -168,79 +168,93 @@ MockCubebStream::MockCubebStream( mAudioVerifier(aInputStreamParams ? aInputStreamParams->rate : aOutputStreamParams->rate, 100 /* aFrequency */) { - MOZ_ASSERT(mAudioGenerator.ChannelCount() <= MAX_INPUT_CHANNELS, - "mInputBuffer has no enough space to hold generated data"); - MOZ_ASSERT_IF(mFrozenStart, mRunningMode == RunningMode::Automatic); + MOZ_RELEASE_ASSERT(mAudioGenerator.ChannelCount() <= MAX_INPUT_CHANNELS, + "mInputBuffer has no enough space to hold generated data"); + if (mFrozenStart) { + MOZ_RELEASE_ASSERT(mRunningMode == RunningMode::Automatic); + } if (aInputStreamParams) { mInputParams = *aInputStreamParams; } if (aOutputStreamParams) { mOutputParams = *aOutputStreamParams; - MOZ_ASSERT(SampleRate() == mOutputParams.rate); + MOZ_RELEASE_ASSERT(SampleRate() == mOutputParams.rate); } } MockCubebStream::~MockCubebStream() = default; int MockCubebStream::Start() { - NotifyState(CUBEB_STATE_STARTED); - mStreamStop = false; - if (mFrozenStart) { - // We need to grab mFrozenStartMonitor before returning to avoid races in - // the calling code -- it controls when to mFrozenStartMonitor.Notify(). - // TempData helps facilitate this by holding what's needed to block the - // calling thread until the background thread has grabbed the lock. - struct TempData { - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TempData) - static_assert(HasThreadSafeRefCnt::value, - "Silence a -Wunused-local-typedef warning"); - Monitor mMonitor{"MockCubebStream::Start::TempData::mMonitor"}; - bool mFinished = false; - - private: - ~TempData() = default; - }; - auto temp = MakeRefPtr(); - MonitorAutoLock lock(temp->mMonitor); - NS_DispatchBackgroundTask(NS_NewRunnableFunction( - "MockCubebStream::WaitForThawBeforeStart", - [temp, this, self = RefPtr(mSelf)]() mutable { - MonitorAutoLock lock(mFrozenStartMonitor); - { - // Unblock MockCubebStream::Start now that we have locked the frozen - // start monitor. - MonitorAutoLock tempLock(temp->mMonitor); - temp->mFinished = true; - temp->mMonitor.Notify(); - temp = nullptr; - } - while (mFrozenStart) { - mFrozenStartMonitor.Wait(); - } - if (!mStreamStop) { + { + MutexAutoLock l(mMutex); + NotifyState(CUBEB_STATE_STARTED); + } + { + MonitorAutoLock lock(mFrozenStartMonitor); + if (mFrozenStart) { + // We need to grab mFrozenStartMonitor before returning to avoid races in + // the calling code -- it controls when to mFrozenStartMonitor.Notify(). + // TempData helps facilitate this by holding what's needed to block the + // calling thread until the background thread has grabbed the lock. + struct TempData { + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TempData) + static_assert(HasThreadSafeRefCnt::value, + "Silence a -Wunused-local-typedef warning"); + Monitor mMonitor{"MockCubebStream::Start::TempData::mMonitor"}; + bool mFinished = false; + + private: + ~TempData() = default; + }; + auto temp = MakeRefPtr(); + MonitorAutoLock lock(temp->mMonitor); + NS_DispatchBackgroundTask(NS_NewRunnableFunction( + "MockCubebStream::WaitForThawBeforeStart", + [temp, this, self = RefPtr(mSelf)]() mutable { + { + // Unblock MockCubebStream::Start now that we have locked the + // frozen start monitor. + MonitorAutoLock tempLock(temp->mMonitor); + temp->mFinished = true; + temp->mMonitor.Notify(); + temp = nullptr; + } + { + MonitorAutoLock lock(mFrozenStartMonitor); + while (mFrozenStart) { + mFrozenStartMonitor.Wait(); + } + } + if (MutexAutoLock l(mMutex); + !mState || *mState != CUBEB_STATE_STARTED) { + return; + } MockCubeb::AsMock(context)->StartStream(mSelf); - } - })); - while (!temp->mFinished) { - temp->mMonitor.Wait(); + })); + while (!temp->mFinished) { + temp->mMonitor.Wait(); + } + return CUBEB_OK; } - return CUBEB_OK; } MockCubeb::AsMock(context)->StartStream(this); return CUBEB_OK; } int MockCubebStream::Stop() { + MockCubeb::AsMock(context)->StopStream(this); + MutexAutoLock l(mMutex); mOutputVerificationEvent.Notify(std::make_tuple( mAudioVerifier.PreSilenceSamples(), mAudioVerifier.EstimatedFreq(), mAudioVerifier.CountDiscontinuities())); - MockCubeb::AsMock(context)->StopStream(this); - mStreamStop = true; NotifyState(CUBEB_STATE_STOPPED); return CUBEB_OK; } -uint64_t MockCubebStream::Position() { return mPosition; } +uint64_t MockCubebStream::Position() { + MutexAutoLock l(mMutex); + return mPosition; +} void MockCubebStream::Destroy() { // Stop() even if cubeb_stream_stop() has already been called, as with @@ -248,11 +262,15 @@ void MockCubebStream::Destroy() { // This provides an extra STOPPED state callback as with audioipc. // It also ensures that this stream is removed from MockCubeb::mLiveStreams. Stop(); - mDestroyed = true; + { + MutexAutoLock l(mMutex); + mDestroyed = true; + } MockCubeb::AsMock(context)->StreamDestroy(this); } int MockCubebStream::SetName(char const* aName) { + MutexAutoLock l(mMutex); mName = aName; mNameSetEvent.Notify(mName); return CUBEB_OK; @@ -260,6 +278,7 @@ int MockCubebStream::SetName(char const* aName) { int MockCubebStream::RegisterDeviceChangedCallback( cubeb_device_changed_callback aDeviceChangedCallback) { + MutexAutoLock l(mMutex); if (mDeviceChangedCallback && aDeviceChangedCallback) { return CUBEB_ERROR_INVALID_PARAMETER; } @@ -267,14 +286,41 @@ int MockCubebStream::RegisterDeviceChangedCallback( return CUBEB_OK; } +int MockCubebStream::SetInputProcessingParams( + cubeb_input_processing_params aParams) { + MockCubeb* mock = MockCubeb::AsMock(context); + auto res = mock->SupportedInputProcessingParams(); + if (res.isErr()) { + return CUBEB_ERROR_NOT_SUPPORTED; + } + cubeb_input_processing_params supported = res.unwrap(); + if ((supported & aParams) != aParams) { + return CUBEB_ERROR_INVALID_PARAMETER; + } + return mock->InputProcessingApplyRv(); +} + cubeb_stream* MockCubebStream::AsCubebStream() { - MOZ_ASSERT(!mDestroyed); + MutexAutoLock l(mMutex); + return AsCubebStreamLocked(); +} + +cubeb_stream* MockCubebStream::AsCubebStreamLocked() { + MOZ_RELEASE_ASSERT(!mDestroyed); + mMutex.AssertCurrentThreadOwns(); return reinterpret_cast(this); } MockCubebStream* MockCubebStream::AsMock(cubeb_stream* aStream) { auto* mockStream = reinterpret_cast(aStream); - MOZ_ASSERT(!mockStream->mDestroyed); + MutexAutoLock l(mockStream->mMutex); + return AsMockLocked(aStream); +} + +MockCubebStream* MockCubebStream::AsMockLocked(cubeb_stream* aStream) { + auto* mockStream = reinterpret_cast(aStream); + mockStream->mMutex.AssertCurrentThreadOwns(); + MOZ_RELEASE_ASSERT(!mockStream->mDestroyed); return mockStream; } @@ -285,58 +331,96 @@ cubeb_devid MockCubebStream::GetOutputDeviceID() const { } uint32_t MockCubebStream::InputChannels() const { + MutexAutoLock l(mMutex); + return InputChannelsLocked(); +} + +uint32_t MockCubebStream::InputChannelsLocked() const { + mMutex.AssertCurrentThreadOwns(); return mAudioGenerator.ChannelCount(); } uint32_t MockCubebStream::OutputChannels() const { + MutexAutoLock l(mMutex); + return OutputChannelsLocked(); +} + +uint32_t MockCubebStream::OutputChannelsLocked() const { + mMutex.AssertCurrentThreadOwns(); return mOutputParams.channels; } uint32_t MockCubebStream::SampleRate() const { + MutexAutoLock l(mMutex); + return SampleRateLocked(); +} + +uint32_t MockCubebStream::SampleRateLocked() const { + mMutex.AssertCurrentThreadOwns(); return mAudioGenerator.mSampleRate; } uint32_t MockCubebStream::InputFrequency() const { + MutexAutoLock l(mMutex); + return InputFrequencyLocked(); +} + +uint32_t MockCubebStream::InputFrequencyLocked() const { + mMutex.AssertCurrentThreadOwns(); return mAudioGenerator.mFrequency; } +Maybe MockCubebStream::State() const { + MutexAutoLock l(mMutex); + return mState; +} + nsTArray&& MockCubebStream::TakeRecordedOutput() { + MutexAutoLock l(mMutex); return std::move(mRecordedOutput); } nsTArray&& MockCubebStream::TakeRecordedInput() { + MutexAutoLock l(mMutex); return std::move(mRecordedInput); } void MockCubebStream::SetDriftFactor(float aDriftFactor) { - MOZ_ASSERT(mRunningMode == MockCubeb::RunningMode::Automatic); + MOZ_RELEASE_ASSERT(mRunningMode == MockCubeb::RunningMode::Automatic); + MutexAutoLock l(mMutex); mDriftFactor = aDriftFactor; } -void MockCubebStream::ForceError() { mForceErrorState = true; } +void MockCubebStream::ForceError() { + MutexAutoLock l(mMutex); + mForceErrorState = true; +} void MockCubebStream::ForceDeviceChanged() { - MOZ_ASSERT(mRunningMode == RunningMode::Automatic); + MOZ_RELEASE_ASSERT(mRunningMode == RunningMode::Automatic); + MutexAutoLock l(mMutex); mForceDeviceChanged = true; }; void MockCubebStream::NotifyDeviceChangedNow() { - MOZ_ASSERT(mRunningMode == RunningMode::Manual); + MOZ_RELEASE_ASSERT(mRunningMode == RunningMode::Manual); NotifyDeviceChanged(); } void MockCubebStream::Thaw() { - MOZ_ASSERT(mRunningMode == RunningMode::Automatic); + MOZ_RELEASE_ASSERT(mRunningMode == RunningMode::Automatic); MonitorAutoLock l(mFrozenStartMonitor); mFrozenStart = false; mFrozenStartMonitor.Notify(); } void MockCubebStream::SetOutputRecordingEnabled(bool aEnabled) { + MutexAutoLock l(mMutex); mOutputRecordingEnabled = aEnabled; } void MockCubebStream::SetInputRecordingEnabled(bool aEnabled) { + MutexAutoLock l(mMutex); mInputRecordingEnabled = aEnabled; } @@ -370,33 +454,43 @@ MediaEventSource& MockCubebStream::DeviceChangeForcedEvent() { } KeepProcessing MockCubebStream::ManualDataCallback(long aNrFrames) { - MOZ_ASSERT(mRunningMode == RunningMode::Manual); - MOZ_ASSERT(aNrFrames <= kMaxNrFrames); + MOZ_RELEASE_ASSERT(mRunningMode == RunningMode::Manual); + MOZ_RELEASE_ASSERT(aNrFrames <= kMaxNrFrames); + MutexAutoLock l(mMutex); return Process(aNrFrames); } KeepProcessing MockCubebStream::Process(long aNrFrames) { + mMutex.AssertCurrentThreadOwns(); + if (!mState || *mState != CUBEB_STATE_STARTED) { + return KeepProcessing::InvalidState; + } if (mInputParams.rate) { mAudioGenerator.GenerateInterleaved(mInputBuffer, aNrFrames); } - cubeb_stream* stream = AsCubebStream(); + cubeb_stream* stream = AsCubebStreamLocked(); const long outframes = mDataCallback(stream, mUserPtr, mHasInput ? mInputBuffer : nullptr, mHasOutput ? mOutputBuffer : nullptr, aNrFrames); - if (mInputRecordingEnabled && mHasInput) { - mRecordedInput.AppendElements(mInputBuffer, outframes * InputChannels()); - } - if (mOutputRecordingEnabled && mHasOutput) { - mRecordedOutput.AppendElements(mOutputBuffer, outframes * OutputChannels()); - } - mAudioVerifier.AppendDataInterleaved(mOutputBuffer, outframes, - MAX_OUTPUT_CHANNELS); - mPosition += outframes; + if (outframes > 0) { + if (mInputRecordingEnabled && mHasInput) { + mRecordedInput.AppendElements(mInputBuffer, + outframes * InputChannelsLocked()); + } + if (mOutputRecordingEnabled && mHasOutput) { + mRecordedOutput.AppendElements(mOutputBuffer, + + outframes * OutputChannelsLocked()); + } + mAudioVerifier.AppendDataInterleaved(mOutputBuffer, outframes, + MAX_OUTPUT_CHANNELS); + mPosition += outframes; - mFramesProcessedEvent.Notify(outframes); - if (mAudioVerifier.PreSilenceEnded()) { - mFramesVerifiedEvent.Notify(outframes); + mFramesProcessedEvent.Notify(outframes); + if (mAudioVerifier.PreSilenceEnded()) { + mFramesVerifiedEvent.Notify(outframes); + } } if (outframes < aNrFrames) { @@ -422,8 +516,9 @@ KeepProcessing MockCubebStream::Process(long aNrFrames) { } KeepProcessing MockCubebStream::Process10Ms() { - MOZ_ASSERT(mRunningMode == RunningMode::Automatic); - uint32_t rate = SampleRate(); + MOZ_RELEASE_ASSERT(mRunningMode == RunningMode::Automatic); + MutexAutoLock l(mMutex); + uint32_t rate = SampleRateLocked(); const long nrFrames = static_cast(static_cast(rate * 10) * mDriftFactor) / PR_MSEC_PER_SEC; @@ -431,11 +526,14 @@ KeepProcessing MockCubebStream::Process10Ms() { } void MockCubebStream::NotifyState(cubeb_state aState) { - mStateCallback(AsCubebStream(), mUserPtr, aState); + mMutex.AssertCurrentThreadOwns(); + mState = Some(aState); + mStateCallback(AsCubebStreamLocked(), mUserPtr, aState); mStateEvent.Notify(aState); } void MockCubebStream::NotifyDeviceChanged() { + MutexAutoLock l(mMutex); mDeviceChangedCallback(this->mUserPtr); mDeviceChangedForcedEvent.Notify(); } @@ -445,20 +543,20 @@ MockCubeb::MockCubeb() : MockCubeb(MockCubeb::RunningMode::Automatic) {} MockCubeb::MockCubeb(RunningMode aRunningMode) : ops(&mock_ops), mRunningMode(aRunningMode) {} -MockCubeb::~MockCubeb() { MOZ_ASSERT(!mFakeAudioThread); }; +MockCubeb::~MockCubeb() { MOZ_RELEASE_ASSERT(!mFakeAudioThread); }; void MockCubeb::Destroy() { - MOZ_ASSERT(mHasCubebContext); + MOZ_RELEASE_ASSERT(mHasCubebContext); { auto streams = mLiveStreams.Lock(); - MOZ_ASSERT(streams->IsEmpty()); + MOZ_RELEASE_ASSERT(streams->IsEmpty()); } mDestroyed = true; Release(); } cubeb* MockCubeb::AsCubebContext() { - MOZ_ASSERT(!mDestroyed); + MOZ_RELEASE_ASSERT(!mDestroyed); if (mHasCubebContext.compareExchange(false, true)) { AddRef(); } @@ -467,7 +565,7 @@ cubeb* MockCubeb::AsCubebContext() { MockCubeb* MockCubeb::AsMock(cubeb* aContext) { auto* mockCubeb = reinterpret_cast(aContext); - MOZ_ASSERT(!mockCubeb->mDestroyed); + MOZ_RELEASE_ASSERT(!mockCubeb->mDestroyed); return mockCubeb; } @@ -528,6 +626,28 @@ int MockCubeb::RegisterDeviceCollectionChangeCallback( return CUBEB_OK; } +Result +MockCubeb::SupportedInputProcessingParams() const { + const auto& [params, rv] = mSupportedInputProcessingParams; + if (rv != CUBEB_OK) { + return Err(rv); + } + return params; +} + +void MockCubeb::SetSupportedInputProcessingParams( + cubeb_input_processing_params aParams, int aRv) { + mSupportedInputProcessingParams = std::make_pair(aParams, aRv); +} + +void MockCubeb::SetInputProcessingApplyRv(int aRv) { + mInputProcessingParamsApplyRv = aRv; +} + +int MockCubeb::InputProcessingApplyRv() const { + return mInputProcessingParamsApplyRv; +} + void MockCubeb::AddDevice(cubeb_device_info aDevice) { if (aDevice.type == CUBEB_DEVICE_TYPE_INPUT) { mInputDevices.AppendElement(aDevice); @@ -613,12 +733,12 @@ void MockCubeb::SetSupportDeviceChangeCallback(bool aSupports) { void MockCubeb::ForceStreamInitError() { mStreamInitErrorState = true; } void MockCubeb::SetStreamStartFreezeEnabled(bool aEnabled) { - MOZ_ASSERT(mRunningMode == RunningMode::Automatic); + MOZ_RELEASE_ASSERT(mRunningMode == RunningMode::Automatic); mStreamStartFreezeEnabled = aEnabled; } auto MockCubeb::ForceAudioThread() -> RefPtr { - MOZ_ASSERT(mRunningMode == RunningMode::Automatic); + MOZ_RELEASE_ASSERT(mRunningMode == RunningMode::Automatic); RefPtr p = mForcedAudioThreadPromise.Ensure(__func__); mForcedAudioThread = true; @@ -627,7 +747,7 @@ auto MockCubeb::ForceAudioThread() -> RefPtr { } void MockCubeb::UnforceAudioThread() { - MOZ_ASSERT(mRunningMode == RunningMode::Automatic); + MOZ_RELEASE_ASSERT(mRunningMode == RunningMode::Automatic); mForcedAudioThread = false; } @@ -660,12 +780,12 @@ void MockCubeb::StreamDestroy(MockCubebStream* aStream) { } void MockCubeb::GoFaster() { - MOZ_ASSERT(mRunningMode == RunningMode::Automatic); + MOZ_RELEASE_ASSERT(mRunningMode == RunningMode::Automatic); mFastMode = true; } void MockCubeb::DontGoFaster() { - MOZ_ASSERT(mRunningMode == RunningMode::Automatic); + MOZ_RELEASE_ASSERT(mRunningMode == RunningMode::Automatic); mFastMode = false; } @@ -679,13 +799,17 @@ MockCubeb::StreamDestroyEvent() { } void MockCubeb::StartStream(MockCubebStream* aStream) { + if (aStream) { + aStream->mMutex.AssertNotCurrentThreadOwns(); + } auto streams = mLiveStreams.Lock(); - MOZ_ASSERT_IF(!aStream, mForcedAudioThread); - // Forcing an audio thread must happen before starting streams - MOZ_ASSERT_IF(!aStream, streams->IsEmpty()); if (aStream) { - MOZ_ASSERT(!streams->Contains(aStream->mSelf)); + MOZ_RELEASE_ASSERT(!streams->Contains(aStream->mSelf)); streams->AppendElement(aStream->mSelf); + } else { + MOZ_RELEASE_ASSERT(mForcedAudioThread); + // Forcing an audio thread must happen before starting streams + MOZ_RELEASE_ASSERT(streams->IsEmpty()); } if (!mFakeAudioThread && mRunningMode == RunningMode::Automatic) { AddRef(); // released when the thread exits @@ -694,6 +818,7 @@ void MockCubeb::StartStream(MockCubebStream* aStream) { } void MockCubeb::StopStream(MockCubebStream* aStream) { + aStream->mMutex.AssertNotCurrentThreadOwns(); { auto streams = mLiveStreams.Lock(); if (!streams->Contains(aStream->mSelf)) { @@ -719,7 +844,7 @@ void MockCubeb::ThreadFunction() { } } streams->RemoveElementsBy([](const auto& stream) { return !stream; }); - MOZ_ASSERT(mFakeAudioThread); + MOZ_RELEASE_ASSERT(mFakeAudioThread); if (streams->IsEmpty() && !mForcedAudioThread) { // This leaks the std::thread if Gecko's main thread has already been // shut down. -- cgit v1.2.3