diff --git a/src/DBConnection.cpp b/src/DBConnection.cpp index d43a389d9..6e12c5c50 100644 --- a/src/DBConnection.cpp +++ b/src/DBConnection.cpp @@ -21,10 +21,6 @@ Paul Licameli -- split from ProjectFileIO.cpp #include "FileException.h" #include "wxFileNameWrapper.h" -#include "./commands/CommandContext.h" -#include "./ProjectAudioManager.h" - - // Configuration to provide "safe" connections static const char *SafeConfig = "PRAGMA .locking_mode = SHARED;" @@ -40,9 +36,11 @@ static const char *FastConfig = DBConnection::DBConnection( const std::weak_ptr &pProject, - const std::shared_ptr &pErrors) + const std::shared_ptr &pErrors, + CheckpointFailureCallback callback) : mpProject{ pProject } , mpErrors{ pErrors } +, mCallback{ std::move(callback) } { mDB = nullptr; mBypass = false; @@ -284,12 +282,6 @@ sqlite3_stmt *DBConnection::GetStatement(enum StatementID id) } -void OnStopAudio() -{ - ProjectAudioManager::Get( *GetActiveProject() ).Stop(); -} - - void DBConnection::CheckpointThread() { // Open another connection to the DB to prevent blocking the main thread. @@ -367,9 +359,10 @@ void DBConnection::CheckpointThread() throw SimpleMessageBoxException{ message, XO("Warning"), "Error:_Disk_full_or_not_writable" }; }, SimpleGuard{}, - [&](AudacityException * e) { + [this](AudacityException * e) { // This executes in the main thread. - OnStopAudio(); + if (mCallback) + mCallback(); if (e) e->DelayedHandlerAction(); } diff --git a/src/DBConnection.h b/src/DBConnection.h index 0ec248ee1..61d8dfaaa 100644 --- a/src/DBConnection.h +++ b/src/DBConnection.h @@ -14,6 +14,7 @@ Paul Licameli -- split from ProjectFileIO.h #include #include +#include #include #include #include @@ -35,10 +36,14 @@ struct DBConnectionErrors class DBConnection { public: + // Type of function invoked in the main thread after detection of + // checkpoint failure, which might have been in a worker thread + using CheckpointFailureCallback = std::function; DBConnection( const std::weak_ptr &pProject, - const std::shared_ptr &pErrors); + const std::shared_ptr &pErrors, + CheckpointFailureCallback callback); ~DBConnection(); bool Open(const char *fileName); @@ -107,6 +112,7 @@ private: std::map mStatements; std::shared_ptr mpErrors; + CheckpointFailureCallback mCallback; // Bypass transactions if database will be deleted after close bool mBypass; diff --git a/src/ProjectAudioManager.cpp b/src/ProjectAudioManager.cpp index 06bc85aaf..6508600cd 100644 --- a/src/ProjectAudioManager.cpp +++ b/src/ProjectAudioManager.cpp @@ -65,6 +65,8 @@ ProjectAudioManager::ProjectAudioManager( AudacityProject &project ) { static ProjectStatus::RegisteredStatusWidthFunction registerStatusWidthFunction{ StatusWidthFunction }; + project.Bind( EVT_CHECKPOINT_FAILURE, + &ProjectAudioManager::OnCheckpointFailure, this ); } ProjectAudioManager::~ProjectAudioManager() = default; @@ -953,6 +955,12 @@ void ProjectAudioManager::OnSoundActivationThreshold() } } +void ProjectAudioManager::OnCheckpointFailure(wxCommandEvent &evt) +{ + evt.Skip(); + Stop(); +} + bool ProjectAudioManager::Playing() const { auto gAudioIO = AudioIO::Get(); diff --git a/src/ProjectAudioManager.h b/src/ProjectAudioManager.h index 4d56766ad..2a76ef026 100644 --- a/src/ProjectAudioManager.h +++ b/src/ProjectAudioManager.h @@ -140,6 +140,8 @@ private: void OnCommitRecording() override; void OnSoundActivationThreshold() override; + void OnCheckpointFailure(wxCommandEvent &evt); + AudacityProject &mProject; std::shared_ptr mCutPreviewTracks; diff --git a/src/ProjectFileIO.cpp b/src/ProjectFileIO.cpp index 5f05a185d..ff8fa4ca8 100644 --- a/src/ProjectFileIO.cpp +++ b/src/ProjectFileIO.cpp @@ -43,6 +43,7 @@ Paul Licameli split from AudacityProject.cpp #endif wxDEFINE_EVENT(EVT_PROJECT_TITLE_CHANGE, wxCommandEvent); +wxDEFINE_EVENT( EVT_CHECKPOINT_FAILURE, wxCommandEvent); static const int ProjectFileID = ('A' << 24 | 'U' << 16 | 'D' << 8 | 'Y'); static const int ProjectFileVersion = 1; @@ -320,7 +321,7 @@ bool ProjectFileIO::OpenConnection(FilePath fileName /* = {} */) // Pass weak_ptr to project into DBConnection constructor curConn = std::make_unique( - mProject.shared_from_this(), mpErrors); + mProject.shared_from_this(), mpErrors, [this]{ OnCheckpointFailure(); } ); if (!curConn->Open(fileName)) { curConn.reset(); @@ -1423,6 +1424,12 @@ XMLTagHandler *ProjectFileIO::HandleXMLChild(const wxChar *tag) return nullptr; } +void ProjectFileIO::OnCheckpointFailure() +{ + wxCommandEvent evt{ EVT_CHECKPOINT_FAILURE }; + mProject.ProcessEvent(evt); +} + void ProjectFileIO::WriteXMLHeader(XMLWriter &xmlFile) const { xmlFile.Write(wxT("( - mProject.shared_from_this(), mpErrors); + mProject.shared_from_this(), mpErrors, + [this]{ OnCheckpointFailure(); }); // NOTE: There is a noticeable delay here when dealing with large multi-hour // projects that we just created. The delay occurs in Open() when it diff --git a/src/ProjectFileIO.h b/src/ProjectFileIO.h index 0829af196..f4c118bd1 100644 --- a/src/ProjectFileIO.h +++ b/src/ProjectFileIO.h @@ -40,6 +40,11 @@ using Connection = std::unique_ptr; using BlockIDs = std::unordered_set; +// An event processed by the project in the main thread after a checkpoint +// failure was detected in a worker thread +wxDECLARE_EXPORTED_EVENT( AUDACITY_DLL_API, + EVT_CHECKPOINT_FAILURE, wxCommandEvent ); + ///\brief Object associated with a project that manages reading and writing /// of Audacity project file formats, and autosave class ProjectFileIO final @@ -177,6 +182,8 @@ public: DBConnection &GetConnection(); private: + void OnCheckpointFailure(); + void WriteXMLHeader(XMLWriter &xmlFile) const; void WriteXML(XMLWriter &xmlFile, bool recording = false, const TrackList *tracks = nullptr) /* not override */;