jamulus/src/server.h

495 lines
17 KiB
C++
Executable file

/******************************************************************************\
* 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 <QObject>
#include <QTimer>
#include <QDateTime>
#include <QHostAddress>
#include <QFileInfo>
#include <algorithm>
#ifdef USE_MULTITHREADING
# include <QtConcurrent>
# include <QFutureSynchronizer>
#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<int> 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 <mach/mach.h>
# include <mach/mach_error.h>
# include <mach/mach_time.h>
# else
# include <sys/time.h>
# 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<unsigned int slotId>
class CServerSlots : public CServerSlots<slotId - 1>
{
public:
void OnSendProtMessCh ( CVector<uint8_t> 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<uint8_t> 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<MAX_NUM_CHANNELS>
{
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<uint8_t>& vecbyRecBuf,
const int iNumBytesRead,
const CHostAddress& HostAdr,
int& iCurChanID );
void GetConCliParam ( CVector<CHostAddress>& vecHostAddresses,
CVector<QString>& vecsName,
CVector<int>& veciJitBufNumFrames,
CVector<int>& 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<CChannelInfo> 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<uint8_t> vecMessage );
template<unsigned int slotId>
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<int>& vecNumAudioChannels,
const CVector<CVector<int16_t> > vecvecsData,
CVector<uint16_t>& 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<int16_t> DoubleFrameSizeConvBufIn[MAX_NUM_CHANNELS];
CConvBuf<int16_t> DoubleFrameSizeConvBufOut[MAX_NUM_CHANNELS];
CVector<QString> vstrChatColors;
CVector<int> vecChanIDsCurConChan;
CVector<CVector<double> > vecvecdGains;
CVector<CVector<double> > vecvecdPannings;
CVector<CVector<int16_t> > vecvecsData;
CVector<int> vecNumAudioChannels;
CVector<int> vecNumFrameSizeConvBlocks;
CVector<int> vecUseDoubleSysFraSizeConvBuf;
CVector<EAudComprType> vecAudioComprType;
CVector<CVector<int16_t> > vecvecsSendData;
CVector<CVector<double> > vecvecsIntermediateProcBuf;
CVector<CVector<uint8_t> > vecvecbyCodedData;
// Channel levels
CVector<uint16_t> 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<int16_t> 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<uint8_t> vecMessage );
void OnProtcolCLMessageReceived ( int iRecID,
CVector<uint8_t> vecbyMesBodyData,
CHostAddress RecHostAddr );
void OnProtcolMessageReceived ( int iRecCounter,
int iRecID,
CVector<uint8_t> 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<int16_t>)