mirror of
https://github.com/cookiengineer/audacity
synced 2025-07-26 09:28:07 +02:00
Gracefully handle disk exhaustion exceptions during recording
This commit is contained in:
parent
f4e2fb5eac
commit
eeb301e50d
@ -1650,6 +1650,8 @@ int AudioIO::StartStream(const ConstWaveTrackArray &playbackTracks,
|
||||
double t0, double t1,
|
||||
const AudioIOStartStreamOptions &options)
|
||||
{
|
||||
auto cleanup = finally ( [this] { ClearRecordingException(); } );
|
||||
|
||||
if( IsBusy() )
|
||||
return 0;
|
||||
|
||||
@ -2250,6 +2252,8 @@ void AudioIO::SetMeters()
|
||||
|
||||
void AudioIO::StopStream()
|
||||
{
|
||||
auto cleanup = finally ( [this] { ClearRecordingException(); } );
|
||||
|
||||
if( mPortStreamV19 == NULL
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
&& mMidiStream == NULL
|
||||
@ -3420,6 +3424,25 @@ void AudioIO::FillBuffers()
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
auto delayedHandler = [this] ( AudacityException * pException ) {
|
||||
// In the main thread, stop recording
|
||||
// This is one place where the application handles disk
|
||||
// exhaustion exceptions from wave track operations, without rolling
|
||||
// back to the last pushed undo state. Instead, partial recording
|
||||
// results are pushed as a NEW undo state. For this reason, as
|
||||
// commented elsewhere, we want an exception safety guarantee for
|
||||
// the output wave tracks, after the failed append operation, that
|
||||
// the tracks remain as they were after the previous successful
|
||||
// (block-level) appends.
|
||||
|
||||
// Note that the Flush in StopStream() may throw another exception,
|
||||
// but StopStream() contains that exception, and the logic in
|
||||
// AudacityException::DelayedHandlerAction prevents redundant message
|
||||
// boxes.
|
||||
StopStream();
|
||||
DefaultDelayedHandlerAction{}( pException );
|
||||
};
|
||||
|
||||
if (mPlaybackTracks.size() > 0)
|
||||
{
|
||||
// Though extremely unlikely, it is possible that some buffers
|
||||
@ -3595,8 +3618,10 @@ void AudioIO::FillBuffers()
|
||||
}
|
||||
} // end of playback buffering
|
||||
|
||||
if (mCaptureTracks.size() > 0) // start record buffering
|
||||
{
|
||||
if (!mRecordingException &&
|
||||
mCaptureTracks.size() > 0)
|
||||
GuardedCall<void>( [&] {
|
||||
// start record buffering
|
||||
auto commonlyAvail = GetCommonlyAvailCapture();
|
||||
|
||||
//
|
||||
@ -3627,6 +3652,7 @@ void AudioIO::FillBuffers()
|
||||
// wxASSERT(got == avail);
|
||||
// but we can't assert in this thread
|
||||
wxUnusedVar(got);
|
||||
// see comment in second handler about guarantee
|
||||
mCaptureTracks[i]-> Append(temp.ptr(), trackFormat, avail, 1,
|
||||
&appendLog);
|
||||
}
|
||||
@ -3648,6 +3674,7 @@ void AudioIO::FillBuffers()
|
||||
mResample[i]->Process(mFactor, (float *)temp1.ptr(), avail,
|
||||
!IsStreamActive(), (float *)temp2.ptr(), size);
|
||||
size = results.second;
|
||||
// see comment in second handler about guarantee
|
||||
mCaptureTracks[i]-> Append(temp2.ptr(), floatSample, size, 1,
|
||||
&appendLog);
|
||||
}
|
||||
@ -3666,7 +3693,22 @@ void AudioIO::FillBuffers()
|
||||
if (mListener && !blockFileLog.IsEmpty())
|
||||
mListener->OnAudioIONewBlockFiles(blockFileLog);
|
||||
}
|
||||
} // end of record buffering
|
||||
// end of record buffering
|
||||
},
|
||||
// handler
|
||||
[this] ( AudacityException *pException ) {
|
||||
if ( pException ) {
|
||||
// So that we don't attempt to fill the recording buffer again
|
||||
// before the main thread stops recording
|
||||
SetRecordingException();
|
||||
return ;
|
||||
}
|
||||
else
|
||||
// Don't want to intercept other exceptions (?)
|
||||
throw;
|
||||
},
|
||||
delayedHandler
|
||||
);
|
||||
}
|
||||
|
||||
void AudioIO::SetListener(AudioIOListener* listener)
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include "MemoryX.h"
|
||||
#include <vector>
|
||||
#include <wx/atomic.h>
|
||||
|
||||
#ifdef USE_MIDI
|
||||
|
||||
@ -692,6 +693,14 @@ private:
|
||||
bool mSilentScrub;
|
||||
sampleCount mScrubDuration;
|
||||
#endif
|
||||
|
||||
// A flag tested and set in one thread, cleared in another. Perhaps
|
||||
// this guarantee of atomicity is more cautious than necessary.
|
||||
wxAtomicInt mRecordingException {};
|
||||
void SetRecordingException()
|
||||
{ wxAtomicInc( mRecordingException ); }
|
||||
void ClearRecordingException()
|
||||
{ if (mRecordingException) wxAtomicDec( mRecordingException ); }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user