summaryrefslogtreecommitdiffstats
path: root/dom/media/gtest/MockCubeb.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/gtest/MockCubeb.cpp')
-rw-r--r--dom/media/gtest/MockCubeb.cpp301
1 files changed, 213 insertions, 88 deletions
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<TempData>();
- MonitorAutoLock lock(temp->mMonitor);
- NS_DispatchBackgroundTask(NS_NewRunnableFunction(
- "MockCubebStream::WaitForThawBeforeStart",
- [temp, this, self = RefPtr<SmartMockCubebStream>(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<TempData>();
+ MonitorAutoLock lock(temp->mMonitor);
+ NS_DispatchBackgroundTask(NS_NewRunnableFunction(
+ "MockCubebStream::WaitForThawBeforeStart",
+ [temp, this, self = RefPtr<SmartMockCubebStream>(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<cubeb_stream*>(this);
}
MockCubebStream* MockCubebStream::AsMock(cubeb_stream* aStream) {
auto* mockStream = reinterpret_cast<MockCubebStream*>(aStream);
- MOZ_ASSERT(!mockStream->mDestroyed);
+ MutexAutoLock l(mockStream->mMutex);
+ return AsMockLocked(aStream);
+}
+
+MockCubebStream* MockCubebStream::AsMockLocked(cubeb_stream* aStream) {
+ auto* mockStream = reinterpret_cast<MockCubebStream*>(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<cubeb_state> MockCubebStream::State() const {
+ MutexAutoLock l(mMutex);
+ return mState;
+}
+
nsTArray<AudioDataValue>&& MockCubebStream::TakeRecordedOutput() {
+ MutexAutoLock l(mMutex);
return std::move(mRecordedOutput);
}
nsTArray<AudioDataValue>&& 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<void>& 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<long>(static_cast<float>(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<MockCubeb*>(aContext);
- MOZ_ASSERT(!mockCubeb->mDestroyed);
+ MOZ_RELEASE_ASSERT(!mockCubeb->mDestroyed);
return mockCubeb;
}
@@ -528,6 +626,28 @@ int MockCubeb::RegisterDeviceCollectionChangeCallback(
return CUBEB_OK;
}
+Result<cubeb_input_processing_params, int>
+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<ForcedAudioThreadPromise> {
- MOZ_ASSERT(mRunningMode == RunningMode::Automatic);
+ MOZ_RELEASE_ASSERT(mRunningMode == RunningMode::Automatic);
RefPtr<ForcedAudioThreadPromise> p =
mForcedAudioThreadPromise.Ensure(__func__);
mForcedAudioThread = true;
@@ -627,7 +747,7 @@ auto MockCubeb::ForceAudioThread() -> RefPtr<ForcedAudioThreadPromise> {
}
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.