Skip to content

Commit

Permalink
Fix connection status issue (#2519)
Browse files Browse the repository at this point in the history
This is a manual port of #2550 by @pgScorpio

Co-authored-by: ann0see <[email protected]>
  • Loading branch information
pgScorpio and ann0see committed Sep 8, 2024
1 parent 5227d1c commit 38fb414
Show file tree
Hide file tree
Showing 9 changed files with 208 additions and 220 deletions.
31 changes: 29 additions & 2 deletions src/channel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ CChannel::CChannel ( const bool bNIsServer ) :
bIsEnabled ( false ),
bIsServer ( bNIsServer ),
bIsIdentified ( false ),
bDisconnectAndDisable ( false ),
iAudioFrameSizeSamples ( DOUBLE_SYSTEM_FRAME_SIZE_SAMPLES ),
SignalLevelMeter ( false, 0.5 ) // server mode with mono out and faster smoothing
{
Expand Down Expand Up @@ -125,7 +126,8 @@ void CChannel::SetEnable ( const bool bNEnStat )
QMutexLocker locker ( &Mutex );

// set internal parameter
bIsEnabled = bNEnStat;
bIsEnabled = bNEnStat;
bDisconnectAndDisable = false;

// The support for the packet sequence number must be reset if the client
// disconnects from a server since we do not yet know if the next server we
Expand Down Expand Up @@ -506,11 +508,24 @@ void CChannel::Disconnect()
// we only have to disconnect the channel if it is actually connected
if ( IsConnected() )
{
// for a Client, block further audio data and disable the channel as soon as Disconnect() is called
// TODO: Add reasoning from #2550

bDisconnectAndDisable = !bIsServer;

// set time out counter to a small value > 0 so that the next time a
// received audio block is queried, the disconnection is performed
// (assuming that no audio packet is received in the meantime)
iConTimeOut = 1; // a small number > 0
}
else if ( !bIsServer )
{
// For clients (?) set defaults

bDisconnectAndDisable = false;
bIsEnabled = false;
iConTimeOut = 0;
}
}

void CChannel::PutProtocolData ( const int iRecCounter, const int iRecID, const CVector<uint8_t>& vecbyMesBodyData, const CHostAddress& RecHostAddr )
Expand All @@ -534,7 +549,7 @@ EPutDataStat CChannel::PutAudioData ( const CVector<uint8_t>& vecbyData, const i
// Only process audio data if:
// - for client only: the packet comes from the server we want to talk to
// - the channel is enabled
if ( ( bIsServer || ( GetAddress() == RecHostAddr ) ) && IsEnabled() )
if ( ( bIsServer || ( GetAddress() == RecHostAddr ) ) && IsEnabled() && !bDisconnectAndDisable )
{
MutexSocketBuf.lock();
{
Expand Down Expand Up @@ -622,6 +637,11 @@ EGetDataStat CChannel::GetData ( CVector<uint8_t>& vecbyData, const int iNumByte
eGetStatus = GS_CHAN_NOW_DISCONNECTED;
iConTimeOut = 0; // make sure we do not have negative values

if ( bDisconnectAndDisable )
{
bDisconnectAndDisable = false;
bIsEnabled = false;
}
// reset network transport properties
ResetNetworkTransportProperties();
}
Expand All @@ -643,6 +663,13 @@ EGetDataStat CChannel::GetData ( CVector<uint8_t>& vecbyData, const int iNumByte
{
// channel is disconnected
eGetStatus = GS_CHAN_NOT_CONNECTED;

if ( bDisconnectAndDisable )
{
bDisconnectAndDisable = false;
bIsEnabled = false;
iConTimeOut = 0;
}
}
}
MutexSocketBuf.unlock();
Expand Down
3 changes: 2 additions & 1 deletion src/channel.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class CChannel : public QObject

void PrepAndSendPacket ( CHighPrioSocket* pSocket, const CVector<uint8_t>& vecbyNPacket, const int iNPacketLen );

void ResetTimeOutCounter() { iConTimeOut = iConTimeOutStartVal; }
void ResetTimeOutCounter() { iConTimeOut = bDisconnectAndDisable ? 1 : iConTimeOutStartVal; }
bool IsConnected() const { return iConTimeOut > 0; }
void Disconnect();

Expand Down Expand Up @@ -216,6 +216,7 @@ class CChannel : public QObject
bool bIsEnabled;
bool bIsServer;
bool bIsIdentified;
bool bDisconnectAndDisable;

int iNetwFrameSizeFact;
int iNetwFrameSize;
Expand Down
173 changes: 97 additions & 76 deletions src/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
/* Implementation *************************************************************/
CClient::CClient ( const quint16 iPortNumber,
const quint16 iQosNumber,
const QString& strConnOnStartupAddress,
const QString& strMIDISetup,
const bool bNoAutoJackConnect,
const QString& strNClientName,
Expand Down Expand Up @@ -184,13 +183,6 @@ CClient::CClient ( const quint16 iPortNumber,
// start the socket (it is important to start the socket after all
// initializations and connections)
Socket.Start();

// do an immediate start if a server address is given
if ( !strConnOnStartupAddress.isEmpty() )
{
SetServerAddr ( strConnOnStartupAddress );
Start();
}
}

CClient::~CClient()
Expand Down Expand Up @@ -337,7 +329,7 @@ void CClient::CreateServerJitterBufferMessage()
void CClient::OnCLPingReceived ( CHostAddress InetAddr, int iMs )
{
// make sure we are running and the server address is correct
if ( IsRunning() && ( InetAddr == Channel.GetAddress() ) )
if ( Channel.IsEnabled() && ( InetAddr == Channel.GetAddress() ) )
{
// take care of wrap arounds (if wrapping, do not use result)
const int iCurDiff = EvaluatePingMessage ( iMs );
Expand Down Expand Up @@ -474,26 +466,6 @@ void CClient::StartDelayTimer()
}
}

bool CClient::SetServerAddr ( QString strNAddr )
{
CHostAddress HostAddress;
#ifdef CLIENT_NO_SRV_CONNECT
if ( NetworkUtil().ParseNetworkAddress ( strNAddr, HostAddress, bEnableIPv6 ) )
#else
if ( NetworkUtil().ParseNetworkAddressWithSrvDiscovery ( strNAddr, HostAddress, bEnableIPv6 ) )
#endif
{
// apply address to the channel
Channel.SetAddress ( HostAddress );

return true;
}
else
{
return false; // invalid address
}
}

bool CClient::GetAndResetbJitterBufferOKFlag()
{
// get the socket buffer put status flag and reset it
Expand Down Expand Up @@ -626,12 +598,16 @@ QString CClient::SetSndCrdDev ( const QString strNewDev )
Sound.Start();
}

// in case of an error inform the GUI about it
if ( !strError.isEmpty() )
{
emit SoundDeviceChanged ( strError );
// due to error, disconnect
Disconnect();
}

// in case of an error, this will inform the GUI about it

emit SoundDeviceChanged();

return strError;
}

Expand Down Expand Up @@ -758,8 +734,18 @@ void CClient::OnSndCrdReinitRequest ( int iSndCrdResetType )
}
MutexDriverReinit.unlock();

if ( !strError.isEmpty() )
{
#ifndef HEADLESS
QMessageBox::critical ( 0, APP_NAME, strError, tr ( "Ok" ) );
#else
qCritical() << qUtf8Printable ( strError );
exit ( 1 );
#endif
}

// inform GUI about the sound card device change
emit SoundDeviceChanged ( strError );
emit SoundDeviceChanged();
}

void CClient::OnHandledSignal ( int sigNum )
Expand All @@ -773,11 +759,8 @@ void CClient::OnHandledSignal ( int sigNum )
{
case SIGINT:
case SIGTERM:
// if connected, terminate connection (needed for headless mode)
if ( IsRunning() )
{
Stop();
}
// if connected, terminate connection
Disconnect();

// this should trigger OnAboutToQuit
QCoreApplication::instance()->exit();
Expand Down Expand Up @@ -862,50 +845,88 @@ void CClient::OnClientIDReceived ( int iChanID )
emit ClientIDReceived ( iChanID );
}

void CClient::Start()
bool CClient::Connect ( QString strServerAddress, QString strServerName )
{
// init object
Init();
if ( !Channel.IsEnabled() )
{
CHostAddress HostAddress;

if ( NetworkUtil().ParseNetworkAddress ( strServerAddress, HostAddress, bEnableIPv6 ) )
{
// init object
Init();
// apply address to the channel
Channel.SetAddress ( HostAddress );

// enable channel
Channel.SetEnable ( true );
// enable channel
Channel.SetEnable ( true );

// start audio interface
Sound.Start();
// start audio interface
Sound.Start();

// Notify ClientDlg
emit Connecting ( strServerName );

return true;
}
}

return false;
}

void CClient::Stop()
bool CClient::Disconnect()
{
// stop audio interface
Sound.Stop();

// disable channel
Channel.SetEnable ( false );

// wait for approx. 100 ms to make sure no audio packet is still in the
// network queue causing the channel to be reconnected right after having
// received the disconnect message (seems not to gain much, disconnect is
// still not working reliably)
QTime DieTime = QTime::currentTime().addMSecs ( 100 );
while ( QTime::currentTime() < DieTime )
{
// exclude user input events because if we use AllEvents, it happens
// that if the user initiates a connection and disconnection quickly
// (e.g. quickly pressing enter five times), the software can get into
// an unknown state
QCoreApplication::processEvents ( QEventLoop::ExcludeUserInputEvents, 100 );
}

// Send disconnect message to server (Since we disable our protocol
// receive mechanism with the next command, we do not evaluate any
// respond from the server, therefore we just hope that the message
// gets its way to the server, if not, the old behaviour time-out
// disconnects the connection anyway).
ConnLessProtocol.CreateCLDisconnection ( Channel.GetAddress() );

// reset current signal level and LEDs
bJitterBufferOK = true;
SignalLevelMeter.Reset();
if ( Channel.IsEnabled() )
{
// start disconnection
Channel.Disconnect();

// Channel.Disconnect() should automatically disable Channel as soon as disconnected.
// Note that this only works if Sound is Active !

QTime DieTime = QTime::currentTime().addMSecs ( 500 );
while ( ( QTime::currentTime() < DieTime ) && Channel.IsEnabled() )
{
// exclude user input events because if we use AllEvents, it happens
// that if the user initiates a connection and disconnection quickly
// (e.g. quickly pressing enter five times), the software can get into
// an unknown state
QCoreApplication::processEvents ( QEventLoop::ExcludeUserInputEvents, 100 );
}

// Now stop the audio interface
Sound.Stop();

// in case we timed out, log warning and make sure Channel is disabled
if ( Channel.IsEnabled() )
{
Channel.SetEnable ( false );
}

// Send disconnect message to server (Since we disable our protocol
// receive mechanism with the next command, we do not evaluate any
// respond from the server, therefore we just hope that the message
// gets its way to the server, if not, the old behaviour time-out
// disconnects the connection anyway).
ConnLessProtocol.CreateCLDisconnection ( Channel.GetAddress() );

// reset current signal level and LEDs
bJitterBufferOK = true;
SignalLevelMeter.Reset();

emit Disconnected();

return true;
}
else
{
// make sure sound is stopped too
Sound.Stop();

emit Disconnected();

return false;
}
}

void CClient::Init()
Expand All @@ -921,7 +942,7 @@ void CClient::Init()
bFraSiFactSafeSupported = true;
#else
bFraSiFactPrefSupported = ( Sound.Init ( iFraSizePreffered ) == iFraSizePreffered );
bFraSiFactDefSupported = ( Sound.Init ( iFraSizeDefault ) == iFraSizeDefault );
bFraSiFactDefSupported = ( Sound.Init ( iFraSizeDefault ) == iFraSizeDefault );
bFraSiFactSafeSupported = ( Sound.Init ( iFraSizeSafe ) == iFraSizeSafe );
#endif

Expand Down
16 changes: 7 additions & 9 deletions src/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,6 @@ class CClient : public QObject
public:
CClient ( const quint16 iPortNumber,
const quint16 iQosNumber,
const QString& strConnOnStartupAddress,
const QString& strMIDISetup,
const bool bNoAutoJackConnect,
const QString& strNClientName,
Expand All @@ -119,19 +118,17 @@ class CClient : public QObject

virtual ~CClient();

void Start();
void Stop();
bool IsRunning() { return Sound.IsRunning(); }
bool IsCallbackEntered() const { return Sound.IsCallbackEntered(); }
bool SetServerAddr ( QString strNAddr );
bool Connect ( QString strServerAddress, QString strServerName );
bool Disconnect();

bool SoundIsRunning() const { return Sound.IsCallbackEntered(); } // For OnTimerCheckAudioDeviceOk only
bool IsConnected() { return Channel.IsConnected(); }

double GetLevelForMeterdBLeft() { return SignalLevelMeter.GetLevelForMeterdBLeftOrMono(); }
double GetLevelForMeterdBRight() { return SignalLevelMeter.GetLevelForMeterdBRight(); }

bool GetAndResetbJitterBufferOKFlag();

bool IsConnected() { return Channel.IsConnected(); }

EGUIDesign GetGUIDesign() const { return eGUIDesign; }
void SetGUIDesign ( const EGUIDesign eNGD ) { eGUIDesign = eNGD; }

Expand Down Expand Up @@ -427,8 +424,9 @@ protected slots:

void CLChannelLevelListReceived ( CHostAddress InetAddr, CVector<uint16_t> vecLevelList );

void Connecting ( QString strServerName );
void Disconnected();
void SoundDeviceChanged ( QString strError );
void SoundDeviceChanged();
void ControllerInFaderLevel ( int iChannelIdx, int iValue );
void ControllerInPanValue ( int iChannelIdx, int iValue );
void ControllerInFaderIsSolo ( int iChannelIdx, bool bIsSolo );
Expand Down
Loading

0 comments on commit 38fb414

Please sign in to comment.