From ece7e04c7ccdcc887378bc4bbc85e9e3d8fe951e Mon Sep 17 00:00:00 2001 From: Bruno Date: Mon, 17 Jan 2022 19:45:58 +0100 Subject: [PATCH] BugFix: correctly wait for Mixer to save file on exit On the way, also improved Connection Manager ending properly. --- Connection.cpp | 88 +++++++++++++++++++++++++--------------- Connection.h | 4 ++ Mixer.cpp | 12 +++--- Streamer.cpp | 22 +++++----- UserInterfaceManager.cpp | 50 +++++++---------------- UserInterfaceManager.h | 1 - main.cpp | 6 +++ 7 files changed, 98 insertions(+), 85 deletions(-) diff --git a/Connection.cpp b/Connection.cpp index 79446c9..2662720 100644 --- a/Connection.cpp +++ b/Connection.cpp @@ -35,16 +35,12 @@ #endif -Connection::Connection() : receiver_(nullptr) +Connection::Connection() : asking_(false), receiver_(nullptr) { } Connection::~Connection() { - if (receiver_!=nullptr) { - receiver_->Break(); - delete receiver_; - } } bool Connection::init() @@ -52,39 +48,43 @@ bool Connection::init() // add default info for myself connections_.push_back(ConnectionInfo()); - // try to open a socket at base handshake port - int trial = 0; - while (trial < MAX_HANDSHAKE) { - try { - // increment the port to have unique ports - connections_[0].port_handshake = HANDSHAKE_PORT + trial; - connections_[0].port_stream_request = STREAM_REQUEST_PORT + trial; - connections_[0].port_osc = OSC_DIALOG_PORT + trial; + if (receiver_ == nullptr) { + // try to open a socket at base handshake port + int trial = 0; + while (trial < MAX_HANDSHAKE) { + try { + // increment the port to have unique ports + connections_[0].port_handshake = HANDSHAKE_PORT + trial; + connections_[0].port_stream_request = STREAM_REQUEST_PORT + trial; + connections_[0].port_osc = OSC_DIALOG_PORT + trial; - // try to create listenning socket - // through exception runtime if fails - receiver_ = new UdpListeningReceiveSocket( IpEndpointName( IpEndpointName::ANY_ADDRESS, - connections_[0].port_handshake ), &listener_ ); - // validate hostname - connections_[0].name = APP_NAME "@" + NetworkToolkit::hostname() + - "." + std::to_string(connections_[0].port_handshake-HANDSHAKE_PORT); - // all good - trial = MAX_HANDSHAKE; + // try to create listenning socket + // through exception runtime if fails + receiver_ = new UdpListeningReceiveSocket( IpEndpointName( IpEndpointName::ANY_ADDRESS, + connections_[0].port_handshake ), &listener_ ); + // validate hostname + connections_[0].name = APP_NAME "@" + NetworkToolkit::hostname() + + "." + std::to_string(connections_[0].port_handshake-HANDSHAKE_PORT); + // all good + trial = MAX_HANDSHAKE; + } + catch (const std::runtime_error&) { + // arg, the receiver could not be initialized + // because the port was not available + receiver_ = nullptr; + } + // try again + trial++; } - catch (const std::runtime_error&) { - // arg, the receiver could not be initialized - // because the port was not available - receiver_ = nullptr; - } - // try again - trial++; } // perfect, we could initialize the receiver if (receiver_!=nullptr) { // listen for answers std::thread(listen).detach(); + // regularly check for available streaming hosts + asking_ = true; std::thread(ask).detach(); // inform the application settings of our id @@ -104,10 +104,31 @@ bool Connection::init() void Connection::terminate() { - if (receiver_!=nullptr) + // end ask loop + std::mutex mtx; + std::unique_lock lck(mtx); + asking_ = false; + if ( ask_end_.wait_for(lck,std::chrono::seconds(2)) == std::cv_status::timeout) + g_printerr("Failed to terminate Connection manager (asker)."); + + // end receiver + if (receiver_!=nullptr) { + + // request termination of receiver receiver_->AsynchronousBreak(); - // restore state of Streamer + // wait for the listenner end notification + std::mutex mtx; + std::unique_lock lck(mtx); + if ( listen_end_.wait_for(lck,std::chrono::seconds(2)) == std::cv_status::timeout) + g_printerr("Failed to terminate Connection manager (listener)."); + + // delete receiver and ready to initialize + delete receiver_; + receiver_ = nullptr; + } + + // end Streamers Streaming::manager().enable( false ); } @@ -175,6 +196,8 @@ void Connection::listen() #endif if (Connection::manager().receiver_) Connection::manager().receiver_->Run(); + + Connection::manager().listen_end_.notify_all(); } void Connection::ask() @@ -191,7 +214,7 @@ void Connection::ask() socket.SetEnableBroadcast(true); // loop infinitely - while(true) + while(Connection::manager().asking_) { // broadcast on several ports for(int i=HANDSHAKE_PORT; i #include +#include #include "NetworkToolkit.h" @@ -86,8 +87,11 @@ protected: private: static void ask(); + std::atomic asking_; + std::condition_variable ask_end_; static void listen(); RequestListener listener_; + std::condition_variable listen_end_; UdpListeningReceiveSocket *receiver_; std::vector< ConnectionInfo > connections_; diff --git a/Mixer.cpp b/Mixer.cpp index 3ba4c86..f1fcb21 100644 --- a/Mixer.cpp +++ b/Mixer.cpp @@ -105,9 +105,9 @@ void Mixer::update() // get the session loaded by this loader merge( sessionImporters_.back().get() ); // FIXME: shouldn't we delete the imported session? - // done with this session loader - sessionImporters_.pop_back(); } + // done with this session loader + sessionImporters_.pop_back(); } } @@ -119,9 +119,9 @@ void Mixer::update() if (sessionLoaders_.back().valid()) { // get the session loaded by this loader set( sessionLoaders_.back().get() ); - // done with this session loader - sessionLoaders_.pop_back(); } + // done with this session loader + sessionLoaders_.pop_back(); busy_ = false; } } @@ -135,9 +135,9 @@ void Mixer::update() // did we get a filename in return? if (sessionSavers_.back().valid()) { filename = sessionSavers_.back().get(); - // done with this session saver - sessionSavers_.pop_back(); } + // done with this session saver + sessionSavers_.pop_back(); if (filename.empty()) Log::Warning("Failed to save Session."); // all ok diff --git a/Streamer.cpp b/Streamer.cpp index 8b952cf..d366961 100644 --- a/Streamer.cpp +++ b/Streamer.cpp @@ -118,11 +118,12 @@ bool Streaming::busy() { bool b = false; - streamers_lock_.lock(); - std::vector::const_iterator sit = streamers_.begin(); - for (; sit != streamers_.end() && !b; ++sit) - b = (*sit)->busy() ; - streamers_lock_.unlock(); + if (streamers_lock_.try_lock()) { + std::vector::const_iterator sit = streamers_.begin(); + for (; sit != streamers_.end() && !b; ++sit) + b = (*sit)->busy() ; + streamers_lock_.unlock(); + } return b; } @@ -132,11 +133,12 @@ std::vector Streaming::listStreams() { std::vector ls; - streamers_lock_.lock(); - std::vector::const_iterator sit = streamers_.begin(); - for (; sit != streamers_.end(); ++sit) - ls.push_back( (*sit)->info() ); - streamers_lock_.unlock(); + if (streamers_lock_.try_lock()) { + std::vector::const_iterator sit = streamers_.begin(); + for (; sit != streamers_.end(); ++sit) + ls.push_back( (*sit)->info() ); + streamers_lock_.unlock(); + } return ls; } diff --git a/UserInterfaceManager.cpp b/UserInterfaceManager.cpp index 4a92ff5..781b40a 100644 --- a/UserInterfaceManager.cpp +++ b/UserInterfaceManager.cpp @@ -141,7 +141,6 @@ UserInterface::UserInterface() currentTextEdit.clear(); screenshot_step = 0; pending_save_on_exit = false; - close_and_exit = false; sessionopendialog = nullptr; sessionimportdialog = nullptr; @@ -154,7 +153,6 @@ bool UserInterface::Init() return false; pending_save_on_exit = false; - close_and_exit = false; // Setup Dear ImGui context IMGUI_CHECKVERSION(); @@ -685,28 +683,24 @@ bool UserInterface::TryClose() if (DialogToolkit::FileDialog::busy()) return false; + // always stop all recordings + FrameGrabbing::manager().stopAll(); + // force close if trying to close again although it is already pending for save - if (pending_save_on_exit) { - close_and_exit = true; + if (pending_save_on_exit) return true; - } - // determine if a pending save of session is required - pending_save_on_exit = ( Settings::application.recentSessions.save_on_exit - && !Mixer::manager().session()->empty() - && Mixer::manager().session()->filename().empty() ); - - // if no pending save of session is needed, close - if (!pending_save_on_exit) + // save on exit + pending_save_on_exit = false; + if (Settings::application.recentSessions.save_on_exit && !Mixer::manager().session()->empty()) { - // stop all recordings - FrameGrabbing::manager().stopAll(); - - // save on exit - if (Settings::application.recentSessions.save_on_exit) + // determine if a pending save of session is required + if (Mixer::manager().session()->filename().empty()) + // need to wait for user to give a filename + pending_save_on_exit = true; + else + // ok to save the session Mixer::manager().save(false); - - close_and_exit = true; } // say we can close if no pending save of session is needed @@ -784,8 +778,7 @@ void UserInterface::NewFrame() ImGui::CloseCurrentPopup(); } if (ImGui::Button(MENU_QUIT, ImVec2(ImGui::GetWindowContentRegionWidth(), 0))) { - pending_save_on_exit = false; - close_and_exit = true; + Rendering::manager().close(); ImGui::CloseCurrentPopup(); } ImGui::Spacing(); @@ -793,21 +786,6 @@ void UserInterface::NewFrame() } } - // Asked to close_and_exit - if (close_and_exit){ - if (!ImGui::IsPopupOpen("Closing")) - ImGui::OpenPopup("Closing"); - if (ImGui::BeginPopupModal("Closing", NULL, ImGuiWindowFlags_AlwaysAutoResize)) { - ImGui::Text("Please wait..."); - ImGui::EndPopup(); - } - - // exit only after everything is closed - if (!FrameGrabbing::manager().busy() && !Mixer::manager().busy()) { - Rendering::manager().close(); - } - } - // navigator bar first navigator.Render(); } diff --git a/UserInterfaceManager.h b/UserInterfaceManager.h index d482737..128d5c9 100644 --- a/UserInterfaceManager.h +++ b/UserInterfaceManager.h @@ -405,7 +405,6 @@ protected: int target_view_navigator; unsigned int screenshot_step; bool pending_save_on_exit; - bool close_and_exit; // Dialogs DialogToolkit::OpenSessionDialog *sessionopendialog; diff --git a/main.cpp b/main.cpp index c539eb6..d6d029c 100644 --- a/main.cpp +++ b/main.cpp @@ -162,6 +162,12 @@ int main(int argc, char *argv[]) /// UserInterface::manager().Terminate(); + /// + /// MIXER TERMINATE + /// + while (Mixer::manager().busy()) + Mixer::manager().update(); + /// /// RENDERING TERMINATE ///