Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix connection status issue (#2519) #3364

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 35 additions & 3 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 @@ -511,6 +513,24 @@ void CChannel::Disconnect()
// (assuming that no audio packet is received in the meantime)
iConTimeOut = 1; // a small number > 0
}

if ( !bIsServer )
{
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 = true;
}
else
{
// For disconnected clients set defaults
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why isn't this done when the disconnect actually happens, rather than here? Like in line 645? Is this just duplicated? Or is there a reason for it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there's a reason for it.
It's probably trying to ensure that bDisconnectAndDisable is representing the client being in process of disconnecting?

Copy link
Collaborator

@pljones pljones Sep 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see what job it's doing that setting iConTimeOut to 1 doesn't already do. It still needs iConTimeOut set to 1, too, so it just adds complexity rather than removing it, without improving readability either.


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 @@ -532,9 +552,9 @@ EPutDataStat CChannel::PutAudioData ( const CVector<uint8_t>& vecbyData, const i
EPutDataStat eRet = PS_GEN_ERROR;

// Only process audio data if:
// - for client only: the packet comes from the server we want to talk to
// - for client only: the packet comes from the server we want to talk to and we aren't disconnecting
// - the channel is enabled
if ( ( bIsServer || ( GetAddress() == RecHostAddr ) ) && IsEnabled() )
if ( ( bIsServer || ( !bIsServer && GetAddress() == RecHostAddr && !bDisconnectAndDisable ) ) && IsEnabled() )
{
MutexSocketBuf.lock();
{
Expand Down Expand Up @@ -622,6 +642,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 && !bIsServer )
{
bDisconnectAndDisable = false;
bIsEnabled = false;
}
// reset network transport properties
ResetNetworkTransportProperties();
}
Expand All @@ -643,6 +668,13 @@ EGetDataStat CChannel::GetData ( CVector<uint8_t>& vecbyData, const int iNumByte
{
// channel is disconnected
eGetStatus = GS_CHAN_NOT_CONNECTED;

if ( bDisconnectAndDisable && !bIsServer )
{
bDisconnectAndDisable = false;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

??! So these get set to the same values whether eGetStatus is GS_CHAN_NOW_DISCONNECTED or GS_CHAN_NOT_CONNECTED? Now I'm really confused.

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 && !bIsServer ) ? 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
87 changes: 62 additions & 25 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();
}
ann0see marked this conversation as resolved.
Show resolved Hide resolved
}

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() ) )
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't about the channel being enabled. It's about whether the client is running. It's a different intent.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the initial PR confused active channel and active client: #2550 (comment)

This difference needs documentation. IMO: Add (like for JSON-RPC) respective technical documentation before the respective methods. As end goal: Write them for every function, for now: Write docs while changing.

{
// take care of wrap arounds (if wrapping, do not use result)
const int iCurDiff = EvaluatePingMessage ( iMs );
Expand Down Expand Up @@ -773,11 +765,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 @@ -876,18 +865,13 @@ void CClient::Start()

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

// disable channel
Channel.SetEnable ( false );
// start disconnection
// Channel.Disconnect() should automatically disable Channel as soon as disconnected.
// Note that this only works if sound is active!
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So why make the changes here?

Copy link
Member Author

@ann0see ann0see Sep 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe it's mainly moving around the Channel.Disconnect() and Sound.Stop() code around.

This may be the actual bug fix?

Channel.Disconnect();

// 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 )
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
Expand All @@ -896,6 +880,19 @@ void CClient::Stop()
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() )
{
//### TODO: BEGIN ###//
// Add error logging
//### TODO: END ###//

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
Expand All @@ -908,6 +905,46 @@ void CClient::Stop()
SignalLevelMeter.Reset();
}

bool CClient::Connect ( QString strServerAddress, QString strServerName )
ann0see marked this conversation as resolved.
Show resolved Hide resolved
{
if ( !Channel.IsEnabled() )
{
// Set server address and connect if valid address was supplied
if ( SetServerAddr ( strServerAddress ) )
{

Start();

emit Connecting ( strServerName );

return true;
}
}

return false;
}

bool CClient::Disconnect()
{
if ( Channel.IsEnabled() )
{
Stop();

emit Disconnected();

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

emit Disconnected();

return false;
}
}

void CClient::Init()
{
// check if possible frame size factors are supported
Expand Down
7 changes: 5 additions & 2 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 @@ -121,8 +120,11 @@ class CClient : public QObject

void Start();
void Stop();
bool Connect ( QString strServerAddress, QString strServerName );
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does make sense to introduce an easy to call Connect() and Disconnect() method IMO, so this is good.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having these in client.cpp rather than clientdlg.cpp is important. It's important enough to be done in a single PR on its own. I think we should start with that.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree. That's issue #3367

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Factored out into #3372

bool Disconnect();

bool IsRunning() { return Sound.IsRunning(); }
bool IsCallbackEntered() const { return Sound.IsCallbackEntered(); }
bool IsCallbackEntered() const { return Sound.IsCallbackEntered(); } // For OnTimerCheckAudioDeviceOk only
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted naming. May need some in depth review and discussion.

bool SetServerAddr ( QString strNAddr );

double GetLevelForMeterdBLeft() { return SignalLevelMeter.GetLevelForMeterdBLeftOrMono(); }
Expand Down Expand Up @@ -427,6 +429,7 @@ protected slots:

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

void Connecting ( QString strServerName );
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably a missing slot.

void Disconnected();
void SoundDeviceChanged ( QString strError );
void ControllerInFaderLevel ( int iChannelIdx, int iValue );
Expand Down
Loading