diff --git a/src/recorder/jamrecorder.cpp b/src/recorder/jamrecorder.cpp index 68fc2ab4..1a84ac61 100755 --- a/src/recorder/jamrecorder.cpp +++ b/src/recorder/jamrecorder.cpp @@ -302,27 +302,32 @@ QMap> CJamSession::TracksFromSessionDir(const QString /** * @brief CJamRecorder::Init Create recording directory, if necessary, and connect signal handlers * @param server Server object emiting signals + * @return QString::null on success else the failure reason */ -bool CJamRecorder::Init( const CServer* server, - const int _iServerFrameSizeSamples ) +QString CJamRecorder::Init( const CServer* server, + const int _iServerFrameSizeSamples ) { + QString errmsg = QString::null; QFileInfo fi(recordBaseDir.absolutePath()); fi.setCaching(false); if (!fi.exists() && !QDir().mkpath(recordBaseDir.absolutePath())) { - qCritical() << recordBaseDir.absolutePath() << "does not exist but could not be created"; - return false; + errmsg = recordBaseDir.absolutePath() + " does not exist but could not be created"; + qCritical() << errmsg; + return errmsg; } if (!fi.isDir()) { - qCritical() << recordBaseDir.absolutePath() << "exists but is not a directory"; - return false; + errmsg = recordBaseDir.absolutePath() + " exists but is not a directory"; + qCritical() << errmsg; + return errmsg; } if (!fi.isWritable()) { - qCritical() << recordBaseDir.absolutePath() << "is a directory but cannot be written to"; - return false; + errmsg = recordBaseDir.absolutePath() + " is a directory but cannot be written to"; + qCritical() << errmsg; + return errmsg; } QObject::connect( (const QObject *)server, SIGNAL ( RestartRecorder() ), @@ -333,6 +338,9 @@ bool CJamRecorder::Init( const CServer* server, this, SLOT( OnEnd() ), Qt::ConnectionType::QueuedConnection ); + QObject::connect( (const QObject *)server, SIGNAL ( EndRecorderThread() ), + this, SLOT( OnAboutToQuit() ) ); + QObject::connect( (const QObject *)server, SIGNAL ( Stopped() ), this, SLOT( OnEnd() ), Qt::ConnectionType::QueuedConnection ); @@ -351,11 +359,7 @@ bool CJamRecorder::Init( const CServer* server, iServerFrameSizeSamples = _iServerFrameSizeSamples; - thisThread = new QThread(); - moveToThread ( thisThread ); - thisThread->start(); - - return true; + return errmsg; } /** @@ -410,7 +414,7 @@ void CJamRecorder::OnAboutToQuit() { OnEnd(); - thisThread->exit(); + QThread::currentThread()->exit(); } void CJamRecorder::ReaperProjectFromCurrentSession() diff --git a/src/recorder/jamrecorder.h b/src/recorder/jamrecorder.h index 4bf8fa8f..a739f4f5 100755 --- a/src/recorder/jamrecorder.h +++ b/src/recorder/jamrecorder.h @@ -149,7 +149,7 @@ public: * @brief Create recording directory, if necessary, and connect signal handlers * @param server Server object emiting signals */ - bool Init( const CServer* server, const int _iServerFrameSizeSamples ); + QString Init( const CServer* server, const int _iServerFrameSizeSamples ); /** * @brief SessionDirToReaper Method that allows an RPP file to be recreated @@ -169,35 +169,33 @@ private: CJamSession* currentSession; int iServerFrameSizeSamples; - QThread* thisThread; - signals: void RecordingSessionStarted ( QString sessionDir ); private slots: /** - * @brief Raised when last client leaves the server, ending the recording. + * @brief Handle last client leaving the server, ends the recording. */ void OnEnd(); /** - * @brief Raised to end one session and start a new one. + * @brief Handle request to end one session and start a new one. */ void OnTriggerSession(); /** - * @brief Raised when application is stopping + * @brief Handle application stopping */ void OnAboutToQuit(); /** - * @brief Raised when an existing client leaves the server. + * @brief Handle an existing client leaving the server. * @param iChID channel number of client */ void OnDisconnected ( int iChID ); /** - * @brief Raised when a frame of data is available to process + * @brief Handle a frame of data to process */ void OnFrame ( const int iChID, const QString name, const CHostAddress address, const int numAudioChannels, const CVector data ); }; diff --git a/src/server.cpp b/src/server.cpp index b958c8fd..d89ef5bc 100755 --- a/src/server.cpp +++ b/src/server.cpp @@ -240,10 +240,8 @@ CServer::CServer ( const int iNewMaxNumChan, Socket ( this, iPortNumber ), Logging ( iMaxDaysHistory ), iFrameCount ( 0 ), - JamRecorder ( strRecordingDirName ), - bRecorderInitialised ( false ), - bEnableRecording ( false ), bWriteStatusHTMLFile ( false ), + bRecorderInitialised ( false ), HighPrecisionTimer ( bNUseDoubleSystemFrameSize ), ServerListManager ( iPortNumber, strCentralServer, @@ -424,11 +422,7 @@ CServer::CServer ( const int iNewMaxNumChan, strWelcomeMessage = strWelcomeMessage.left ( MAX_LEN_CHAT_TEXT ); // enable jam recording (if requested) - kicks off the thread - if ( !strRecordingDirName.isEmpty() ) - { - bRecorderInitialised = JamRecorder.Init ( this, iServerFrameSizeSamples ); - SetEnableRecording ( bRecorderInitialised ); - } + SetRecordingDir ( strRecordingDirName ); // enable all channels (for the server all channel must be enabled the // entire life time of the software) @@ -479,9 +473,6 @@ CServer::CServer ( const int iNewMaxNumChan, QObject::connect ( &ServerListManager, &CServerListManager::SvrRegStatusChanged, this, &CServer::SvrRegStatusChanged ); - QObject::connect( &JamRecorder, &recorder::CJamRecorder::RecordingSessionStarted, - this, &CServer::RecordingSessionStarted ); - QObject::connect ( QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, &CServer::OnAboutToQuit ); @@ -742,46 +733,6 @@ void CServer::OnHandledSignal ( int sigNum ) #endif } -void CServer::RequestNewRecording() -{ - if ( bRecorderInitialised && bEnableRecording ) - { - emit RestartRecorder(); - } - - // send recording state message - doesn't hurt - CreateAndSendRecorderStateForAllConChannels(); -} - -void CServer::SetEnableRecording ( bool bNewEnableRecording ) -{ - if ( bRecorderInitialised ) - { - // note that this block executes regardless of whether - // what appears to be a change is being applied, to ensure - // the requested state is the result - bEnableRecording = bNewEnableRecording; - -#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0) -// TODO we should use the ConsoleWriterFactory() instead of qInfo() - qInfo() << "Recording state" << ( bEnableRecording ? "enabled" : "disabled" ); -#endif - - if ( !bEnableRecording ) - { - emit StopRecorder(); - } - else if ( !IsRunning() ) - { - // This dirty hack is for the GUI. It doesn't care. - emit StopRecorder(); - } - } - - // send recording state message - CreateAndSendRecorderStateForAllConChannels(); -} - void CServer::Start() { // only start if not already running @@ -1639,6 +1590,92 @@ void CServer::WriteHTMLChannelList() streamFileOut << "" << endl; } +void CServer::RequestNewRecording() +{ + if ( bRecorderInitialised && bEnableRecording ) + { + emit RestartRecorder(); + } + + // send recording state message - doesn't hurt + CreateAndSendRecorderStateForAllConChannels(); +} + +void CServer::SetEnableRecording ( bool bNewEnableRecording ) +{ + if ( bRecorderInitialised ) + { + // note that this block executes regardless of whether + // what appears to be a change is being applied, to ensure + // the requested state is the result + bEnableRecording = bNewEnableRecording; + +#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0) +// TODO we should use the ConsoleWriterFactory() instead of qInfo() + qInfo() << "Recording state" << ( bEnableRecording ? "enabled" : "disabled" ); +#endif + + if ( !bEnableRecording ) + { + emit StopRecorder(); + } + else if ( !IsRunning() ) + { + // This dirty hack is for the GUI. It doesn't care. + emit StopRecorder(); + } + } + + // send recording state message + CreateAndSendRecorderStateForAllConChannels(); +} + +void CServer::SetRecordingDir ( QString newRecordingDir ) +{ + if ( bRecorderInitialised ) + { + // We have a thread and we want to start a new one. + // We only want one running. + // This could take time, unfortunately. + // Hopefully changing recording directory will NOT happen during a long jam... + emit EndRecorderThread(); + thJamRecorder.wait(); + } + + if ( !newRecordingDir.isEmpty() ) + { + pJamRecorder = new recorder::CJamRecorder ( newRecordingDir ); + strRecorderErrMsg = pJamRecorder->Init ( this, iServerFrameSizeSamples ); + bRecorderInitialised = ( strRecorderErrMsg == QString::null ); + bEnableRecording = bRecorderInitialised; + } + else + { + // This is the only time this is ever true - UI needs to handle it + strRecorderErrMsg = QString::null; + bRecorderInitialised = false; + bEnableRecording = false; + } + if ( bRecorderInitialised ) + { + strRecordingDir = newRecordingDir; + pJamRecorder->moveToThread ( &thJamRecorder ); + thJamRecorder.setObjectName ( "Jamulus::JamRecorder" ); + + QObject::connect ( &thJamRecorder, &QThread::finished, + pJamRecorder, &QObject::deleteLater ); + + QObject::connect ( pJamRecorder, &recorder::CJamRecorder::RecordingSessionStarted, + this, &CServer::RecordingSessionStarted ); + + thJamRecorder.start(); + } + else + { + strRecordingDir = ""; + } +} + void CServer::customEvent ( QEvent* pEvent ) { if ( pEvent->type() == QEvent::User + 11 ) diff --git a/src/server.h b/src/server.h index bb58dc2d..10f84df5 100755 --- a/src/server.h +++ b/src/server.h @@ -200,9 +200,12 @@ public: CVector& veciNetwFrameSizeFact ); bool GetRecorderInitialised() { return bRecorderInitialised; } + QString GetRecorderErrMsg() { return strRecorderErrMsg; } bool GetRecordingEnabled() { return bEnableRecording; } void RequestNewRecording(); void SetEnableRecording ( bool bNewEnableRecording ); + QString GetRecordingDir() { return strRecordingDir; } + void SetRecordingDir( QString newRecordingDir ); // Server list management -------------------------------------------------- void UpdateServerList() { ServerListManager.Update(); } @@ -358,16 +361,19 @@ protected: // channel level update frame interval counter int iFrameCount; - // recording thread - recorder::CJamRecorder JamRecorder; - bool bRecorderInitialised; - bool bEnableRecording; - // HTML file server status bool bWriteStatusHTMLFile; QString strServerHTMLFileListName; QString strServerNameWithPort; + // recording thread + bool bRecorderInitialised; + bool bEnableRecording; + QThread thJamRecorder; + recorder::CJamRecorder* pJamRecorder; + QString strRecorderErrMsg; + QString strRecordingDir; + CHighPrecisionTimer HighPrecisionTimer; // server list @@ -396,6 +402,7 @@ signals: void RestartRecorder(); void StopRecorder(); void RecordingSessionStarted ( QString sessionDir ); + void EndRecorderThread(); public slots: void OnTimer();