@@ -59,6 +59,7 @@ CClient::CClient ( const quint16 iPortNumber,
5959 strClientName ( strNClientName ),
6060 pSignalHandler ( CSignalHandler::getSingletonP() ),
6161 pSettings ( nullptr ),
62+ eConnectionState ( CS_DISCONNECTED ),
6263 Channel ( false ), /* we need a client channel -> "false" */
6364 CurOpusEncoder ( nullptr ),
6465 CurOpusDecoder ( nullptr ),
@@ -145,7 +146,7 @@ CClient::CClient ( const quint16 iPortNumber,
145146 // The first ConClientListMesReceived handler performs the necessary cleanup and has to run first:
146147 QObject::connect ( &Channel, &CChannel::ConClientListMesReceived, this , &CClient::OnConClientListMesReceived );
147148
148- QObject::connect ( &Channel, &CChannel::Disconnected, this , &CClient::Disconnected );
149+ QObject::connect ( &Channel, &CChannel::Disconnected, this , &CClient::Stop );
149150
150151 QObject::connect ( &Channel, &CChannel::NewConnection, this , &CClient::OnNewConnection );
151152
@@ -626,6 +627,9 @@ bool CClient::SetServerAddr ( QString strNAddr )
626627 // apply address to the channel
627628 Channel.SetAddress ( HostAddress );
628629
630+ // By default, set server name to HostAddress. If using the Connect() method, this may be overwritten
631+ SetConnectedServerName ( HostAddress.toString () );
632+
629633 return true ;
630634 }
631635 else
@@ -929,11 +933,9 @@ void CClient::OnHandledSignal ( int sigNum )
929933 {
930934 case SIGINT :
931935 case SIGTERM :
932- // if connected, terminate connection (needed for headless mode)
933- if ( IsRunning () )
934- {
935- Stop ();
936- }
936+ // tear down any pending or established connection first, so the server
937+ // is notified we are leaving (Disconnect() is a no-op if not connected)
938+ Disconnect ();
937939
938940 // this should trigger OnAboutToQuit
939941 QCoreApplication::instance ()->exit ();
@@ -1027,6 +1029,9 @@ void CClient::OnClientIDReceived ( int iServerChanID )
10271029 SetRemoteChanGain ( iChanID, 0 , false );
10281030 }
10291031
1032+ // the server has assigned us a channel ID, so the connection is established
1033+ SetConnectionState ( CS_CONNECTED );
1034+
10301035 emit ClientIDReceived ( iChanID );
10311036}
10321037
@@ -1069,8 +1074,19 @@ void CClient::Start()
10691074 // Disable hibernation or display dimming if the app is running on Windows
10701075 SetThreadExecutionState ( ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED );
10711076#endif
1077+
1078+ // the connection is requested now but not yet established: the transition
1079+ // to CS_CONNECTED happens when the server assigns our channel ID
1080+ // (see OnClientIDReceived)
1081+ SetConnectionState ( CS_CONNECTING );
1082+
1083+ emit Connecting ( GetConnectedServerName () );
10721084}
10731085
1086+ // / @method
1087+ // / @brief Stops client and disconnects from server
1088+ // / @emit Disconnected
1089+ // / Use to set CClientDlg to show not being connected
10741090void CClient::Stop ()
10751091{
10761092 // stop audio interface
@@ -1081,7 +1097,16 @@ void CClient::Stop()
10811097
10821098 // Fall back to opus in case raw was used
10831099 bRawAudioIsSupported = false ;
1084- Init ();
1100+ try
1101+ {
1102+ Init ();
1103+ }
1104+ catch ( const CGenErr& generr )
1105+ {
1106+ // a dead audio backend (e.g. JACK was shut down) must not prevent the
1107+ // disconnect message below from reaching the server
1108+ qWarning () << " Could not reinitialise the sound device while disconnecting:" << generr.GetErrorText ();
1109+ }
10851110
10861111 // wait for approx. 100 ms to make sure no audio packet is still in the
10871112 // network queue causing the channel to be reconnected right after having
@@ -1112,6 +1137,74 @@ void CClient::Stop()
11121137 // Allow hibernation or display dimming if the app is running again (Windows)
11131138 SetThreadExecutionState ( ES_CONTINUOUS );
11141139#endif
1140+
1141+ SetConnectionState ( CS_DISCONNECTED );
1142+
1143+ // emit Disconnected() to inform UI of disconnection
1144+ emit Disconnected ();
1145+ }
1146+
1147+ // / @method
1148+ // / @brief Disconnects from the server if a connection is requested or established.
1149+ // / Idempotent: a no-op when already disconnected.
1150+ // / @emit Disconnected
1151+ void CClient::Disconnect ()
1152+ {
1153+ // Key off the connection state, not IsRunning() (which tracks the audio
1154+ // device): the two diverge while connecting and in headless mode, and on
1155+ // SIGTERM we must still send the disconnect message to the server.
1156+ if ( GetConnectionState () != CS_DISCONNECTED )
1157+ {
1158+ Stop ();
1159+ }
1160+ }
1161+
1162+ // / @method
1163+ // / @brief Connects to strServerAddress. If a connection is currently requested
1164+ // / or established, that connection is terminated first.
1165+ // / @emit Connecting (strServerName) if SetServerAddr was valid. emit happens through Start().
1166+ // / Use to set CClientDlg to show being connected
1167+ // / @emit ConnectingFailed (error) if an error occurred
1168+ // / Use to display error message in CClientDlg
1169+ // / @param strServerAddress - the server address to connect to
1170+ // / @param strServerName - the human readable server name passed to Connecting()
1171+ void CClient::Connect ( const QString& strServerAddress, const QString& strServerName )
1172+ {
1173+ try
1174+ {
1175+ // disconnect from any current server first so that connecting to a
1176+ // different server while connected behaves as a reconnect
1177+ Disconnect ();
1178+
1179+ // Set server address and connect if valid address was supplied
1180+ if ( SetServerAddr ( strServerAddress ) )
1181+ {
1182+ SetConnectedServerName ( strServerName );
1183+ Start ();
1184+ }
1185+ else
1186+ {
1187+ throw CGenErr ( tr ( " Received invalid server address. Please check for typos in the provided server address." ) );
1188+ }
1189+ }
1190+ catch ( const CGenErr& generr )
1191+ {
1192+ Stop ();
1193+ emit ConnectingFailed ( generr.GetErrorText () );
1194+ }
1195+ }
1196+
1197+ // / @method
1198+ // / @brief Updates the connection state and, if it changed, notifies observers.
1199+ // / @emit ConnectionStateChanged (state) when the state actually changes
1200+ // / @param eNewConnectionState - the state to transition to
1201+ void CClient::SetConnectionState ( const EConnectionState eNewConnectionState )
1202+ {
1203+ if ( eConnectionState != eNewConnectionState )
1204+ {
1205+ eConnectionState = eNewConnectionState;
1206+ emit ConnectionStateChanged ( eConnectionState );
1207+ }
11151208}
11161209
11171210void CClient::Init ()
0 commit comments