mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-11 18:34:58 +01:00
BugFix: correctly wait for Mixer to save file on exit
On the way, also improved Connection Manager ending properly.
This commit is contained in:
@@ -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,39 +48,43 @@ bool Connection::init()
|
|||||||
// add default info for myself
|
// add default info for myself
|
||||||
connections_.push_back(ConnectionInfo());
|
connections_.push_back(ConnectionInfo());
|
||||||
|
|
||||||
// try to open a socket at base handshake port
|
if (receiver_ == nullptr) {
|
||||||
int trial = 0;
|
// try to open a socket at base handshake port
|
||||||
while (trial < MAX_HANDSHAKE) {
|
int trial = 0;
|
||||||
try {
|
while (trial < MAX_HANDSHAKE) {
|
||||||
// increment the port to have unique ports
|
try {
|
||||||
connections_[0].port_handshake = HANDSHAKE_PORT + trial;
|
// increment the port to have unique ports
|
||||||
connections_[0].port_stream_request = STREAM_REQUEST_PORT + trial;
|
connections_[0].port_handshake = HANDSHAKE_PORT + trial;
|
||||||
connections_[0].port_osc = OSC_DIALOG_PORT + trial;
|
connections_[0].port_stream_request = STREAM_REQUEST_PORT + trial;
|
||||||
|
connections_[0].port_osc = OSC_DIALOG_PORT + trial;
|
||||||
|
|
||||||
// try to create listenning socket
|
// try to create listenning socket
|
||||||
// through exception runtime if fails
|
// through exception runtime if fails
|
||||||
receiver_ = new UdpListeningReceiveSocket( IpEndpointName( IpEndpointName::ANY_ADDRESS,
|
receiver_ = new UdpListeningReceiveSocket( IpEndpointName( IpEndpointName::ANY_ADDRESS,
|
||||||
connections_[0].port_handshake ), &listener_ );
|
connections_[0].port_handshake ), &listener_ );
|
||||||
// validate hostname
|
// validate hostname
|
||||||
connections_[0].name = APP_NAME "@" + NetworkToolkit::hostname() +
|
connections_[0].name = APP_NAME "@" + NetworkToolkit::hostname() +
|
||||||
"." + std::to_string(connections_[0].port_handshake-HANDSHAKE_PORT);
|
"." + std::to_string(connections_[0].port_handshake-HANDSHAKE_PORT);
|
||||||
// all good
|
// all good
|
||||||
trial = MAX_HANDSHAKE;
|
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
|
// 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++)
|
||||||
@@ -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,
|
||||||
|
|||||||
@@ -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_;
|
||||||
|
|||||||
12
Mixer.cpp
12
Mixer.cpp
@@ -105,9 +105,9 @@ 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
|
|
||||||
sessionImporters_.pop_back();
|
|
||||||
}
|
}
|
||||||
|
// done with this session loader
|
||||||
|
sessionImporters_.pop_back();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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
|
|
||||||
sessionLoaders_.pop_back();
|
|
||||||
}
|
}
|
||||||
|
// done with this session loader
|
||||||
|
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
|
|
||||||
sessionSavers_.pop_back();
|
|
||||||
}
|
}
|
||||||
|
// done with this session saver
|
||||||
|
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
|
||||||
|
|||||||
22
Streamer.cpp
22
Streamer.cpp
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
// always stop all recordings
|
||||||
|
FrameGrabbing::manager().stopAll();
|
||||||
|
|
||||||
// force close if trying to close again although it is already pending for save
|
// force close if trying to close again although it is already pending for save
|
||||||
if (pending_save_on_exit) {
|
if (pending_save_on_exit)
|
||||||
close_and_exit = true;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
// determine if a pending save of session is required
|
// save on exit
|
||||||
pending_save_on_exit = ( Settings::application.recentSessions.save_on_exit
|
pending_save_on_exit = false;
|
||||||
&& !Mixer::manager().session()->empty()
|
if (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
|
// determine if a pending save of session is required
|
||||||
FrameGrabbing::manager().stopAll();
|
if (Mixer::manager().session()->filename().empty())
|
||||||
|
// need to wait for user to give a filename
|
||||||
// save on exit
|
pending_save_on_exit = true;
|
||||||
if (Settings::application.recentSessions.save_on_exit)
|
else
|
||||||
|
// ok to save the session
|
||||||
Mixer::manager().save(false);
|
Mixer::manager().save(false);
|
||||||
|
|
||||||
close_and_exit = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
6
main.cpp
6
main.cpp
@@ -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
|
||||||
///
|
///
|
||||||
|
|||||||
Reference in New Issue
Block a user