From 4e461f875509678cd004d635ee2267a4ea99d20a Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Mon, 27 Aug 2018 15:30:06 -0400 Subject: [PATCH] Explicit scrub shut-down signal replaces the "nudge" --- src/AudioIO.cpp | 52 +++++++++++++++++++++---------------- src/AudioIO.h | 2 ++ src/tracks/ui/Scrubbing.cpp | 5 ++-- src/tracks/ui/Scrubbing.h | 2 ++ 4 files changed, 36 insertions(+), 25 deletions(-) diff --git a/src/AudioIO.cpp b/src/AudioIO.cpp index d392e9fad..dab9d3525 100644 --- a/src/AudioIO.cpp +++ b/src/AudioIO.cpp @@ -549,15 +549,6 @@ struct AudioIO::ScrubState } } - // This is for avoiding deadlocks while starting a scrub: - // Audio stream needs to be unblocked - void Nudge() - { - wxMutexLocker locker(mUpdating); - mNudged = true; - mAvailable.Signal(); - } - bool Update(double end, const ScrubbingOptions &options) { // Main thread indicates a scrubbing interval @@ -617,14 +608,14 @@ struct AudioIO::ScrubState if (!cleanup) { cleanup.create(mUpdating); } - while(!mNudged && mMiddleIdx == mLeadingIdx) + while(! mStopped.load( std::memory_order_relaxed )&& + mMiddleIdx == mLeadingIdx) mAvailable.Wait(); - mNudged = false; - auto now = ::wxGetLocalTimeMillis(); - if (mMiddleIdx != mLeadingIdx) { + if ( ! mStopped.load( std::memory_order_relaxed ) && + mMiddleIdx != mLeadingIdx ) { Data &entry = mEntries[mMiddleIdx]; if (entry.mDuration > 0) { // First use of the entry @@ -646,11 +637,18 @@ struct AudioIO::ScrubState } } else { - // We got the shut-down signal, or we got nudged, or we discarded all the work. + // We got the shut-down signal, or we discarded all the work. startSample = endSample = duration = -1L; } } + void Stop() + { + mStopped.store( true, std::memory_order_relaxed ); + wxMutexLocker locker(mUpdating); + mAvailable.Signal(); + } + double LastTrackTime() const { // Needed by the main thread sometimes @@ -832,12 +830,12 @@ private: unsigned mTrailingIdx; unsigned mMiddleIdx; unsigned mLeadingIdx; + std::atomic mStopped { false }; const double mRate; wxLongLong mLastScrubTimeMillis; mutable wxMutex mUpdating; mutable wxCondition mAvailable { mUpdating }; - bool mNudged { false }; }; #endif @@ -2006,9 +2004,17 @@ int AudioIO::StartStream(const TransportTracks &tracks, mAudioThreadShouldCallFillBuffersOnce = true; while( mAudioThreadShouldCallFillBuffersOnce ) { - if (mScrubState) - mScrubState->Nudge(); - wxMilliSleep( 50 ); +#ifndef USE_SCRUB_THREAD + // Yuck, we either have to poll "by hand" when scrub polling doesn't + // work with a thread, or else yield to timer messages, but that would + // execute too much else + if (mScrubState) { + mOwningProject->GetScrubber().ContinueScrubbingPoll(); + wxMilliSleep( Scrubber::ScrubPollInterval_ms ); + } + else +#endif + wxMilliSleep( 50 ); } if(mNumPlaybackChannels > 0 || mNumCaptureChannels > 0) { @@ -2513,8 +2519,6 @@ void AudioIO::StopStream() // mAudioThreadFillBuffersLoopRunning = false; - if (mScrubState) - mScrubState->Nudge(); // Audacity can deadlock if it tries to update meters while // we're stopping PortAudio (because the meter updating code @@ -2622,8 +2626,6 @@ void AudioIO::StopStream() { // LLL: Experienced recursive yield here...once. wxGetApp().Yield(true); // Pass true for onlyIfNeeded to avoid recursive call error. - if (mScrubState) - mScrubState->Nudge(); wxMilliSleep( 50 ); } @@ -2768,6 +2770,12 @@ bool AudioIO::UpdateScrub return false; } +void AudioIO::StopScrub() +{ + if (mScrubState) + mScrubState->Stop(); +} + double AudioIO::GetLastScrubTime() const { if (mScrubState) diff --git a/src/AudioIO.h b/src/AudioIO.h index 33145598e..47497b138 100644 --- a/src/AudioIO.h +++ b/src/AudioIO.h @@ -261,6 +261,8 @@ class AUDACITY_DLL_API AudioIO final { */ bool UpdateScrub(double endTimeOrSpeed, const ScrubbingOptions &options); + void StopScrub(); + /** \brief return the ending time of the last scrub interval. */ double GetLastScrubTime() const; diff --git a/src/tracks/ui/Scrubbing.cpp b/src/tracks/ui/Scrubbing.cpp index 46eff33e4..221b54892 100644 --- a/src/tracks/ui/Scrubbing.cpp +++ b/src/tracks/ui/Scrubbing.cpp @@ -51,9 +51,7 @@ enum { ScrubSpeedStepsPerOctave = 4, #endif - ScrubPollInterval_ms = 50, - - kOneSecondCountdown = 1000 / ScrubPollInterval_ms, + kOneSecondCountdown = 1000 / Scrubber::ScrubPollInterval_ms, }; static const double MinStutter = 0.2; @@ -657,6 +655,7 @@ void Scrubber::StopPolling() void Scrubber::StopScrubbing() { + gAudioIO->StopScrub(); StopPolling(); if (HasMark() && !mCancelled) { diff --git a/src/tracks/ui/Scrubbing.h b/src/tracks/ui/Scrubbing.h index 86a40b41e..b571e5875 100644 --- a/src/tracks/ui/Scrubbing.h +++ b/src/tracks/ui/Scrubbing.h @@ -72,6 +72,8 @@ struct ScrubbingOptions { class Scrubber : public wxEvtHandler { public: + static constexpr unsigned ScrubPollInterval_ms = 50; + Scrubber(AudacityProject *project); ~Scrubber();