/******************************************************************************\ * Copyright (c) 2004-2020 * * Author(s): * Volker Fischer * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * \******************************************************************************/ #pragma once #include #include #include #include #include #include #ifdef USE_MULTITHREADING # include # include #endif #ifdef USE_OPUS_SHARED_LIB # include "opus/opus_custom.h" #else # include "opus_custom.h" #endif #include "global.h" #include "buffer.h" #include "signalhandler.h" #include "socket.h" #include "channel.h" #include "util.h" #include "serverlogging.h" #include "serverlist.h" #include "recorder/jamcontroller.h" /* Definitions ****************************************************************/ // no valid channel number #define INVALID_CHANNEL_ID ( MAX_NUM_CHANNELS + 1 ) /* Classes ********************************************************************/ #if ( defined ( WIN32 ) || defined ( _WIN32 ) ) // using QTimer for Windows class CHighPrecisionTimer : public QObject { Q_OBJECT public: CHighPrecisionTimer ( const bool bNewUseDoubleSystemFrameSize ); void Start(); void Stop(); bool isActive() const { return Timer.isActive(); } protected: QTimer Timer; CVector veciTimeOutIntervals; int iCurPosInVector; int iIntervalCounter; bool bUseDoubleSystemFrameSize; public slots: void OnTimer(); signals: void timeout(); }; #else // using mach timers for Mac and nanosleep for Linux # if defined ( __APPLE__ ) || defined ( __MACOSX ) # include # include # include # else # include # endif class CHighPrecisionTimer : public QThread { Q_OBJECT public: CHighPrecisionTimer ( const bool bUseDoubleSystemFrameSize ); void Start(); void Stop(); bool isActive() { return bRun; } protected: virtual void run(); bool bRun; # if defined ( __APPLE__ ) || defined ( __MACOSX ) uint64_t Delay; uint64_t NextEnd; # else long Delay; timespec NextEnd; # endif signals: void timeout(); }; #endif template class CServerSlots : public CServerSlots { public: void OnSendProtMessCh ( CVector mess ) { SendProtMessage ( slotId - 1, mess ); } void OnReqConnClientsListCh() { CreateAndSendChanListForThisChan ( slotId - 1 ); } void OnChatTextReceivedCh ( QString strChatText ) { CreateAndSendChatTextForAllConChannels ( slotId - 1, strChatText ); } void OnMuteStateHasChangedCh ( int iChanID, bool bIsMuted ) { CreateOtherMuteStateChanged ( slotId - 1, iChanID, bIsMuted ); } void OnServerAutoSockBufSizeChangeCh ( int iNNumFra ) { CreateAndSendJitBufMessage ( slotId - 1, iNNumFra ); } protected: virtual void SendProtMessage ( int iChID, CVector vecMessage ) = 0; virtual void CreateAndSendChanListForThisChan ( const int iCurChanID ) = 0; virtual void CreateAndSendChatTextForAllConChannels ( const int iCurChanID, const QString& strChatText ) = 0; virtual void CreateOtherMuteStateChanged ( const int iCurChanID, const int iOtherChanID, const bool bIsMuted ) = 0; virtual void CreateAndSendJitBufMessage ( const int iCurChanID, const int iNNumFra ) = 0; }; template<> class CServerSlots<0> {}; class CServer : public QObject, public CServerSlots { Q_OBJECT public: CServer ( const int iNewMaxNumChan, const QString& strLoggingFileName, const quint16 iPortNumber, const QString& strHTMLStatusFileName, const QString& strServerNameForHTMLStatusFile, const QString& strCentralServer, const QString& strServerInfo, const QString& strNewWelcomeMessage, const QString& strRecordingDirName, const bool bNCentServPingServerInList, const bool bNDisconnectAllClientsOnQuit, const bool bNUseDoubleSystemFrameSize, const ELicenceType eNLicenceType ); virtual ~CServer(); void Start(); void Stop(); bool IsRunning() { return HighPrecisionTimer.isActive(); } bool PutAudioData ( const CVector& vecbyRecBuf, const int iNumBytesRead, const CHostAddress& HostAdr, int& iCurChanID ); void GetConCliParam ( CVector& vecHostAddresses, CVector& vecsName, CVector& veciJitBufNumFrames, CVector& veciNetwFrameSizeFact ); // Jam recorder ------------------------------------------------------------ bool GetRecorderInitialised() { return JamController.GetRecorderInitialised(); } QString GetRecorderErrMsg() { return JamController.GetRecorderErrMsg(); } bool GetRecordingEnabled() { return JamController.GetRecordingEnabled(); } void RequestNewRecording() { JamController.RequestNewRecording(); } void SetEnableRecording ( bool bNewEnableRecording ); QString GetRecordingDir() { return JamController.GetRecordingDir(); } void SetRecordingDir( QString newRecordingDir ) { JamController.SetRecordingDir ( newRecordingDir, iServerFrameSizeSamples ); } virtual void CreateAndSendRecorderStateForAllConChannels(); // Server list management -------------------------------------------------- void UpdateServerList() { ServerListManager.Update(); } void UnregisterSlaveServer() { ServerListManager.SlaveServerUnregister(); } void SetServerListEnabled ( const bool bState ) { ServerListManager.SetEnabled ( bState ); } bool GetServerListEnabled() { return ServerListManager.GetEnabled(); } void SetServerListCentralServerAddress ( const QString& sNCentServAddr ) { ServerListManager.SetCentralServerAddress ( sNCentServAddr ); } QString GetServerListCentralServerAddress() { return ServerListManager.GetCentralServerAddress(); } void SetCentralServerAddressType ( const ECSAddType eNCSAT ) { ServerListManager.SetCentralServerAddressType ( eNCSAT ); } ECSAddType GetCentralServerAddressType() { return ServerListManager.GetCentralServerAddressType(); } void SetServerName ( const QString& strNewName ) { ServerListManager.SetServerName ( strNewName ); } QString GetServerName() { return ServerListManager.GetServerName(); } void SetServerCity ( const QString& strNewCity ) { ServerListManager.SetServerCity ( strNewCity ); } QString GetServerCity() { return ServerListManager.GetServerCity(); } void SetServerCountry ( const QLocale::Country eNewCountry ) { ServerListManager.SetServerCountry ( eNewCountry ); } QLocale::Country GetServerCountry() { return ServerListManager.GetServerCountry(); } void SetWelcomeMessage ( const QString& strNWelcMess ); QString GetWelcomeMessage() { return strWelcomeMessage; } ESvrRegStatus GetSvrRegStatus() { return ServerListManager.GetSvrRegStatus(); } // GUI settings ------------------------------------------------------------ void SetAutoRunMinimized ( const bool NAuRuMin ) { bAutoRunMinimized = NAuRuMin; } bool GetAutoRunMinimized() { return bAutoRunMinimized; } void SetLicenceType ( const ELicenceType NLiType ) { eLicenceType = NLiType; } ELicenceType GetLicenceType() { return eLicenceType; } protected: // access functions for actual channels bool IsConnected ( const int iChanNum ) { return vecChannels[iChanNum].IsConnected(); } void StartStatusHTMLFileWriting ( const QString& strNewFileName, const QString& strNewServerNameWithPort ); int GetFreeChan(); int FindChannel ( const CHostAddress& CheckAddr ); int GetNumberOfConnectedClients(); CVector CreateChannelList(); virtual void CreateAndSendChanListForAllConChannels(); virtual void CreateAndSendChanListForThisChan ( const int iCurChanID ); virtual void CreateAndSendChatTextForAllConChannels ( const int iCurChanID, const QString& strChatText ); virtual void CreateOtherMuteStateChanged ( const int iCurChanID, const int iOtherChanID, const bool bIsMuted ); virtual void CreateAndSendJitBufMessage ( const int iCurChanID, const int iNNumFra ); virtual void SendProtMessage ( int iChID, CVector vecMessage ); template inline void connectChannelSignalsToServerSlots(); void WriteHTMLChannelList(); void MixEncodeTransmitData ( const int iChanCnt, const int iCurChanID, const int iNumClients ); virtual void customEvent ( QEvent* pEvent ); // if server mode is normal or double system frame size bool bUseDoubleSystemFrameSize; int iServerFrameSizeSamples; bool CreateLevelsForAllConChannels ( const int iNumClients, const CVector& vecNumAudioChannels, const CVector > vecvecsData, CVector& vecLevelsOut ); // do not use the vector class since CChannel does not have appropriate // copy constructor/operator CChannel vecChannels[MAX_NUM_CHANNELS]; int iMaxNumChannels; CProtocol ConnLessProtocol; QMutex Mutex; QMutex MutexWelcomeMessage; // audio encoder/decoder OpusCustomMode* Opus64Mode[MAX_NUM_CHANNELS]; OpusCustomEncoder* Opus64EncoderMono[MAX_NUM_CHANNELS]; OpusCustomDecoder* Opus64DecoderMono[MAX_NUM_CHANNELS]; OpusCustomEncoder* Opus64EncoderStereo[MAX_NUM_CHANNELS]; OpusCustomDecoder* Opus64DecoderStereo[MAX_NUM_CHANNELS]; OpusCustomMode* OpusMode[MAX_NUM_CHANNELS]; OpusCustomEncoder* OpusEncoderMono[MAX_NUM_CHANNELS]; OpusCustomDecoder* OpusDecoderMono[MAX_NUM_CHANNELS]; OpusCustomEncoder* OpusEncoderStereo[MAX_NUM_CHANNELS]; OpusCustomDecoder* OpusDecoderStereo[MAX_NUM_CHANNELS]; CConvBuf DoubleFrameSizeConvBufIn[MAX_NUM_CHANNELS]; CConvBuf DoubleFrameSizeConvBufOut[MAX_NUM_CHANNELS]; CVector vstrChatColors; CVector vecChanIDsCurConChan; CVector > vecvecdGains; CVector > vecvecdPannings; CVector > vecvecsData; CVector vecNumAudioChannels; CVector vecNumFrameSizeConvBlocks; CVector vecUseDoubleSysFraSizeConvBuf; CVector vecAudioComprType; CVector > vecvecsSendData; CVector > vecvecsIntermediateProcBuf; CVector > vecvecbyCodedData; // Channel levels CVector vecChannelLevels; // actual working objects CHighPrioSocket Socket; // logging CServerLogging Logging; // channel level update frame interval counter int iFrameCount; // HTML file server status bool bWriteStatusHTMLFile; QString strServerHTMLFileListName; QString strServerNameWithPort; CHighPrecisionTimer HighPrecisionTimer; // server list CServerListManager ServerListManager; // jam recorder recorder::CJamController JamController; // GUI settings bool bAutoRunMinimized; // messaging QString strWelcomeMessage; ELicenceType eLicenceType; bool bDisconnectAllClientsOnQuit; CSignalHandler* pSignalHandler; signals: void Started(); void Stopped(); void ClientDisconnected ( const int iChID ); void SvrRegStatusChanged(); void AudioFrame ( const int iChID, const QString stChName, const CHostAddress RecHostAddr, const int iNumAudChan, const CVector vecsData ); // pass through from jam controller void RestartRecorder(); void StopRecorder(); void RecordingSessionStarted ( QString sessionDir ); void EndRecorderThread(); public slots: void OnTimer(); void OnNewConnection ( int iChID, CHostAddress RecHostAddr ); void OnServerFull ( CHostAddress RecHostAddr ); void OnSendCLProtMessage ( CHostAddress InetAddr, CVector vecMessage ); void OnProtcolCLMessageReceived ( int iRecID, CVector vecbyMesBodyData, CHostAddress RecHostAddr ); void OnProtcolMessageReceived ( int iRecCounter, int iRecID, CVector vecbyMesBodyData, CHostAddress RecHostAddr ); void OnCLPingReceived ( CHostAddress InetAddr, int iMs ) { ConnLessProtocol.CreateCLPingMes ( InetAddr, iMs ); } void OnCLPingWithNumClientsReceived ( CHostAddress InetAddr, int iMs, int ) { ConnLessProtocol.CreateCLPingWithNumClientsMes ( InetAddr, iMs, GetNumberOfConnectedClients() ); } void OnCLSendEmptyMes ( CHostAddress TargetInetAddr ) { // only send empty message if server list is enabled and this is not // the central server if ( ServerListManager.GetEnabled() && !ServerListManager.GetIsCentralServer() ) { ConnLessProtocol.CreateCLEmptyMes ( TargetInetAddr ); } } void OnCLReqServerList ( CHostAddress InetAddr ) { ServerListManager.CentralServerQueryServerList ( InetAddr ); } void OnCLReqVersionAndOS ( CHostAddress InetAddr ) { ConnLessProtocol.CreateCLVersionAndOSMes ( InetAddr ); } void OnCLReqConnClientsList ( CHostAddress InetAddr ) { ConnLessProtocol.CreateCLConnClientsListMes ( InetAddr, CreateChannelList() ); } void OnCLRegisterServerReceived ( CHostAddress InetAddr, CHostAddress LInetAddr, CServerCoreInfo ServerInfo ) { ServerListManager.CentralServerRegisterServer ( InetAddr, LInetAddr, ServerInfo ); } void OnCLRegisterServerExReceived ( CHostAddress InetAddr, CHostAddress LInetAddr, CServerCoreInfo ServerInfo, COSUtil::EOpSystemType eOSType, QString strVersion ) { ServerListManager.CentralServerRegisterServerEx ( InetAddr, LInetAddr, ServerInfo, eOSType, strVersion ); } void OnCLRegisterServerResp ( CHostAddress /* unused */, ESvrRegResult eResult ) { ServerListManager.StoreRegistrationResult ( eResult ); } void OnCLUnregisterServerReceived ( CHostAddress InetAddr ) { ServerListManager.CentralServerUnregisterServer ( InetAddr ); } void OnCLDisconnection ( CHostAddress InetAddr ); void OnAboutToQuit(); void OnHandledSignal ( int sigNum ); }; Q_DECLARE_METATYPE(CVector)