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)
{
// 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<bool> 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)

View File

@ -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;

View File

@ -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) {

View File

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