BugFix: correctly wait for Mixer to save file on exit

On the way, also improved Connection Manager ending properly.
This commit is contained in:
Bruno
2022-01-17 19:45:58 +01:00
parent 81e8d6d99c
commit 0b4d273e08
7 changed files with 99 additions and 86 deletions

View File

@@ -35,16 +35,12 @@
#endif #endif
Connection::Connection() : receiver_(nullptr) Connection::Connection() : asking_(false), receiver_(nullptr)
{ {
} }
Connection::~Connection() Connection::~Connection()
{ {
if (receiver_!=nullptr) {
receiver_->Break();
delete receiver_;
}
} }
bool Connection::init() bool Connection::init()
@@ -52,6 +48,7 @@ bool Connection::init()
// add default info for myself // add default info for myself
connections_.push_back(ConnectionInfo()); connections_.push_back(ConnectionInfo());
if (receiver_ == nullptr) {
// try to open a socket at base handshake port // try to open a socket at base handshake port
int trial = 0; int trial = 0;
while (trial < MAX_HANDSHAKE) { while (trial < MAX_HANDSHAKE) {
@@ -79,12 +76,15 @@ bool Connection::init()
// try again // try again
trial++; trial++;
} }
}
// perfect, we could initialize the receiver // perfect, we could initialize the receiver
if (receiver_!=nullptr) { if (receiver_!=nullptr) {
// listen for answers // listen for answers
std::thread(listen).detach(); std::thread(listen).detach();
// regularly check for available streaming hosts // regularly check for available streaming hosts
asking_ = true;
std::thread(ask).detach(); std::thread(ask).detach();
// inform the application settings of our id // inform the application settings of our id
@@ -104,10 +104,31 @@ bool Connection::init()
void Connection::terminate() void Connection::terminate()
{ {
if (receiver_!=nullptr) // end ask loop
std::mutex mtx;
std::unique_lock<std::mutex> 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(); receiver_->AsynchronousBreak();
// restore state of Streamer // wait for the listenner end notification
std::mutex mtx;
std::unique_lock<std::mutex> 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 ); Streaming::manager().enable( false );
} }
@@ -175,6 +196,8 @@ void Connection::listen()
#endif #endif
if (Connection::manager().receiver_) if (Connection::manager().receiver_)
Connection::manager().receiver_->Run(); Connection::manager().receiver_->Run();
Connection::manager().listen_end_.notify_all();
} }
void Connection::ask() void Connection::ask()
@@ -191,7 +214,7 @@ void Connection::ask()
socket.SetEnableBroadcast(true); socket.SetEnableBroadcast(true);
// loop infinitely // loop infinitely
while(true) while(Connection::manager().asking_)
{ {
// broadcast on several ports // broadcast on several ports
for(int i=HANDSHAKE_PORT; i<HANDSHAKE_PORT+MAX_HANDSHAKE; i++) for(int i=HANDSHAKE_PORT; i<HANDSHAKE_PORT+MAX_HANDSHAKE; i++)
@@ -208,7 +231,7 @@ void Connection::ask()
// erase connection if its life score is negative (not responding too many times) // erase connection if its life score is negative (not responding too many times)
if ( (*it).alive < 0 ) { if ( (*it).alive < 0 ) {
// inform streamer to cancel streaming to this client // inform streamer to cancel streaming to this client
Streaming::manager().removeStreams( (*it).name ); // Streaming::manager().removeStreams( (*it).name );
// remove from list // remove from list
it = Connection::manager().connections_.erase(it); it = Connection::manager().connections_.erase(it);
#ifdef CONNECTION_DEBUG #ifdef CONNECTION_DEBUG
@@ -222,6 +245,7 @@ void Connection::ask()
} }
} }
Connection::manager().ask_end_.notify_all();
} }
void Connection::RequestListener::ProcessMessage( const osc::ReceivedMessage& m, void Connection::RequestListener::ProcessMessage( const osc::ReceivedMessage& m,

View File

@@ -3,6 +3,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <condition_variable>
#include "NetworkToolkit.h" #include "NetworkToolkit.h"
@@ -86,8 +87,11 @@ protected:
private: private:
static void ask(); static void ask();
std::atomic<bool> asking_;
std::condition_variable ask_end_;
static void listen(); static void listen();
RequestListener listener_; RequestListener listener_;
std::condition_variable listen_end_;
UdpListeningReceiveSocket *receiver_; UdpListeningReceiveSocket *receiver_;
std::vector< ConnectionInfo > connections_; std::vector< ConnectionInfo > connections_;

View File

@@ -105,11 +105,11 @@ void Mixer::update()
// get the session loaded by this loader // get the session loaded by this loader
merge( sessionImporters_.back().get() ); merge( sessionImporters_.back().get() );
// FIXME: shouldn't we delete the imported session? // FIXME: shouldn't we delete the imported session?
}
// done with this session loader // done with this session loader
sessionImporters_.pop_back(); sessionImporters_.pop_back();
} }
} }
}
// if there is a session loader pending // if there is a session loader pending
if (!sessionLoaders_.empty()) { if (!sessionLoaders_.empty()) {
@@ -119,9 +119,9 @@ void Mixer::update()
if (sessionLoaders_.back().valid()) { if (sessionLoaders_.back().valid()) {
// get the session loaded by this loader // get the session loaded by this loader
set( sessionLoaders_.back().get() ); set( sessionLoaders_.back().get() );
}
// done with this session loader // done with this session loader
sessionLoaders_.pop_back(); sessionLoaders_.pop_back();
}
busy_ = false; busy_ = false;
} }
} }
@@ -135,9 +135,9 @@ void Mixer::update()
// did we get a filename in return? // did we get a filename in return?
if (sessionSavers_.back().valid()) { if (sessionSavers_.back().valid()) {
filename = sessionSavers_.back().get(); filename = sessionSavers_.back().get();
}
// done with this session saver // done with this session saver
sessionSavers_.pop_back(); sessionSavers_.pop_back();
}
if (filename.empty()) if (filename.empty())
Log::Warning("Failed to save Session."); Log::Warning("Failed to save Session.");
// all ok // all ok

View File

@@ -118,11 +118,12 @@ bool Streaming::busy()
{ {
bool b = false; bool b = false;
streamers_lock_.lock(); if (streamers_lock_.try_lock()) {
std::vector<VideoStreamer *>::const_iterator sit = streamers_.begin(); std::vector<VideoStreamer *>::const_iterator sit = streamers_.begin();
for (; sit != streamers_.end() && !b; ++sit) for (; sit != streamers_.end() && !b; ++sit)
b = (*sit)->busy() ; b = (*sit)->busy() ;
streamers_lock_.unlock(); streamers_lock_.unlock();
}
return b; return b;
} }
@@ -132,11 +133,12 @@ std::vector<std::string> Streaming::listStreams()
{ {
std::vector<std::string> ls; std::vector<std::string> ls;
streamers_lock_.lock(); if (streamers_lock_.try_lock()) {
std::vector<VideoStreamer *>::const_iterator sit = streamers_.begin(); std::vector<VideoStreamer *>::const_iterator sit = streamers_.begin();
for (; sit != streamers_.end(); ++sit) for (; sit != streamers_.end(); ++sit)
ls.push_back( (*sit)->info() ); ls.push_back( (*sit)->info() );
streamers_lock_.unlock(); streamers_lock_.unlock();
}
return ls; return ls;
} }

View File

@@ -141,7 +141,6 @@ UserInterface::UserInterface()
currentTextEdit.clear(); currentTextEdit.clear();
screenshot_step = 0; screenshot_step = 0;
pending_save_on_exit = false; pending_save_on_exit = false;
close_and_exit = false;
sessionopendialog = nullptr; sessionopendialog = nullptr;
sessionimportdialog = nullptr; sessionimportdialog = nullptr;
@@ -154,7 +153,6 @@ bool UserInterface::Init()
return false; return false;
pending_save_on_exit = false; pending_save_on_exit = false;
close_and_exit = false;
// Setup Dear ImGui context // Setup Dear ImGui context
IMGUI_CHECKVERSION(); IMGUI_CHECKVERSION();
@@ -685,28 +683,24 @@ bool UserInterface::TryClose()
if (DialogToolkit::FileDialog::busy()) if (DialogToolkit::FileDialog::busy())
return false; return false;
// force close if trying to close again although it is already pending for save // always stop all recordings
if (pending_save_on_exit) {
close_and_exit = true;
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)
{
// stop all recordings
FrameGrabbing::manager().stopAll(); FrameGrabbing::manager().stopAll();
// save on exit // force close if trying to close again although it is already pending for save
if (Settings::application.recentSessions.save_on_exit) if (pending_save_on_exit)
Mixer::manager().save(false); return true;
close_and_exit = true; // save on exit
pending_save_on_exit = false;
if (Settings::application.recentSessions.save_on_exit && !Mixer::manager().session()->empty())
{
// 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);
} }
// say we can close if no pending save of session is needed // say we can close if no pending save of session is needed
@@ -784,8 +778,7 @@ void UserInterface::NewFrame()
ImGui::CloseCurrentPopup(); ImGui::CloseCurrentPopup();
} }
if (ImGui::Button(MENU_QUIT, ImVec2(ImGui::GetWindowContentRegionWidth(), 0))) { if (ImGui::Button(MENU_QUIT, ImVec2(ImGui::GetWindowContentRegionWidth(), 0))) {
pending_save_on_exit = false; Rendering::manager().close();
close_and_exit = true;
ImGui::CloseCurrentPopup(); ImGui::CloseCurrentPopup();
} }
ImGui::Spacing(); 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 bar first
navigator.Render(); navigator.Render();
} }

View File

@@ -405,7 +405,6 @@ protected:
int target_view_navigator; int target_view_navigator;
unsigned int screenshot_step; unsigned int screenshot_step;
bool pending_save_on_exit; bool pending_save_on_exit;
bool close_and_exit;
// Dialogs // Dialogs
DialogToolkit::OpenSessionDialog *sessionopendialog; DialogToolkit::OpenSessionDialog *sessionopendialog;

View File

@@ -162,6 +162,12 @@ int main(int argc, char *argv[])
/// ///
UserInterface::manager().Terminate(); UserInterface::manager().Terminate();
///
/// MIXER TERMINATE
///
while (Mixer::manager().busy())
Mixer::manager().update();
/// ///
/// RENDERING TERMINATE /// RENDERING TERMINATE
/// ///