From d5c754b58013ef929903ceea9db3345ee2086f72 Mon Sep 17 00:00:00 2001 From: Peter L Jones <peter@drealm.info> Date: Fri, 15 May 2020 20:01:57 +0100 Subject: [PATCH 1/3] Expanded signal handling --- src/server.cpp | 29 +++++++++++++++++++++++++---- src/server.h | 2 +- src/signalhandler.cpp | 8 +++++--- src/signalhandler.h | 4 ++-- 4 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/server.cpp b/src/server.cpp index 87af18bb..b6c7f3b2 100755 --- a/src/server.cpp +++ b/src/server.cpp @@ -471,8 +471,8 @@ CServer::CServer ( const int iNewMaxNumChan, this, SLOT ( OnAboutToQuit() ) ); QObject::connect ( pSignalHandler, - SIGNAL ( ShutdownSignal ( int ) ), - this, SLOT ( OnShutdown ( int ) ) ); + SIGNAL ( HandledSignal ( int ) ), + this, SLOT ( OnHandledSignal ( int ) ) ); connectChannelSignalsToServerSlots<MAX_NUM_CHANNELS>(); @@ -665,10 +665,31 @@ void CServer::OnAboutToQuit() } } -void CServer::OnShutdown ( int ) +void CServer::OnHandledSignal ( int sigNum ) { - // This should trigger OnAboutToQuit +#ifdef _WIN32 + + // Windows does not actually get OnHandledSignal triggered QCoreApplication::instance()->exit(); + Q_UNUSED ( sigNum ) + +#else + + switch ( sigNum ) + { + + case SIGINT: + case SIGTERM: + // This should trigger OnAboutToQuit + QCoreApplication::instance()->exit(); + break; + + default: + break; + + } + +#endif } void CServer::Start() diff --git a/src/server.h b/src/server.h index da38bc35..52633b4a 100755 --- a/src/server.h +++ b/src/server.h @@ -441,5 +441,5 @@ public slots: void OnAboutToQuit(); - void OnShutdown ( int ); + void OnHandledSignal ( int sigNum ); }; diff --git a/src/signalhandler.cpp b/src/signalhandler.cpp index 4c37d018..d0205c9e 100755 --- a/src/signalhandler.cpp +++ b/src/signalhandler.cpp @@ -75,7 +75,7 @@ CSignalHandler* CSignalHandler::getSingletonP() { return singleton; } bool CSignalHandler::emitSignal ( int sigNum ) { - return QMetaObject::invokeMethod( singleton, "ShutdownSignal", Qt::QueuedConnection, Q_ARG( int, sigNum ) ); + return QMetaObject::invokeMethod( singleton, "HandledSignal", Qt::QueuedConnection, Q_ARG( int, sigNum ) ); } #ifndef _WIN32 @@ -124,11 +124,11 @@ QReadWriteLock* CSignalWin::getLock() const return &lock; } -BOOL WINAPI CSignalWin::signalHandler ( _In_ DWORD sigNum ) +BOOL WINAPI CSignalWin::signalHandler ( _In_ DWORD ) { auto self = getSelf<CSignalWin>(); QReadLocker lock ( self->getLock() ); - return self->pSignalHandler->emitSignal ( static_cast<int>( sigNum ) ); + return self->pSignalHandler->emitSignal ( -1 ); } #else @@ -145,12 +145,14 @@ CSignalUnix::CSignalUnix ( CSignalHandler* nPSignalHandler ) : socketNotifier->setEnabled ( true ); + setSignalHandled ( SIGUSR1, true ); setSignalHandled ( SIGINT, true ); setSignalHandled ( SIGTERM, true ); } } CSignalUnix::~CSignalUnix() { + setSignalHandled ( SIGUSR1, false ); setSignalHandled ( SIGINT, false ); setSignalHandled ( SIGTERM, false ); } diff --git a/src/signalhandler.h b/src/signalhandler.h index 1263ee6a..59409d13 100755 --- a/src/signalhandler.h +++ b/src/signalhandler.h @@ -104,7 +104,7 @@ public slots: #endif signals: - void ShutdownSignal ( int sigNum ); + void HandledSignal ( int sigNum ); private: QScopedPointer<CSignalBase> pSignalBase; @@ -153,7 +153,7 @@ public: private: mutable QReadWriteLock lock; - static BOOL WINAPI signalHandler ( _In_ DWORD sigNum ); + static BOOL WINAPI signalHandler ( _In_ DWORD ); }; #else From 376ce88f76a4c3253951a8132e2f9246b0375d3a Mon Sep 17 00:00:00 2001 From: Peter L Jones <peter@drealm.info> Date: Fri, 15 May 2020 19:50:41 +0100 Subject: [PATCH 2/3] Recorder support for session cut --- src/recorder/jamrecorder.cpp | 51 ++++++++++++++++++++++++++++-------- src/recorder/jamrecorder.h | 42 +++++++++++++++++++---------- 2 files changed, 68 insertions(+), 25 deletions(-) diff --git a/src/recorder/jamrecorder.cpp b/src/recorder/jamrecorder.cpp index 2c817919..7719bd6d 100755 --- a/src/recorder/jamrecorder.cpp +++ b/src/recorder/jamrecorder.cpp @@ -322,13 +322,12 @@ void CJamRecorder::Init( const CServer* server, this, SLOT( OnDisconnected ( int ) ), Qt::ConnectionType::QueuedConnection ); - qRegisterMetaType<CVector<int16_t>>(); + qRegisterMetaType<CVector<int16_t>> ( "CVector<int16_t>" ); QObject::connect( (const QObject *)server, SIGNAL ( AudioFrame( const int, const QString, const CHostAddress, const int, const CVector<int16_t> ) ), this, SLOT( OnFrame (const int, const QString, const CHostAddress, const int, const CVector<int16_t> ) ), Qt::ConnectionType::QueuedConnection ); - QObject::connect( QCoreApplication::instance(), - SIGNAL ( aboutToQuit() ), + QObject::connect( QCoreApplication::instance(), SIGNAL ( aboutToQuit() ), this, SLOT( OnAboutToQuit() ) ); iServerFrameSizeSamples = _iServerFrameSizeSamples; @@ -338,11 +337,10 @@ void CJamRecorder::Init( const CServer* server, thisThread->start(); } - /** - * @brief CJamRecorder::OnStart Start up tasks when the first client connects + * @brief CJamRecorder::Start Start up tasks for a new session */ -void CJamRecorder::OnStart() { +void CJamRecorder::Start() { // Ensure any previous cleaning up has been done. OnEnd(); @@ -350,11 +348,17 @@ void CJamRecorder::OnStart() { isRecording = true; } + /** * @brief CJamRecorder::OnEnd Finalise the recording and emit the Reaper RPP file + * + * Emits RecordingSessionEnded with the Reaper project file name, + * or null if was not recording or a problem occurs */ void CJamRecorder::OnEnd() { + QString reaperProjectFileName = QString::Null(); + if ( isRecording ) { isRecording = false; @@ -366,21 +370,46 @@ void CJamRecorder::OnEnd() if (fi.exists()) { qWarning() << "CJamRecorder::OnEnd():" << fi.absolutePath() << "exists and will not be overwritten."; + reaperProjectFileName = QString::Null(); } else { QFile outf (reaperProjectFileName); - outf.open(QFile::WriteOnly); - QTextStream out(&outf); - out << CReaperProject( currentSession->Tracks(), iServerFrameSizeSamples ).toString() << endl; - qDebug() << "Session RPP:" << reaperProjectFileName; + if ( outf.open(QFile::WriteOnly) ) + { + QTextStream out(&outf); + out << CReaperProject( currentSession->Tracks(), iServerFrameSizeSamples ).toString() << endl; + qDebug() << "Session RPP:" << reaperProjectFileName; + } + else + { + qWarning() << "CJamRecorder::OnEnd():" << fi.absolutePath() << "could not be created, no RPP written."; + reaperProjectFileName = QString::Null(); + } } delete currentSession; currentSession = nullptr; } + + emit RecordingSessionEnded ( reaperProjectFileName ); } +/** + * @brief CJamRecorder::OnTriggerSession End one session and start a new one + */ +void CJamRecorder::OnTriggerSession() +{ + // This should magically get everything right... + if ( isRecording ) + { + Start(); + } +} + +/** + * @brief CJamRecorder::OnAboutToQuit End any recording and exit thread + */ void CJamRecorder::OnAboutToQuit() { OnEnd(); @@ -452,7 +481,7 @@ void CJamRecorder::OnFrame(const int iChID, const QString name, const CHostAddre // Make sure we are ready if ( !isRecording ) { - OnStart(); + Start(); } currentSession->Frame( iChID, name, address, numAudioChannels, data, iServerFrameSizeSamples ); diff --git a/src/recorder/jamrecorder.h b/src/recorder/jamrecorder.h index eb5a0581..2bc128db 100755 --- a/src/recorder/jamrecorder.h +++ b/src/recorder/jamrecorder.h @@ -143,21 +143,44 @@ public: { } + /** + * @brief Create recording directory, if necessary, and connect signal handlers + * @param server Server object emiting signals + */ void Init( const CServer* server, const int _iServerFrameSizeSamples ); + /** + * @brief SessionDirToReaper Method that allows an RPP file to be recreated + * @param strSessionDirName Where the session wave files are + * @param serverFrameSizeSamples What the server frame size was for the session + */ static void SessionDirToReaper( QString& strSessionDirName, int serverFrameSizeSamples ); -public slots: - /** - * @brief Raised when first client joins the server, triggering a new recording. - */ - void OnStart(); +private: + void Start(); + QDir recordBaseDir; + + bool isRecording; + CJamSession* currentSession; + int iServerFrameSizeSamples; + + QThread* thisThread; + +signals: + void RecordingSessionEnded ( QString sessionDir ); + +private slots: /** * @brief Raised when last client leaves the server, ending the recording. */ void OnEnd(); + /** + * @brief Raised to end one session and start a new one. + */ + void OnTriggerSession(); + /** * @brief Raised when application is stopping */ @@ -173,15 +196,6 @@ public slots: * @brief Raised when a frame of data is available to process */ void OnFrame ( const int iChID, const QString name, const CHostAddress address, const int numAudioChannels, const CVector<int16_t> data ); - -private: - QDir recordBaseDir; - - bool isRecording; - CJamSession* currentSession; - int iServerFrameSizeSamples; - - QThread* thisThread; }; } From 4bf5176e6aa757e459649744c8b0277625bfed19 Mon Sep 17 00:00:00 2001 From: Peter L Jones <peter@drealm.info> Date: Fri, 15 May 2020 21:52:13 +0100 Subject: [PATCH 3/3] Request new recording on SIGUSR1 --- src/recorder/jamrecorder.cpp | 4 ++++ src/server.cpp | 12 ++++++++++++ src/server.h | 3 +++ 3 files changed, 19 insertions(+) diff --git a/src/recorder/jamrecorder.cpp b/src/recorder/jamrecorder.cpp index 7719bd6d..4327ccf2 100755 --- a/src/recorder/jamrecorder.cpp +++ b/src/recorder/jamrecorder.cpp @@ -314,6 +314,10 @@ void CJamRecorder::Init( const CServer* server, throw std::runtime_error( (recordBaseDir.absolutePath() + " is a directory but cannot be written to").toStdString() ); } + QObject::connect( (const QObject *)server, SIGNAL ( RestartRecorder() ), + this, SLOT( OnTriggerSession() ), + Qt::ConnectionType::QueuedConnection ); + QObject::connect( (const QObject *)server, SIGNAL ( Stopped() ), this, SLOT( OnEnd() ), Qt::ConnectionType::QueuedConnection ); diff --git a/src/server.cpp b/src/server.cpp index b6c7f3b2..718875e8 100755 --- a/src/server.cpp +++ b/src/server.cpp @@ -678,6 +678,10 @@ void CServer::OnHandledSignal ( int sigNum ) switch ( sigNum ) { + case SIGUSR1: + RequestNewRecording(); + break; + case SIGINT: case SIGTERM: // This should trigger OnAboutToQuit @@ -1586,3 +1590,11 @@ void CServer::CreateLevelsForAllConChannels ( const int i vecLevelsOut[j] = static_cast<uint16_t> ( ceil ( dCurSigLevel ) ); } } + +void CServer::RequestNewRecording() +{ + if ( bEnableRecording ) + { + emit RestartRecorder(); + } +} diff --git a/src/server.h b/src/server.h index 52633b4a..475928e4 100755 --- a/src/server.h +++ b/src/server.h @@ -285,6 +285,8 @@ protected: const CVector<CVector<int16_t> > vecvecsData, CVector<uint16_t>& vecLevelsOut ); + void RequestNewRecording(); + // do not use the vector class since CChannel does not have appropriate // copy constructor/operator CChannel vecChannels[MAX_NUM_CHANNELS]; @@ -364,6 +366,7 @@ signals: const CHostAddress RecHostAddr, const int iNumAudChan, const CVector<int16_t> vecsData ); + void RestartRecorder(); public slots: void OnTimer();