1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-08-01 08:29:27 +02:00

Explicit scrub shut-down signal replaces the "nudge"

This commit is contained in:
Paul Licameli 2018-08-27 15:30:06 -04:00
parent 303ac9367a
commit 4e461f8755
4 changed files with 36 additions and 25 deletions

View File

@ -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) bool Update(double end, const ScrubbingOptions &options)
{ {
// Main thread indicates a scrubbing interval // Main thread indicates a scrubbing interval
@ -617,14 +608,14 @@ struct AudioIO::ScrubState
if (!cleanup) { if (!cleanup) {
cleanup.create(mUpdating); cleanup.create(mUpdating);
} }
while(!mNudged && mMiddleIdx == mLeadingIdx) while(! mStopped.load( std::memory_order_relaxed )&&
mMiddleIdx == mLeadingIdx)
mAvailable.Wait(); mAvailable.Wait();
mNudged = false;
auto now = ::wxGetLocalTimeMillis(); auto now = ::wxGetLocalTimeMillis();
if (mMiddleIdx != mLeadingIdx) { if ( ! mStopped.load( std::memory_order_relaxed ) &&
mMiddleIdx != mLeadingIdx ) {
Data &entry = mEntries[mMiddleIdx]; Data &entry = mEntries[mMiddleIdx];
if (entry.mDuration > 0) { if (entry.mDuration > 0) {
// First use of the entry // First use of the entry
@ -646,11 +637,18 @@ struct AudioIO::ScrubState
} }
} }
else { 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; startSample = endSample = duration = -1L;
} }
} }
void Stop()
{
mStopped.store( true, std::memory_order_relaxed );
wxMutexLocker locker(mUpdating);
mAvailable.Signal();
}
double LastTrackTime() const double LastTrackTime() const
{ {
// Needed by the main thread sometimes // Needed by the main thread sometimes
@ -832,12 +830,12 @@ private:
unsigned mTrailingIdx; unsigned mTrailingIdx;
unsigned mMiddleIdx; unsigned mMiddleIdx;
unsigned mLeadingIdx; unsigned mLeadingIdx;
std::atomic<bool> mStopped { false };
const double mRate; const double mRate;
wxLongLong mLastScrubTimeMillis; wxLongLong mLastScrubTimeMillis;
mutable wxMutex mUpdating; mutable wxMutex mUpdating;
mutable wxCondition mAvailable { mUpdating }; mutable wxCondition mAvailable { mUpdating };
bool mNudged { false };
}; };
#endif #endif
@ -2006,9 +2004,17 @@ int AudioIO::StartStream(const TransportTracks &tracks,
mAudioThreadShouldCallFillBuffersOnce = true; mAudioThreadShouldCallFillBuffersOnce = true;
while( mAudioThreadShouldCallFillBuffersOnce ) { while( mAudioThreadShouldCallFillBuffersOnce ) {
if (mScrubState) #ifndef USE_SCRUB_THREAD
mScrubState->Nudge(); // Yuck, we either have to poll "by hand" when scrub polling doesn't
wxMilliSleep( 50 ); // 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) { if(mNumPlaybackChannels > 0 || mNumCaptureChannels > 0) {
@ -2513,8 +2519,6 @@ void AudioIO::StopStream()
// //
mAudioThreadFillBuffersLoopRunning = false; mAudioThreadFillBuffersLoopRunning = false;
if (mScrubState)
mScrubState->Nudge();
// Audacity can deadlock if it tries to update meters while // Audacity can deadlock if it tries to update meters while
// we're stopping PortAudio (because the meter updating code // we're stopping PortAudio (because the meter updating code
@ -2622,8 +2626,6 @@ void AudioIO::StopStream()
{ {
// LLL: Experienced recursive yield here...once. // LLL: Experienced recursive yield here...once.
wxGetApp().Yield(true); // Pass true for onlyIfNeeded to avoid recursive call error. wxGetApp().Yield(true); // Pass true for onlyIfNeeded to avoid recursive call error.
if (mScrubState)
mScrubState->Nudge();
wxMilliSleep( 50 ); wxMilliSleep( 50 );
} }
@ -2768,6 +2770,12 @@ bool AudioIO::UpdateScrub
return false; return false;
} }
void AudioIO::StopScrub()
{
if (mScrubState)
mScrubState->Stop();
}
double AudioIO::GetLastScrubTime() const double AudioIO::GetLastScrubTime() const
{ {
if (mScrubState) if (mScrubState)

View File

@ -261,6 +261,8 @@ class AUDACITY_DLL_API AudioIO final {
*/ */
bool UpdateScrub(double endTimeOrSpeed, const ScrubbingOptions &options); bool UpdateScrub(double endTimeOrSpeed, const ScrubbingOptions &options);
void StopScrub();
/** \brief return the ending time of the last scrub interval. /** \brief return the ending time of the last scrub interval.
*/ */
double GetLastScrubTime() const; double GetLastScrubTime() const;

View File

@ -51,9 +51,7 @@ enum {
ScrubSpeedStepsPerOctave = 4, ScrubSpeedStepsPerOctave = 4,
#endif #endif
ScrubPollInterval_ms = 50, kOneSecondCountdown = 1000 / Scrubber::ScrubPollInterval_ms,
kOneSecondCountdown = 1000 / ScrubPollInterval_ms,
}; };
static const double MinStutter = 0.2; static const double MinStutter = 0.2;
@ -657,6 +655,7 @@ void Scrubber::StopPolling()
void Scrubber::StopScrubbing() void Scrubber::StopScrubbing()
{ {
gAudioIO->StopScrub();
StopPolling(); StopPolling();
if (HasMark() && !mCancelled) { if (HasMark() && !mCancelled) {

View File

@ -72,6 +72,8 @@ struct ScrubbingOptions {
class Scrubber : public wxEvtHandler class Scrubber : public wxEvtHandler
{ {
public: public:
static constexpr unsigned ScrubPollInterval_ms = 50;
Scrubber(AudacityProject *project); Scrubber(AudacityProject *project);
~Scrubber(); ~Scrubber();