Merge pull request #42 from pljones/feature/channel-meters
Feature/channel meters
|
@ -35,16 +35,28 @@ CChannelFader::CChannelFader ( QWidget* pNW,
|
|||
// QWidget takes the ownership of the pMainGrid so that this only has
|
||||
// to be created locally in this constructor)
|
||||
pFrame = new QFrame ( pNW );
|
||||
QVBoxLayout* pMainGrid = new QVBoxLayout ( pFrame );
|
||||
pFader = new QSlider ( Qt::Vertical, pFrame );
|
||||
pcbMute = new QCheckBox ( "Mute", pFrame );
|
||||
pcbSolo = new QCheckBox ( "Solo", pFrame );
|
||||
|
||||
pLevelsBox = new QWidget ( pFrame );
|
||||
plbrChannelLevel = new CMultiColorLEDBar ( pLevelsBox );
|
||||
pFader = new QSlider ( Qt::Vertical, pLevelsBox );
|
||||
|
||||
pMuteSoloBox = new QWidget ( pFrame );
|
||||
pcbMute = new QCheckBox ( "Mute", pMuteSoloBox );
|
||||
pcbSolo = new QCheckBox ( "Solo", pMuteSoloBox );
|
||||
|
||||
pLabelInstBox = new QGroupBox ( pFrame );
|
||||
plblLabel = new QLabel ( "", pFrame );
|
||||
plblInstrument = new QLabel ( pFrame );
|
||||
plblCountryFlag = new QLabel ( pFrame );
|
||||
|
||||
QVBoxLayout* pMainGrid = new QVBoxLayout ( pFrame );
|
||||
QHBoxLayout* pLevelsGrid = new QHBoxLayout ( pLevelsBox );
|
||||
QVBoxLayout* pMuteSoloGrid = new QVBoxLayout ( pMuteSoloBox );
|
||||
QHBoxLayout* pLabelGrid = new QHBoxLayout ( pLabelInstBox );
|
||||
QVBoxLayout* pLabelPictGrid = new QVBoxLayout();
|
||||
QVBoxLayout* pLabelPictGrid = new QVBoxLayout ( );
|
||||
|
||||
// setup channel level
|
||||
plbrChannelLevel->setContentsMargins( 0, 3, 2, 3 );
|
||||
|
||||
// setup slider
|
||||
pFader->setPageStep ( 1 );
|
||||
|
@ -62,18 +74,30 @@ CChannelFader::CChannelFader ( QWidget* pNW,
|
|||
|
||||
// set margins of the layouts to zero to get maximum space for the controls
|
||||
pMainGrid->setContentsMargins ( 0, 0, 0, 0 );
|
||||
|
||||
pLevelsGrid->setContentsMargins ( 0, 0, 0, 0 );
|
||||
pLevelsGrid->setSpacing ( 0 ); // only minimal space
|
||||
|
||||
pMuteSoloGrid->setContentsMargins ( 0, 0, 0, 0 );
|
||||
|
||||
pLabelGrid->setContentsMargins ( 0, 0, 0, 0 );
|
||||
pLabelGrid->setSpacing ( 2 ); // only minimal space between picture and text
|
||||
|
||||
// add user controls to the grids
|
||||
pLabelPictGrid->addWidget ( plblCountryFlag, 0, Qt::AlignHCenter );
|
||||
pLabelPictGrid->addWidget ( plblInstrument, 0, Qt::AlignHCenter );
|
||||
|
||||
pLabelGrid->addLayout ( pLabelPictGrid );
|
||||
pLabelGrid->addWidget ( plblLabel, 0, Qt::AlignVCenter );
|
||||
|
||||
pMainGrid->addWidget ( pFader, 0, Qt::AlignHCenter );
|
||||
pMainGrid->addWidget ( pcbMute, 0, Qt::AlignLeft );
|
||||
pMainGrid->addWidget ( pcbSolo, 0, Qt::AlignLeft );
|
||||
pLevelsGrid->addWidget ( plbrChannelLevel, 0, Qt::AlignRight );
|
||||
pLevelsGrid->addWidget ( pFader, 0, Qt::AlignLeft );
|
||||
|
||||
pMuteSoloGrid->addWidget ( pcbMute, 0, Qt::AlignLeft );
|
||||
pMuteSoloGrid->addWidget ( pcbSolo, 0, Qt::AlignLeft );
|
||||
|
||||
pMainGrid->addWidget ( pLevelsBox, 0, Qt::AlignHCenter );
|
||||
pMainGrid->addWidget ( pMuteSoloBox, 0, Qt::AlignHCenter );
|
||||
pMainGrid->addWidget ( pLabelInstBox );
|
||||
|
||||
// add fader frame to audio mixer board layout
|
||||
|
@ -83,17 +107,23 @@ CChannelFader::CChannelFader ( QWidget* pNW,
|
|||
Reset();
|
||||
|
||||
// add help text to controls
|
||||
plbrChannelLevel->setWhatsThis ( tr ( "<b>Channel Level:</b> Displays the "
|
||||
"pre-fader audio level of this channel. All connected clients at the "
|
||||
"server will be assigned an audio level, the same value for each client." ) );
|
||||
plbrChannelLevel->setAccessibleName ( tr ( "Input level of the current audio "
|
||||
"channel at the server" ) );
|
||||
|
||||
pFader->setWhatsThis ( tr ( "<b>Mixer Fader:</b> Adjusts the audio level of "
|
||||
"this channel. All connected clients at the server will be assigned "
|
||||
"an audio fader at each client." ) );
|
||||
pFader->setAccessibleName ( tr ( "Mixer level setting of the connected client "
|
||||
"at the server" ) );
|
||||
"an audio fader at each client, adjusting the local mix." ) );
|
||||
pFader->setAccessibleName ( tr ( "Local mix level setting of the current audio "
|
||||
"channel at the server" ) );
|
||||
|
||||
pcbMute->setWhatsThis ( tr ( "<b>Mute:</b> With the Mute checkbox, the current "
|
||||
pcbMute->setWhatsThis ( tr ( "<b>Mute:</b> With the Mute checkbox, the "
|
||||
"audio channel can be muted." ) );
|
||||
pcbMute->setAccessibleName ( tr ( "Mute button" ) );
|
||||
|
||||
pcbSolo->setWhatsThis ( tr ( "<b>Solo:</b> With the Solo checkbox, the current "
|
||||
pcbSolo->setWhatsThis ( tr ( "<b>Solo:</b> With the Solo checkbox, the "
|
||||
"audio channel can be set to solo which means that all other channels "
|
||||
"except of the current channel are muted. It is possible to set more than "
|
||||
"one channel to solo." ) );
|
||||
|
@ -158,6 +188,11 @@ void CChannelFader::SetGUIDesign ( const EGUIDesign eNewDesign )
|
|||
}
|
||||
}
|
||||
|
||||
void CChannelFader::SetDisplayChannelLevel ( const bool eNDCL )
|
||||
{
|
||||
plbrChannelLevel->setHidden( !eNDCL );
|
||||
}
|
||||
|
||||
void CChannelFader::SetupFaderTag ( const ESkillLevel eSkillLevel )
|
||||
{
|
||||
// setup group box for label/instrument picture: set a thick black border
|
||||
|
@ -306,6 +341,11 @@ void CChannelFader::UpdateSoloState ( const bool bNewOtherSoloState )
|
|||
}
|
||||
}
|
||||
|
||||
void CChannelFader::SetChannelLevel ( const uint16_t iLevel )
|
||||
{
|
||||
plbrChannelLevel->setValue ( iLevel );
|
||||
}
|
||||
|
||||
void CChannelFader::SetText ( const CChannelInfo& ChanInfo )
|
||||
{
|
||||
// store original received name
|
||||
|
@ -634,6 +674,17 @@ void CAudioMixerBoard::SetGUIDesign ( const EGUIDesign eNewDesign )
|
|||
}
|
||||
}
|
||||
|
||||
void CAudioMixerBoard::SetDisplayChannelLevels ( const bool eNDCL )
|
||||
{
|
||||
bDisplayChannelLevels = eNDCL;
|
||||
|
||||
// apply preference to child GUI controls
|
||||
for ( int i = 0; i < MAX_NUM_CHANNELS; i++ )
|
||||
{
|
||||
vecpChanFader[i]->SetDisplayChannelLevel ( bDisplayChannelLevels );
|
||||
}
|
||||
}
|
||||
|
||||
void CAudioMixerBoard::HideAll()
|
||||
{
|
||||
// make all controls invisible
|
||||
|
@ -710,6 +761,9 @@ void CAudioMixerBoard::ApplyNewConClientList ( CVector<CChannelInfo>& vecChanInf
|
|||
}
|
||||
}
|
||||
|
||||
// At some future time a new level will arrive -- ???
|
||||
vecpChanFader[i]->SetChannelLevel ( 0 );
|
||||
|
||||
// set the text in the fader
|
||||
vecpChanFader[i]->SetText ( vecChanInfo[j] );
|
||||
|
||||
|
@ -857,3 +911,17 @@ bool CAudioMixerBoard::GetStoredFaderSettings ( const CChannelInfo& ChanInfo,
|
|||
// return "not OK" since we did not find matching fader settings
|
||||
return false;
|
||||
}
|
||||
|
||||
void CAudioMixerBoard::SetChannelLevels ( const CVector<uint16_t>& vecChannelLevel )
|
||||
{
|
||||
const int iNumChannelLevels = vecChannelLevel.Size();
|
||||
int i = 0;
|
||||
|
||||
for ( int iChId = 0; iChId < MAX_NUM_CHANNELS; iChId++ )
|
||||
{
|
||||
if ( vecpChanFader[iChId]->IsVisible() && i < iNumChannelLevels )
|
||||
{
|
||||
vecpChanFader[iChId]->SetChannelLevel ( vecChannelLevel[i++] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include <QHostAddress>
|
||||
#include "global.h"
|
||||
#include "util.h"
|
||||
#include "multicolorledbar.h"
|
||||
|
||||
|
||||
/* Classes ********************************************************************/
|
||||
|
@ -55,6 +56,7 @@ public:
|
|||
bool IsSolo() { return pcbSolo->isChecked(); }
|
||||
bool IsMute() { return pcbMute->isChecked(); }
|
||||
void SetGUIDesign ( const EGUIDesign eNewDesign );
|
||||
void SetDisplayChannelLevel ( const bool eNDCL );
|
||||
|
||||
void UpdateSoloState ( const bool bNewOtherSoloState );
|
||||
void SetFaderLevel ( const int iLevel );
|
||||
|
@ -62,6 +64,7 @@ public:
|
|||
void SetFaderIsMute ( const bool bIsMute );
|
||||
int GetFaderLevel() { return pFader->value(); }
|
||||
void Reset();
|
||||
void SetChannelLevel ( const uint16_t iLevel );
|
||||
|
||||
protected:
|
||||
double CalcFaderGain ( const int value );
|
||||
|
@ -70,10 +73,16 @@ protected:
|
|||
void SetupFaderTag ( const ESkillLevel eSkillLevel );
|
||||
|
||||
QFrame* pFrame;
|
||||
QGroupBox* pLabelInstBox;
|
||||
|
||||
QWidget* pLevelsBox;
|
||||
QWidget* pMuteSoloBox;
|
||||
CMultiColorLEDBar* plbrChannelLevel;
|
||||
QSlider* pFader;
|
||||
|
||||
QCheckBox* pcbMute;
|
||||
QCheckBox* pcbSolo;
|
||||
|
||||
QGroupBox* pLabelInstBox;
|
||||
QLabel* plblLabel;
|
||||
QLabel* plblInstrument;
|
||||
QLabel* plblCountryFlag;
|
||||
|
@ -103,10 +112,13 @@ public:
|
|||
void ApplyNewConClientList ( CVector<CChannelInfo>& vecChanInfo );
|
||||
void SetServerName ( const QString& strNewServerName );
|
||||
void SetGUIDesign ( const EGUIDesign eNewDesign );
|
||||
void SetDisplayChannelLevels ( const bool eNDCL );
|
||||
|
||||
void SetFaderLevel ( const int iChannelIdx,
|
||||
const int iValue );
|
||||
|
||||
void SetChannelLevels ( const CVector<uint16_t>& vecChannelLevel );
|
||||
|
||||
// settings
|
||||
CVector<QString> vecStoredFaderTags;
|
||||
CVector<int> vecStoredFaderLevels;
|
||||
|
@ -129,6 +141,7 @@ protected:
|
|||
CVector<CChannelFader*> vecpChanFader;
|
||||
QGroupBox* pGroupBox;
|
||||
QHBoxLayout* pMainLayout;
|
||||
bool bDisplayChannelLevels;
|
||||
bool bNoFaderVisible;
|
||||
|
||||
public slots:
|
||||
|
|
|
@ -102,6 +102,10 @@ qRegisterMetaType<CHostAddress> ( "CHostAddress" );
|
|||
QObject::connect( &Protocol,
|
||||
SIGNAL ( LicenceRequired ( ELicenceType ) ),
|
||||
SIGNAL ( LicenceRequired ( ELicenceType ) ) );
|
||||
|
||||
QObject::connect ( &Protocol,
|
||||
SIGNAL ( ReqChannelLevelList ( bool ) ),
|
||||
this, SLOT ( OnReqChannelLevelList ( bool ) ) );
|
||||
}
|
||||
|
||||
bool CChannel::ProtocolIsEnabled()
|
||||
|
|
|
@ -159,12 +159,18 @@ public:
|
|||
void CreateReqConnClientsList() { Protocol.CreateReqConnClientsList(); }
|
||||
void CreateChatTextMes ( const QString& strChatText ) { Protocol.CreateChatTextMes ( strChatText ); }
|
||||
void CreateLicReqMes ( const ELicenceType eLicenceType ) { Protocol.CreateLicenceRequiredMes ( eLicenceType ); }
|
||||
void CreateReqChannelLevelListMes ( bool bOptIn ) { Protocol.CreateReqChannelLevelListMes ( bOptIn ); }
|
||||
|
||||
void CreateConClientListMes ( const CVector<CChannelInfo>& vecChanInfo )
|
||||
{ Protocol.CreateConClientListMes ( vecChanInfo ); }
|
||||
|
||||
CNetworkTransportProps GetNetworkTransportPropsFromCurrentSettings();
|
||||
|
||||
bool ChannelLevelsRequired() const { return bChannelLevelsRequired; }
|
||||
|
||||
double GetPrevLevel() const { return dPrevLevel; }
|
||||
void SetPrevLevel ( const double nPL ) { dPrevLevel = nPL; }
|
||||
|
||||
protected:
|
||||
bool ProtocolIsEnabled();
|
||||
|
||||
|
@ -177,6 +183,8 @@ protected:
|
|||
iNetwFrameSizeFact = FRAME_SIZE_FACTOR_PREFERRED;
|
||||
iNetwFrameSize = CELT_MINIMUM_NUM_BYTES;
|
||||
iNumAudioChannels = 1; // mono
|
||||
|
||||
dPrevLevel = 0.0;
|
||||
}
|
||||
|
||||
// connection parameters
|
||||
|
@ -216,6 +224,9 @@ protected:
|
|||
QMutex MutexSocketBuf;
|
||||
QMutex MutexConvBuf;
|
||||
|
||||
bool bChannelLevelsRequired;
|
||||
double dPrevLevel;
|
||||
|
||||
public slots:
|
||||
void OnSendProtMessage ( CVector<uint8_t> vecMessage );
|
||||
void OnJittBufSizeChange ( int iNewJitBufSize );
|
||||
|
@ -249,6 +260,8 @@ public slots:
|
|||
|
||||
void OnNewConnection() { emit NewConnection(); }
|
||||
|
||||
void OnReqChannelLevelList ( bool bOptIn ) { bChannelLevelsRequired = bOptIn; }
|
||||
|
||||
signals:
|
||||
void MessReadyForSending ( CVector<uint8_t> vecMessage );
|
||||
void NewConnection();
|
||||
|
|
|
@ -65,6 +65,7 @@ CClient::CClient ( const quint16 iPortNumber,
|
|||
bFraSiFactDefSupported ( false ),
|
||||
bFraSiFactSafeSupported ( false ),
|
||||
eGUIDesign ( GD_ORIGINAL ),
|
||||
bDisplayChannelLevels ( true ),
|
||||
bJitterBufferOK ( true ),
|
||||
strCentralServerAddress ( "" ),
|
||||
bUseDefaultCentralServerAddress ( true ),
|
||||
|
@ -191,6 +192,10 @@ CClient::CClient ( const quint16 iPortNumber,
|
|||
SIGNAL ( CLVersionAndOSReceived ( CHostAddress, COSUtil::EOpSystemType, QString ) ) );
|
||||
#endif
|
||||
|
||||
QObject::connect ( &ConnLessProtocol,
|
||||
SIGNAL ( CLChannelLevelListReceived ( CHostAddress, CVector<uint16_t> ) ),
|
||||
this, SLOT ( OnCLChannelLevelListReceived ( CHostAddress, CVector<uint16_t> ) ) );
|
||||
|
||||
// other
|
||||
QObject::connect ( &Sound, SIGNAL ( ReinitRequest ( int ) ),
|
||||
this, SLOT ( OnSndCrdReinitRequest ( int ) ) );
|
||||
|
@ -279,6 +284,9 @@ void CClient::OnNewConnection()
|
|||
// Same problem is with the jitter buffer message.
|
||||
Channel.CreateReqConnClientsList();
|
||||
CreateServerJitterBufferMessage();
|
||||
|
||||
// send opt-in / out for Channel Level updates
|
||||
Channel.CreateReqChannelLevelListMes ( bDisplayChannelLevels );
|
||||
}
|
||||
|
||||
void CClient::CreateServerJitterBufferMessage()
|
||||
|
@ -387,6 +395,14 @@ bool CClient::GetAndResetbJitterBufferOKFlag()
|
|||
return bSocketJitBufOKFlag;
|
||||
}
|
||||
|
||||
void CClient::SetDisplayChannelLevels ( const bool bNDCL )
|
||||
{
|
||||
bDisplayChannelLevels = bNDCL;
|
||||
|
||||
// tell any connected server about the change
|
||||
Channel.CreateReqChannelLevelListMes ( bDisplayChannelLevels );
|
||||
}
|
||||
|
||||
void CClient::SetSndCrdPrefFrameSizeFactor ( const int iNewFactor )
|
||||
{
|
||||
// first check new input parameter
|
||||
|
@ -598,6 +614,12 @@ void CClient::OnSndCrdReinitRequest ( int iSndCrdResetType )
|
|||
}
|
||||
}
|
||||
|
||||
void CClient::OnCLChannelLevelListReceived ( CHostAddress InetAddr,
|
||||
CVector<uint16_t> vecLevelList )
|
||||
{
|
||||
emit CLChannelLevelListReceived ( InetAddr, vecLevelList );
|
||||
}
|
||||
|
||||
void CClient::Start()
|
||||
{
|
||||
// always use the OPUS codec
|
||||
|
|
10
src/client.h
|
@ -128,6 +128,9 @@ public:
|
|||
EGUIDesign GetGUIDesign() const { return eGUIDesign; }
|
||||
void SetGUIDesign ( const EGUIDesign eNGD ) { eGUIDesign = eNGD; }
|
||||
|
||||
bool GetDisplayChannelLevels() const { return bDisplayChannelLevels; }
|
||||
void SetDisplayChannelLevels ( const bool bNDCL );
|
||||
|
||||
EAudioQuality GetAudioQuality() const { return eAudioQuality; }
|
||||
void SetAudioQuality ( const EAudioQuality eNAudioQuality );
|
||||
|
||||
|
@ -359,6 +362,7 @@ protected:
|
|||
int iStereoBlockSizeSam;
|
||||
|
||||
EGUIDesign eGUIDesign;
|
||||
bool bDisplayChannelLevels;
|
||||
|
||||
bool bJitterBufferOK;
|
||||
|
||||
|
@ -398,6 +402,9 @@ public slots:
|
|||
|
||||
void OnSndCrdReinitRequest ( int iSndCrdResetType );
|
||||
|
||||
void OnCLChannelLevelListReceived ( CHostAddress InetAddr,
|
||||
CVector<uint16_t> vecLevelList );
|
||||
|
||||
signals:
|
||||
void ConClientListMesReceived ( CVector<CChannelInfo> vecChanInfo );
|
||||
void ChatTextReceived ( QString strChatText );
|
||||
|
@ -420,6 +427,9 @@ signals:
|
|||
QString strVersion );
|
||||
#endif
|
||||
|
||||
void CLChannelLevelListReceived ( CHostAddress InetAddr,
|
||||
CVector<uint16_t> vecLevelList );
|
||||
|
||||
void Disconnected();
|
||||
void ControllerInFaderLevel ( int iChannelIdx, int iValue );
|
||||
};
|
||||
|
|
|
@ -185,6 +185,9 @@ CClientDlg::CClientDlg ( CClient* pNCliP,
|
|||
// reset mixer board
|
||||
MainMixerBoard->HideAll();
|
||||
|
||||
// restore channel level display preference
|
||||
MainMixerBoard->SetDisplayChannelLevels ( pClient->GetDisplayChannelLevels() );
|
||||
|
||||
// restore fader settings
|
||||
MainMixerBoard->vecStoredFaderTags = pClient->vecStoredFaderTags;
|
||||
MainMixerBoard->vecStoredFaderLevels = pClient->vecStoredFaderLevels;
|
||||
|
@ -483,6 +486,10 @@ CClientDlg::CClientDlg ( CClient* pNCliP,
|
|||
SIGNAL ( ControllerInFaderLevel ( int, int ) ),
|
||||
this, SLOT ( OnControllerInFaderLevel ( int, int ) ) );
|
||||
|
||||
QObject::connect ( pClient,
|
||||
SIGNAL ( CLChannelLevelListReceived ( CHostAddress, CVector<uint16_t> ) ),
|
||||
this, SLOT ( OnCLChannelLevelListReceived ( CHostAddress, CVector<uint16_t> ) ) );
|
||||
|
||||
#ifdef ENABLE_CLIENT_VERSION_AND_OS_DEBUGGING
|
||||
QObject::connect ( pClient,
|
||||
SIGNAL ( CLVersionAndOSReceived ( CHostAddress, COSUtil::EOpSystemType, QString ) ),
|
||||
|
@ -495,6 +502,9 @@ CClientDlg::CClientDlg ( CClient* pNCliP,
|
|||
QObject::connect ( &ClientSettingsDlg, SIGNAL ( GUIDesignChanged() ),
|
||||
this, SLOT ( OnGUIDesignChanged() ) );
|
||||
|
||||
QObject::connect ( &ClientSettingsDlg, SIGNAL ( DisplayChannelLevelsChanged() ),
|
||||
this, SLOT ( OnDisplayChannelLevelsChanged() ) );
|
||||
|
||||
QObject::connect ( &ClientSettingsDlg, SIGNAL ( AudioChannelsChanged() ),
|
||||
this, SLOT ( OnAudioChannelsChanged() ) );
|
||||
|
||||
|
@ -906,7 +916,7 @@ void CClientDlg::OnTimerSigMet()
|
|||
// linear transformation of the input level range to the progress-bar
|
||||
// range
|
||||
dCurSigLevelL -= LOW_BOUND_SIG_METER;
|
||||
dCurSigLevelL *= NUM_STEPS_INP_LEV_METER /
|
||||
dCurSigLevelL *= NUM_STEPS_LED_BAR /
|
||||
( UPPER_BOUND_SIG_METER - LOW_BOUND_SIG_METER );
|
||||
|
||||
// lower bound the signal
|
||||
|
@ -916,7 +926,7 @@ void CClientDlg::OnTimerSigMet()
|
|||
}
|
||||
|
||||
dCurSigLevelR -= LOW_BOUND_SIG_METER;
|
||||
dCurSigLevelR *= NUM_STEPS_INP_LEV_METER /
|
||||
dCurSigLevelR *= NUM_STEPS_LED_BAR /
|
||||
( UPPER_BOUND_SIG_METER - LOW_BOUND_SIG_METER );
|
||||
|
||||
// lower bound the signal
|
||||
|
|
|
@ -60,10 +60,6 @@
|
|||
#define BUFFER_LED_UPDATE_TIME_MS 300 // ms
|
||||
#define LED_BAR_UPDATE_TIME_MS 1000 // ms
|
||||
|
||||
// range for signal level meter
|
||||
#define LOW_BOUND_SIG_METER ( -50.0 ) // dB
|
||||
#define UPPER_BOUND_SIG_METER ( 0.0 ) // dB
|
||||
|
||||
// number of ping times > upper bound until error message is shown
|
||||
#define NUM_HIGH_PINGS_UNTIL_ERROR 5
|
||||
|
||||
|
@ -196,12 +192,19 @@ public slots:
|
|||
CVector<CChannelInfo> vecChanInfo )
|
||||
{ ConnectDlg.SetConnClientsList ( InetAddr, vecChanInfo ); }
|
||||
|
||||
void OnCLChannelLevelListReceived ( CHostAddress /* unused */,
|
||||
CVector<uint16_t> vecLevelList )
|
||||
{ MainMixerBoard->SetChannelLevels ( vecLevelList ); }
|
||||
|
||||
void OnConnectDlgAccepted();
|
||||
void OnDisconnected();
|
||||
|
||||
void OnGUIDesignChanged()
|
||||
{ SetGUIDesign ( pClient->GetGUIDesign() ); }
|
||||
|
||||
void OnDisplayChannelLevelsChanged()
|
||||
{ MainMixerBoard->SetDisplayChannelLevels ( pClient->GetDisplayChannelLevels() ); }
|
||||
|
||||
void OnAudioChannelsChanged() { UpdateRevSelection(); }
|
||||
void OnNumClientsChanged ( int iNewNumClients );
|
||||
void OnNewClientLevelChanged() { MainMixerBoard->iNewClientFaderLevel = pClient->iNewClientFaderLevel; }
|
||||
|
|
|
@ -189,6 +189,12 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, QWidget* parent,
|
|||
|
||||
chbGUIDesignFancy->setAccessibleName ( tr ( "Fancy skin check box" ) );
|
||||
|
||||
// display channel levels
|
||||
chbDisplayChannelLevels->setWhatsThis ( tr ( "<b>Display Channel Levels:</b> "
|
||||
"If enabled, each client channel will display a pre-fader level bar." ) );
|
||||
|
||||
chbDisplayChannelLevels->setAccessibleName ( tr ( "Display channel levels check box" ) );
|
||||
|
||||
// audio channels
|
||||
QString strAudioChannels = tr ( "<b>Audio Channels:</b> "
|
||||
"Select the number of audio channels to be used. There are three "
|
||||
|
@ -323,6 +329,9 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, QWidget* parent,
|
|||
chbGUIDesignFancy->setCheckState ( Qt::Checked );
|
||||
}
|
||||
|
||||
// Display Channel Levels check box
|
||||
chbDisplayChannelLevels->setCheckState ( pClient->GetDisplayChannelLevels() ? Qt::Checked : Qt::Unchecked );
|
||||
|
||||
// "Audio Channels" combo box
|
||||
cbxAudioChannels->clear();
|
||||
cbxAudioChannels->addItem ( "Mono" ); // CC_MONO
|
||||
|
@ -386,6 +395,9 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, QWidget* parent,
|
|||
QObject::connect ( chbGUIDesignFancy, SIGNAL ( stateChanged ( int ) ),
|
||||
this, SLOT ( OnGUIDesignFancyStateChanged ( int ) ) );
|
||||
|
||||
QObject::connect ( chbDisplayChannelLevels, SIGNAL ( stateChanged ( int ) ),
|
||||
this, SLOT ( OnDisplayChannelLevelsStateChanged ( int ) ) );
|
||||
|
||||
QObject::connect ( chbAutoJitBuf, SIGNAL ( stateChanged ( int ) ),
|
||||
this, SLOT ( OnAutoJitBufStateChanged ( int ) ) );
|
||||
|
||||
|
@ -704,6 +716,12 @@ void CClientSettingsDlg::OnGUIDesignFancyStateChanged ( int value )
|
|||
UpdateDisplay();
|
||||
}
|
||||
|
||||
void CClientSettingsDlg::OnDisplayChannelLevelsStateChanged ( int value )
|
||||
{
|
||||
pClient->SetDisplayChannelLevels ( value != Qt::Unchecked );
|
||||
emit DisplayChannelLevelsChanged();
|
||||
}
|
||||
|
||||
void CClientSettingsDlg::OnDefaultCentralServerStateChanged ( int value )
|
||||
{
|
||||
// apply new setting to the client
|
||||
|
|
|
@ -90,6 +90,7 @@ protected:
|
|||
void OnSliderSndCrdBufferDelay ( int value );
|
||||
void OnAutoJitBufStateChanged ( int value );
|
||||
void OnGUIDesignFancyStateChanged ( int value );
|
||||
void OnDisplayChannelLevelsStateChanged ( int value );
|
||||
void OnDefaultCentralServerStateChanged ( int value );
|
||||
void OnCentralServerAddressEditingFinished();
|
||||
void OnNewClientLevelEditingFinished();
|
||||
|
@ -105,6 +106,7 @@ protected:
|
|||
|
||||
signals:
|
||||
void GUIDesignChanged();
|
||||
void DisplayChannelLevelsChanged();
|
||||
void AudioChannelsChanged();
|
||||
void NewClientLevelChanged();
|
||||
};
|
||||
|
|
|
@ -529,6 +529,8 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="chbGUIDesignFancy">
|
||||
<property name="text">
|
||||
|
@ -536,6 +538,15 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="chbDisplayChannelLevels">
|
||||
<property name="text">
|
||||
<string>Display Channel Levels</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout">
|
||||
<item>
|
||||
|
@ -719,6 +730,7 @@
|
|||
<tabstop>cbxAudioQuality</tabstop>
|
||||
<tabstop>edtNewClientLevel</tabstop>
|
||||
<tabstop>chbGUIDesignFancy</tabstop>
|
||||
<tabstop>chbDisplayChannelFaders</tabstop>
|
||||
<tabstop>chbDefaultCentralServer</tabstop>
|
||||
<tabstop>edtCentralServerAddress</tabstop>
|
||||
</tabstops>
|
||||
|
|
15
src/global.h
|
@ -169,10 +169,14 @@ LED bar: lbr
|
|||
// maximum number of fader settings to be stored (together with the fader tags)
|
||||
#define MAX_NUM_STORED_FADER_SETTINGS 100
|
||||
|
||||
// defines for LED input level meter
|
||||
#define NUM_STEPS_INP_LEV_METER 8
|
||||
#define RED_BOUND_INP_LEV_METER 7
|
||||
#define YELLOW_BOUND_INP_LEV_METER 5
|
||||
// defines for LED level meter CMultiColorLEDBar
|
||||
#define NUM_STEPS_LED_BAR 8
|
||||
#define RED_BOUND_LED_BAR 7
|
||||
#define YELLOW_BOUND_LED_BAR 5
|
||||
|
||||
// range for signal level meter
|
||||
#define LOW_BOUND_SIG_METER ( -50.0 ) // dB
|
||||
#define UPPER_BOUND_SIG_METER ( 0.0 ) // dB
|
||||
|
||||
// Maximum number of connected clients at the server. If you want to change this
|
||||
// paramter you have to modify the code on some places, too! The code tag
|
||||
|
@ -195,6 +199,9 @@ LED bar: lbr
|
|||
// list
|
||||
#define PING_UPDATE_TIME_SERVER_LIST_MS 2000 // ms
|
||||
|
||||
// defines the interval between Channel Level updates from the server
|
||||
#define CHANNEL_LEVEL_UPDATE_INTERVAL 100 // number of frames
|
||||
|
||||
// time-out until a registered server is deleted from the server list if no
|
||||
// new registering was made in minutes
|
||||
#define SERVLIST_TIME_OUT_MINUTES 60 // minutes
|
||||
|
|
|
@ -33,7 +33,7 @@ CMultiColorLEDBar::CMultiColorLEDBar ( QWidget* parent, Qt::WindowFlags f )
|
|||
: QFrame ( parent, f )
|
||||
{
|
||||
// set total number of LEDs
|
||||
iNumLEDs = NUM_STEPS_INP_LEV_METER;
|
||||
iNumLEDs = NUM_STEPS_LED_BAR;
|
||||
|
||||
// create layout and set spacing to zero
|
||||
pMainLayout = new QVBoxLayout ( this );
|
||||
|
@ -105,14 +105,14 @@ void CMultiColorLEDBar::setValue ( const int value )
|
|||
if ( iLEDIdx < value )
|
||||
{
|
||||
// check which color we should use (green, yellow or red)
|
||||
if ( iLEDIdx < YELLOW_BOUND_INP_LEV_METER )
|
||||
if ( iLEDIdx < YELLOW_BOUND_LED_BAR )
|
||||
{
|
||||
// green region
|
||||
vecpLEDs[iLEDIdx]->setColor ( cLED::RL_GREEN );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( iLEDIdx < RED_BOUND_INP_LEV_METER )
|
||||
if ( iLEDIdx < RED_BOUND_LED_BAR )
|
||||
{
|
||||
// yellow region
|
||||
vecpLEDs[iLEDIdx]->setColor ( cLED::RL_YELLOW );
|
||||
|
|
135
src/protocol.cpp
|
@ -153,6 +153,14 @@ MESSAGES (with connection)
|
|||
| 1 byte licence type |
|
||||
+---------------------+
|
||||
|
||||
- PROTMESSID_CLM_REQ_CHANNEL_LEVEL_LIST: Opt in or out of the channel level list
|
||||
|
||||
+---------------+
|
||||
| 1 byte option |
|
||||
+---------------+
|
||||
|
||||
option is boolean, true to opt in, false to opt out
|
||||
|
||||
|
||||
// #### COMPATIBILITY OLD VERSION, TO BE REMOVED ####
|
||||
- PROTMESSID_OPUS_SUPPORTED: Informs that OPUS codec is supported
|
||||
|
@ -276,6 +284,27 @@ CONNECTION LESS MESSAGES
|
|||
|
||||
note: does not have any data -> n = 0
|
||||
|
||||
- PROTMESSID_CLM_CHANNEL_LEVEL_LIST: The channel level list
|
||||
|
||||
+----------------------------------+
|
||||
| ( ( n + 1 ) / 2 ) * 4 bit values |
|
||||
+----------------------------------+
|
||||
|
||||
n is number of connected clients
|
||||
|
||||
the values are the maximum channel levels for a client frame converted
|
||||
to the range of CMultiColorLEDBar in 4 bits, two entries per byte
|
||||
with the earlier channel in the lower half of the byte
|
||||
|
||||
where an odd number of clients is connected, there will be four unused
|
||||
upper bits in the final byte, containing 0xF (which is out of range)
|
||||
|
||||
the server may compute them message when any client has used
|
||||
PROTMESSID_CLM_REQ_CHANNEL_LEVEL_LIST to opt in
|
||||
|
||||
the server may issue to message only to a client that has used
|
||||
PROTMESSID_CLM_REQ_CHANNEL_LEVEL_LIST to opt in
|
||||
|
||||
|
||||
******************************************************************************
|
||||
*
|
||||
|
@ -549,6 +578,10 @@ if ( rand() < ( RAND_MAX / 2 ) ) return false;
|
|||
case PROTMESSID_LICENCE_REQUIRED:
|
||||
bRet = EvaluateLicenceRequiredMes ( vecbyMesBodyData );
|
||||
break;
|
||||
|
||||
case PROTMESSID_REQ_CHANNEL_LEVEL_LIST:
|
||||
bRet = EvaluateReqChannelLevelListMes ( vecbyMesBodyData );
|
||||
break;
|
||||
}
|
||||
|
||||
// immediately send acknowledge message
|
||||
|
@ -634,6 +667,10 @@ if ( rand() < ( RAND_MAX / 2 ) ) return false;
|
|||
case PROTMESSID_CLM_REQ_CONN_CLIENTS_LIST:
|
||||
bRet = EvaluateCLReqConnClientsListMes ( InetAddr );
|
||||
break;
|
||||
|
||||
case PROTMESSID_CLM_CHANNEL_LEVEL_LIST:
|
||||
bRet = EvaluateCLChannelLevelListMes ( InetAddr, vecbyMesBodyData );
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1234,6 +1271,40 @@ void CProtocol::CreateOpusSupportedMes()
|
|||
CVector<uint8_t> ( 0 ) );
|
||||
}
|
||||
|
||||
void CProtocol::CreateReqChannelLevelListMes ( const bool bRCL )
|
||||
{
|
||||
CVector<uint8_t> vecData ( 1 ); // 1 byte of data
|
||||
int iPos = 0; // init position pointer
|
||||
PutValOnStream ( vecData, iPos,
|
||||
static_cast<uint32_t> ( bRCL ), 1 );
|
||||
|
||||
CreateAndSendMessage ( PROTMESSID_REQ_CHANNEL_LEVEL_LIST, vecData );
|
||||
}
|
||||
|
||||
bool CProtocol::EvaluateReqChannelLevelListMes ( const CVector<uint8_t>& vecData )
|
||||
{
|
||||
int iPos = 0; // init position pointer
|
||||
|
||||
// check size
|
||||
if ( vecData.Size() != 1 )
|
||||
{
|
||||
return true; // return error code
|
||||
}
|
||||
|
||||
// extract opt in / out for channel levels
|
||||
uint32_t val = GetValFromStream ( vecData, iPos, 1 );
|
||||
|
||||
if ( val != 0 && val != 1 )
|
||||
{
|
||||
return true; // return error code
|
||||
}
|
||||
|
||||
// invoke message action
|
||||
emit ReqChannelLevelList ( static_cast<bool> ( val ) );
|
||||
|
||||
return false; // no error
|
||||
}
|
||||
|
||||
|
||||
// Connection less messages ----------------------------------------------------
|
||||
void CProtocol::CreateCLPingMes ( const CHostAddress& InetAddr, const int iMs )
|
||||
|
@ -1936,6 +2007,70 @@ bool CProtocol::EvaluateCLReqConnClientsListMes ( const CHostAddress& InetAddr )
|
|||
return false; // no error
|
||||
}
|
||||
|
||||
void CProtocol::CreateCLChannelLevelListMes ( const CHostAddress& InetAddr,
|
||||
const CVector<uint16_t>& vecLevelList,
|
||||
const int iNumClients )
|
||||
{
|
||||
// This must be a multiple of bytes at four bits per client
|
||||
const int iNumBytes = ( iNumClients + 1 ) / 2;
|
||||
CVector<uint8_t> vecData( iNumBytes );
|
||||
int iPos = 0; // init position pointer
|
||||
|
||||
for ( int i = 0, j = 0; i < iNumClients; i += 2 /* pack two per byte */, j++ )
|
||||
{
|
||||
uint16_t levelLo = vecLevelList[i] & 0x0F;
|
||||
uint16_t levelHi = ( i + 1 < iNumClients ) ? vecLevelList[i + 1] & 0x0F : 0x0F;
|
||||
uint8_t byte = static_cast<uint8_t> ( levelLo | ( levelHi << 4 ) );
|
||||
|
||||
PutValOnStream ( vecData, iPos,
|
||||
static_cast<uint32_t> ( byte ), 1 );
|
||||
}
|
||||
|
||||
CreateAndImmSendConLessMessage ( PROTMESSID_CLM_CHANNEL_LEVEL_LIST,
|
||||
vecData,
|
||||
InetAddr );
|
||||
}
|
||||
|
||||
bool CProtocol::EvaluateCLChannelLevelListMes ( const CHostAddress& InetAddr,
|
||||
const CVector<uint8_t>& vecData )
|
||||
{
|
||||
int iPos = 0; // init position pointer
|
||||
const int iDataLen = vecData.Size(); // four bits per channel, 2 channels per byte
|
||||
// may have one too many entries, last being 0xF
|
||||
int iVecLen = iDataLen * 2; // one ushort per channel
|
||||
|
||||
if ( iVecLen > MAX_NUM_CHANNELS )
|
||||
{
|
||||
return true; // return error code
|
||||
}
|
||||
|
||||
CVector<uint16_t> vecLevelList ( iVecLen );
|
||||
|
||||
for (int i = 0, j = 0; i < iDataLen; i++, j += 2 )
|
||||
{
|
||||
uint8_t byte = static_cast<uint8_t> ( GetValFromStream ( vecData, iPos, 1 ) );
|
||||
uint16_t levelLo = byte & 0x0F;
|
||||
uint16_t levelHi = ( byte >> 4 ) & 0x0F;
|
||||
|
||||
vecLevelList[j] = levelLo;
|
||||
|
||||
if ( levelHi != 0x0F )
|
||||
{
|
||||
vecLevelList[j + 1] = levelHi;
|
||||
}
|
||||
else
|
||||
{
|
||||
vecLevelList.resize ( iVecLen - 1 );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// invoke message action
|
||||
emit CLChannelLevelListReceived ( InetAddr, vecLevelList );
|
||||
|
||||
return false; // no error
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************\
|
||||
* Message generation and parsing *
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
#define PROTMESSID_CHANNEL_INFOS 25 // set channel infos
|
||||
#define PROTMESSID_OPUS_SUPPORTED 26 // tells that OPUS codec is supported
|
||||
#define PROTMESSID_LICENCE_REQUIRED 27 // licence required
|
||||
#define PROTMESSID_REQ_CHANNEL_LEVEL_LIST 28 // request the channel level list
|
||||
|
||||
// message IDs of connection less messages (CLM)
|
||||
// DEFINITION -> start at 1000, end at 1999, see IsConnectionLessMessageID
|
||||
|
@ -71,6 +72,7 @@
|
|||
#define PROTMESSID_CLM_REQ_VERSION_AND_OS 1012 // request version number and operating system
|
||||
#define PROTMESSID_CLM_CONN_CLIENTS_LIST 1013 // channel infos for connected clients
|
||||
#define PROTMESSID_CLM_REQ_CONN_CLIENTS_LIST 1014 // request the connected clients list
|
||||
#define PROTMESSID_CLM_CHANNEL_LEVEL_LIST 1015 // channel level list
|
||||
|
||||
// lengths of message as defined in protocol.cpp file
|
||||
#define MESS_HEADER_LENGTH_BYTE 7 // TAG (2), ID (2), cnt (1), length (2)
|
||||
|
@ -102,6 +104,7 @@ public:
|
|||
void CreateReqNetwTranspPropsMes();
|
||||
void CreateLicenceRequiredMes ( const ELicenceType eLicenceType );
|
||||
void CreateOpusSupportedMes();
|
||||
void CreateReqChannelLevelListMes ( const bool bRCL );
|
||||
|
||||
void CreateCLPingMes ( const CHostAddress& InetAddr, const int iMs );
|
||||
void CreateCLPingWithNumClientsMes ( const CHostAddress& InetAddr,
|
||||
|
@ -123,6 +126,9 @@ public:
|
|||
void CreateCLConnClientsListMes ( const CHostAddress& InetAddr,
|
||||
const CVector<CChannelInfo>& vecChanInfo );
|
||||
void CreateCLReqConnClientsListMes ( const CHostAddress& InetAddr );
|
||||
void CreateCLChannelLevelListMes ( const CHostAddress& InetAddr,
|
||||
const CVector<uint16_t>& vecLevelList,
|
||||
const int iNumClients );
|
||||
|
||||
static bool ParseMessageFrame ( const CVector<uint8_t>& vecbyData,
|
||||
const int iNumBytesIn,
|
||||
|
@ -216,6 +222,7 @@ protected:
|
|||
bool EvaluateNetwTranspPropsMes ( const CVector<uint8_t>& vecData );
|
||||
bool EvaluateReqNetwTranspPropsMes();
|
||||
bool EvaluateLicenceRequiredMes ( const CVector<uint8_t>& vecData );
|
||||
bool EvaluateReqChannelLevelListMes ( const CVector<uint8_t>& vecData );
|
||||
|
||||
bool EvaluateCLPingMes ( const CHostAddress& InetAddr,
|
||||
const CVector<uint8_t>& vecData );
|
||||
|
@ -236,6 +243,8 @@ protected:
|
|||
bool EvaluateCLConnClientsListMes ( const CHostAddress& InetAddr,
|
||||
const CVector<uint8_t>& vecData );
|
||||
bool EvaluateCLReqConnClientsListMes ( const CHostAddress& InetAddr );
|
||||
bool EvaluateCLChannelLevelListMes ( const CHostAddress& InetAddr,
|
||||
const CVector<uint8_t>& vecData );
|
||||
|
||||
int iOldRecID;
|
||||
int iOldRecCnt;
|
||||
|
@ -270,6 +279,7 @@ signals:
|
|||
void NetTranspPropsReceived ( CNetworkTransportProps NetworkTransportProps );
|
||||
void ReqNetTranspProps();
|
||||
void LicenceRequired ( ELicenceType eLicenceType );
|
||||
void ReqChannelLevelList ( bool bOptIn );
|
||||
|
||||
void CLPingReceived ( CHostAddress InetAddr,
|
||||
int iMs );
|
||||
|
@ -291,4 +301,6 @@ signals:
|
|||
void CLConnClientsListMesReceived ( CHostAddress InetAddr,
|
||||
CVector<CChannelInfo> vecChanInfo );
|
||||
void CLReqConnClientsList ( CHostAddress InetAddr );
|
||||
void CLChannelLevelListReceived ( CHostAddress InetAddr,
|
||||
CVector<uint16_t> vecLevelList );
|
||||
};
|
||||
|
|
BIN
src/res/homepage/displaychannellevels.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 60 KiB |
|
@ -81,11 +81,11 @@ The reverberation effect requires significant CPU so that it should only be used
|
|||
level fader is set to minimum (which is the default setting), the reverberation effect is switched off and does
|
||||
not cause any additional CPU usage.
|
||||
|
||||
### Local audio input fader
|
||||
### Local audio pan / balance control
|
||||
|
||||
![Local audio input fader](audiofader.jpg)
|
||||
![Local audio pan / balance control](audiofader.jpg)
|
||||
|
||||
With the audio fader, the relative levels of the left and right local audio channels can be changed. For a mono signal
|
||||
With the balance control, the relative levels of the left and right local audio channels can be changed. For a mono signal
|
||||
it acts like a panning between the two channels. If, e.g., a microphone is connected to the right input channel and
|
||||
an instrument is connected to the left input channel which is much louder than the microphone, move the audio fader
|
||||
in a direction where the label above the fader shows L -x, where x is the current attenuation indicator.
|
||||
|
@ -94,11 +94,13 @@ in a direction where the label above the fader shows L -x, where x is the curren
|
|||
|
||||
![Audio faders](faders.jpg)
|
||||
|
||||
In the audio mixer frame, a fader for each connected client at the server is shown. This includes a fader for the own signal.
|
||||
With the faders, the audio level of each client can be modified individually.
|
||||
In the audio mixer frame, a fader is shown for each connected client at the server, including yourself.
|
||||
The faders allow you to adjust the level of what you hear without affecting what others hear.
|
||||
The VU meter shows the input level at the server - that is, what you are sending.
|
||||
|
||||
With the Mute checkbox, the current audio channel can be muted. With the Solo checkbox, the current audio channel can
|
||||
be set to solo which means that all other channels except of the current channel are muted.
|
||||
Using the Mute checkbox prevents the indicated channel being heard in your local mix.
|
||||
|
||||
The solo checkboxes allow you to hear only one, or several, channels, with those not soloed being muted.
|
||||
|
||||
Settings Window
|
||||
---------------
|
||||
|
@ -206,6 +208,12 @@ that client was already stored.
|
|||
|
||||
If enabled, a fancy skin will be applied to the main window.
|
||||
|
||||
### Display channel levels
|
||||
|
||||
![Display channel levels](displaychannellevels.png)
|
||||
|
||||
If enabled, the channel input level for each connected client will be displayed in the mixer.
|
||||
|
||||
### Central server address
|
||||
|
||||
![Central server address](centralserveraddress.png)
|
||||
|
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 71 KiB |
|
@ -335,6 +335,8 @@ CServer::CServer ( const int iNewMaxNumChan,
|
|||
// allocate worst case memory for the coded data
|
||||
vecbyCodedData.Init ( MAX_SIZE_BYTES_NETW_BUF );
|
||||
|
||||
// allocate worst case memory for the channel levels
|
||||
vecChannelLevels.Init ( iMaxNumChannels );
|
||||
|
||||
// enable history graph (if requested)
|
||||
if ( !strHistoryFileName.isEmpty() )
|
||||
|
@ -864,6 +866,7 @@ JitterMeas.Measure();
|
|||
// some inits
|
||||
int iNumClients = 0; // init connected client counter
|
||||
bool bChannelIsNowDisconnected = false;
|
||||
bool bSendChannelLevels = false;
|
||||
|
||||
// Make put and get calls thread safe. Do not forget to unlock mutex
|
||||
// afterwards!
|
||||
|
@ -1007,6 +1010,29 @@ JitterMeas.Measure();
|
|||
// one client is connected.
|
||||
if ( iNumClients > 0 )
|
||||
{
|
||||
|
||||
// Low frequency updates
|
||||
if ( iFrameCount > CHANNEL_LEVEL_UPDATE_INTERVAL )
|
||||
{
|
||||
iFrameCount = 0;
|
||||
|
||||
// Calculate channel levels if any client has requested them
|
||||
for ( int i = 0; i < iNumClients; i++ )
|
||||
{
|
||||
if ( vecChannels[ vecChanIDsCurConChan[i] ].ChannelLevelsRequired() )
|
||||
{
|
||||
bSendChannelLevels = true;
|
||||
|
||||
CreateLevelsForAllConChannels ( iNumClients,
|
||||
vecNumAudioChannels,
|
||||
vecvecsData,
|
||||
vecChannelLevels );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
iFrameCount++;
|
||||
|
||||
for ( int i = 0; i < iNumClients; i++ )
|
||||
{
|
||||
// get actual ID of current channel
|
||||
|
@ -1095,6 +1121,12 @@ opus_custom_encoder_ctl ( CurOpusEncoder,
|
|||
|
||||
// update socket buffer size
|
||||
vecChannels[iCurChanID].UpdateSocketBufferSize();
|
||||
|
||||
// send channel levels
|
||||
if ( bSendChannelLevels && vecChannels[iCurChanID].ChannelLevelsRequired() )
|
||||
{
|
||||
ConnLessProtocol.CreateCLChannelLevelListMes ( vecChannels[iCurChanID].GetAddress(), vecChannelLevels, iNumClients );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1574,3 +1606,69 @@ void CServer::customEvent ( QEvent* pEvent )
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Compute frame peak level for each client
|
||||
void CServer::CreateLevelsForAllConChannels ( const int iNumClients,
|
||||
const CVector<int>& vecNumAudioChannels,
|
||||
const CVector<CVector<int16_t> > vecvecsData,
|
||||
CVector<uint16_t>& vecLevelsOut )
|
||||
{
|
||||
int i, j, k;
|
||||
|
||||
// init return vector with zeros since we mix all channels on that vector
|
||||
vecLevelsOut.Reset ( 0 );
|
||||
|
||||
for ( j = 0; j < iNumClients; j++ )
|
||||
{
|
||||
// get a reference to the audio data
|
||||
const CVector<int16_t>& vecsData = vecvecsData[j];
|
||||
|
||||
double dCurLevel = 0.0;
|
||||
if ( vecNumAudioChannels[j] == 1 )
|
||||
{
|
||||
// mono
|
||||
for ( i = 0; i < SYSTEM_FRAME_SIZE_SAMPLES; i += 3 )
|
||||
{
|
||||
dCurLevel = std::max ( dCurLevel, std::abs ( static_cast<double> ( vecsData[i] ) ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// stereo: apply stereo-to-mono attenuation
|
||||
for ( i = 0, k = 0; i < SYSTEM_FRAME_SIZE_SAMPLES; i += 3, k += 6 )
|
||||
{
|
||||
double sMix = ( static_cast<double> ( vecsData[k] ) + vecsData[k + 1] ) / 2;
|
||||
dCurLevel = std::max ( dCurLevel, std::abs ( sMix ) );
|
||||
}
|
||||
}
|
||||
|
||||
// smoothing
|
||||
int iChId = vecChanIDsCurConChan [ j ];
|
||||
dCurLevel = std::max ( dCurLevel, vecChannels[ iChId ].GetPrevLevel() * 0.5 );
|
||||
vecChannels[ iChId ].SetPrevLevel ( dCurLevel );
|
||||
|
||||
// logarithmic measure
|
||||
const double dNormChanLevel = dCurLevel / _MAXSHORT;
|
||||
double dCurSigLevel;
|
||||
if ( dNormChanLevel > 0 )
|
||||
{
|
||||
dCurSigLevel = 20.0 * log10 ( dNormChanLevel );
|
||||
}
|
||||
else
|
||||
{
|
||||
dCurSigLevel = -100000.0; // large negative value
|
||||
}
|
||||
|
||||
// map to signal level meter
|
||||
dCurSigLevel -= LOW_BOUND_SIG_METER;
|
||||
dCurSigLevel *= NUM_STEPS_LED_BAR /
|
||||
( UPPER_BOUND_SIG_METER - LOW_BOUND_SIG_METER );
|
||||
|
||||
if ( dCurSigLevel < 0 )
|
||||
{
|
||||
dCurSigLevel = 0;
|
||||
}
|
||||
|
||||
vecLevelsOut[j] = static_cast<uint16_t> ( ceil ( dCurSigLevel ) );
|
||||
}
|
||||
}
|
||||
|
|
12
src/server.h
|
@ -28,6 +28,7 @@
|
|||
#include <QTimer>
|
||||
#include <QDateTime>
|
||||
#include <QHostAddress>
|
||||
#include <algorithm>
|
||||
#ifdef USE_OPUS_SHARED_LIB
|
||||
# include "opus/opus_custom.h"
|
||||
#else
|
||||
|
@ -225,6 +226,11 @@ protected:
|
|||
// if server mode is normal or double system frame size
|
||||
bool bUseDoubleSystemFrameSize;
|
||||
|
||||
void 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];
|
||||
|
@ -255,12 +261,18 @@ protected:
|
|||
CVector<int16_t> vecsSendData;
|
||||
CVector<uint8_t> vecbyCodedData;
|
||||
|
||||
// Channel levels
|
||||
CVector<uint16_t> vecChannelLevels;
|
||||
|
||||
// actual working objects
|
||||
CHighPrioSocket Socket;
|
||||
|
||||
// logging
|
||||
CServerLogging Logging;
|
||||
|
||||
// channel level update frame interval counter
|
||||
uint16_t iFrameCount;
|
||||
|
||||
// recording thread
|
||||
recorder::CJamRecorder JamRecorder;
|
||||
bool bEnableRecording;
|
||||
|
|
|
@ -250,6 +250,12 @@ void CSettings::Load()
|
|||
pClient->SetGUIDesign ( static_cast<EGUIDesign> ( iValue ) );
|
||||
}
|
||||
|
||||
// display channel levels preference
|
||||
if ( GetFlagIniSet ( IniXMLDocument, "client", "displaychannellevels", bValue ) )
|
||||
{
|
||||
pClient->SetDisplayChannelLevels ( bValue );
|
||||
}
|
||||
|
||||
// audio channels
|
||||
if ( GetNumericIniSet ( IniXMLDocument, "client", "audiochannels",
|
||||
0, 2 /* CC_STEREO */, iValue ) )
|
||||
|
@ -490,6 +496,10 @@ void CSettings::Save()
|
|||
SetNumericIniSet ( IniXMLDocument, "client", "guidesign",
|
||||
static_cast<int> ( pClient->GetGUIDesign() ) );
|
||||
|
||||
// display channel levels preference
|
||||
SetFlagIniSet ( IniXMLDocument, "client", "displaychannellevels",
|
||||
pClient->GetDisplayChannelLevels() );
|
||||
|
||||
// audio channels
|
||||
SetNumericIniSet ( IniXMLDocument, "client", "audiochannels",
|
||||
static_cast<int> ( pClient->GetAudioChannels() ) );
|
||||
|
|