[AFV] Signal/handling for authentication failures

* authentication issues in AFV were silently handled
* and there was no re-try, which could mean an initial glitch COULD cause AFV not working properly
* NOW handling in AFV client and context
* also reset connection data so for a new session no old authentication token or check time is used
* check for "invalid" QDateTime(s)
This commit is contained in:
Klaus Basan
2020-04-27 19:04:01 +02:00
committed by Mat Sutcliffe
parent 9e6716e515
commit bba07ef4c4
13 changed files with 146 additions and 34 deletions

View File

@@ -62,7 +62,7 @@ namespace BlackCore
m_output(new COutput(this)), m_output(new COutput(this)),
m_voiceServerTimer(new QTimer(this)) m_voiceServerTimer(new QTimer(this))
{ {
this->setObjectName("AFV client: " + apiServer ); this->setObjectName("AFV client: " + apiServer);
m_connection->setReceiveAudio(false); m_connection->setReceiveAudio(false);
connect(m_input, &CInput::opusDataAvailable, this, &CAfvClient::opusDataAvailable); connect(m_input, &CInput::opusDataAvailable, this, &CAfvClient::opusDataAvailable);
@@ -144,7 +144,7 @@ namespace BlackCore
} }
const bool integrated = sApp->getIContextSimulator()->getSimulatorSettings().isComIntegrated(); const bool integrated = sApp->getIContextSimulator()->getSimulatorSettings().isComIntegrated();
const bool changed = integrated != m_integratedComUnit; const bool changed = integrated != m_integratedComUnit;
m_integratedComUnit = integrated; m_integratedComUnit = integrated;
if (changed) if (changed)
@@ -167,9 +167,21 @@ namespace BlackCore
this->connectWithContexts(); this->connectWithContexts();
this->setCallsign(callsign); this->setCallsign(callsign);
QPointer<CAfvClient> myself(this);
if (!this->isConnected() && m_retryConnectAttempt == 0)
{
// check if connect simply did NOT receive an answer
QTimer::singleShot(20 * 1000, this, [ = ]
{
if (!myself) { return; }
if (m_retryConnectAttempt > 0) { return; } // already handled
// this will reconnect ONLY if not already connected
this->retryConnectTo(cid, password, callsign, client, QStringLiteral("No connection afer 20secs"));
});
}
// thread safe connect // thread safe connect
{ {
QPointer<CAfvClient> myself(this);
QMutexLocker lock(&m_mutexConnection); QMutexLocker lock(&m_mutexConnection);
// async connection // async connection
@@ -194,10 +206,12 @@ namespace BlackCore
QMutexLocker lock(&m_mutex); QMutexLocker lock(&m_mutex);
if (m_voiceServerTimer) { m_voiceServerTimer->start(PositionUpdatesMs); } if (m_voiceServerTimer) { m_voiceServerTimer->start(PositionUpdatesMs); }
} }
m_retryConnectAttempt = 0;
emit this->connectionStatusChanged(Connected); emit this->connectionStatusChanged(Connected);
} }
else else
{ {
myself->retryConnectTo(cid, password, callsign, client, QStringLiteral("AFV authentication failed for '%1' callsign '%2'").arg(cid, callsign));
emit this->connectionStatusChanged(Disconnected); emit this->connectionStatusChanged(Disconnected);
} }
} }
@@ -1024,12 +1038,12 @@ namespace BlackCore
void CAfvClient::autoLogoffWithoutFsdNetwork() void CAfvClient::autoLogoffWithoutFsdNetwork()
{ {
if (!hasContexts()) { return; } if (!hasContexts()) { return; }
if (!this->isConnected()) { m_connectMismatches = 0; return; } if (!this->isConnected()) { m_fsdConnectMismatches = 0; return; }
// AFV is connected // AFV is connected
if (sApp->getIContextNetwork()->isConnected()) { m_connectMismatches = 0; return; } if (sApp->getIContextNetwork()->isConnected()) { m_fsdConnectMismatches = 0; return; }
if (++m_connectMismatches < 2) { return; } // avoid a single issue causing logoff if (++m_fsdConnectMismatches < 2) { return; } // avoid a single issue causing logoff
CLogMessage(this).warning(u"Auto logoff AFV client because FSD no longer connected"); CLogMessage(this).warning(u"Auto logoff AFV client because FSD no longer connected");
this->disconnectFrom(); this->disconnectFrom();
@@ -1161,6 +1175,32 @@ namespace BlackCore
emit this->receivingCallsignsChanged(args); emit this->receivingCallsignsChanged(args);
} }
void CAfvClient::retryConnectTo(const QString &cid, const QString &password, const QString &callsign, const QString &client, const QString &reason)
{
if (this->isConnected()) { return; }
m_retryConnectAttempt++;
const int retrySecs = qMin(3 * 60, m_retryConnectAttempt * 30);
const CStatusMessage msg = CStatusMessage(this).validationError(reason + ". Retry in %1secs. Attempt %2.") << retrySecs << m_retryConnectAttempt;
this->reconnectTo(cid, password, callsign, client, retrySecs * 1000, msg);
}
void CAfvClient::reconnectTo(const QString &cid, const QString &password, const QString &callsign, const QString &client, int delayMs, const CStatusMessage &msg)
{
if (msg.isFailure())
{
emit this->afvConnectionFailure(msg);
}
QPointer<CAfvClient> myself(this);
QTimer::singleShot(delayMs, this, [ = ]
{
if (!myself) { return; }
if (myself->isConnected()) { return; }
this->connectTo(cid, password, callsign, client);
});
}
QVector<StationDto> CAfvClient::getAliasedStations() const QVector<StationDto> CAfvClient::getAliasedStations() const
{ {
QMutexLocker lock(&m_mutex); QMutexLocker lock(&m_mutex);

View File

@@ -293,6 +293,9 @@ namespace BlackCore
//! Connection status has been changed //! Connection status has been changed
void connectionStatusChanged(ConnectionStatus status); void connectionStatusChanged(ConnectionStatus status);
//! Authentication has failed with AFV server
void afvConnectionFailure(const BlackMisc::CStatusMessage &msg);
//! Client updated from own aicraft data //! Client updated from own aicraft data
void updatedFromOwnAircraftCockpit(); void updatedFromOwnAircraftCockpit();
@@ -332,6 +335,12 @@ namespace BlackCore
void onUpdateTransceiversFromContext(const BlackMisc::Simulation::CSimulatedAircraft &aircraft, const BlackMisc::CIdentifier &originator); void onUpdateTransceiversFromContext(const BlackMisc::Simulation::CSimulatedAircraft &aircraft, const BlackMisc::CIdentifier &originator);
void onReceivingCallsignsChanged(const BlackCore::Afv::Audio::TransceiverReceivingCallsignsChangedArgs &args); void onReceivingCallsignsChanged(const BlackCore::Afv::Audio::TransceiverReceivingCallsignsChangedArgs &args);
//! Re-try connection to server
void retryConnectTo(const QString &cid, const QString &password, const QString &callsign, const QString &client, const QString &reason);
//! Connect again in given ms
void reconnectTo(const QString &cid, const QString &password, const QString &callsign, const QString &client, int delayMs, const BlackMisc::CStatusMessage &msg);
//! All aliased stations //! All aliased stations
//! \threadsafe //! \threadsafe
//! @{ //! @{
@@ -375,7 +384,8 @@ namespace BlackCore
QSet<quint16> m_enabledTransceivers; QSet<quint16> m_enabledTransceivers;
static const QVector<quint16> &allTransceiverIds() { static const QVector<quint16> transceiverIds{0, 1}; return transceiverIds; } static const QVector<quint16> &allTransceiverIds() { static const QVector<quint16> transceiverIds{0, 1}; return transceiverIds; }
std::atomic_int m_connectMismatches { 0 }; std::atomic_int m_fsdConnectMismatches { 0 }; //!< FSD no longer connected?
std::atomic_int m_retryConnectAttempt { 0 }; //!< Try to connect the n-th time
std::atomic_bool m_isStarted { false }; std::atomic_bool m_isStarted { false };
std::atomic_bool m_loopbackOn { false }; std::atomic_bool m_loopbackOn { false };
std::atomic_bool m_enableAliased { true }; std::atomic_bool m_enableAliased { true };

View File

@@ -107,9 +107,9 @@ namespace BlackCore
const qint64 validFromSecs = doc.object().value("nbf").toInt(-1); const qint64 validFromSecs = doc.object().value("nbf").toInt(-1);
if (validFromSecs < 0) { break; } if (validFromSecs < 0) { break; }
const qint64 localSecsSinceEpoch = QDateTime::currentSecsSinceEpoch(); const qint64 localSecsSinceEpoch = QDateTime::currentSecsSinceEpoch();
serverToUserOffsetSecs = validFromSecs - localSecsSinceEpoch; serverToUserOffsetSecs = validFromSecs - localSecsSinceEpoch;
const qint64 serverExpirySecs = doc.object().value("exp").toInt(); const qint64 serverExpirySecs = doc.object().value("exp").toInt();
const qint64 expiryLocalUtc = serverExpirySecs - serverToUserOffsetSecs; const qint64 expiryLocalUtc = serverExpirySecs - serverToUserOffsetSecs;
lifeTimeSecs = expiryLocalUtc - localSecsSinceEpoch; lifeTimeSecs = expiryLocalUtc - localSecsSinceEpoch;
} }
while (false); while (false);
@@ -117,7 +117,7 @@ namespace BlackCore
if (lifeTimeSecs > 0) if (lifeTimeSecs > 0)
{ {
m_serverToUserOffsetMs = serverToUserOffsetSecs * 1000; m_serverToUserOffsetMs = serverToUserOffsetSecs * 1000;
m_expiryLocalUtc = QDateTime::currentDateTimeUtc().addSecs(lifeTimeSecs); m_expiryLocalUtc = QDateTime::currentDateTimeUtc().addSecs(lifeTimeSecs);
m_isAuthenticated = true; m_isAuthenticated = true;
} }
@@ -254,7 +254,7 @@ namespace BlackCore
// posted in QAM thread, reply is nullptr if called from another thread // posted in QAM thread, reply is nullptr if called from another thread
sApp->postToNetwork(request, CApplication::NoLogRequestId, json.toJson(), sApp->postToNetwork(request, CApplication::NoLogRequestId, json.toJson(),
{ {
this, [ = ](QNetworkReply *nwReply) this, [ = ](QNetworkReply * nwReply)
{ {
// called in "this" thread // called in "this" thread
const QScopedPointer<QNetworkReply, QScopedPointerDeleteLater> reply(nwReply); const QScopedPointer<QNetworkReply, QScopedPointerDeleteLater> reply(nwReply);
@@ -297,7 +297,7 @@ namespace BlackCore
void CApiServerConnection::checkExpiry() void CApiServerConnection::checkExpiry()
{ {
if (QDateTime::currentDateTimeUtc() > m_expiryLocalUtc.addSecs(-5 * 60)) if (!m_expiryLocalUtc.isValid() || QDateTime::currentDateTimeUtc() > m_expiryLocalUtc.addSecs(-5 * 60))
{ {
QPointer<CApiServerConnection> myself(this); QPointer<CApiServerConnection> myself(this);
this->connectTo(m_username, m_password, m_client, m_networkVersion, this->connectTo(m_username, m_password, m_client, m_networkVersion,

View File

@@ -31,10 +31,10 @@ namespace BlackCore
CLogMessage(this).debug(u"ClientConnection instantiated"); CLogMessage(this).debug(u"ClientConnection instantiated");
// connect(&m_apiServerConnection, &ApiServerConnection::authenticationFinished, this, &ClientConnection::apiConnectionFinished); // connect(&m_apiServerConnection, &ApiServerConnection::authenticationFinished, this, &ClientConnection::apiConnectionFinished);
// connect(&m_apiServerConnection, &ApiServerConnection::addCallsignFinished, this, &ClientConnection::addCallsignFinished); // connect(&m_apiServerConnection, &ApiServerConnection::addCallsignFinished, this, &ClientConnection::addCallsignFinished);
// connect(&m_apiServerConnection, &ApiServerConnection::removeCallsignFinished, this, &ClientConnection::removeCallsignFinished); // connect(&m_apiServerConnection, &ApiServerConnection::removeCallsignFinished, this, &ClientConnection::removeCallsignFinished);
connect(m_voiceServerTimer, &QTimer::timeout, this, &CClientConnection::voiceServerHeartbeat); connect(m_voiceServerTimer, &QTimer::timeout, this, &CClientConnection::voiceServerHeartbeat); // sends heartbeat to server
connect(m_udpSocket, &QUdpSocket::readyRead, this, &CClientConnection::readPendingDatagrams); connect(m_udpSocket, &QUdpSocket::readyRead, this, &CClientConnection::readPendingDatagrams);
connect(m_udpSocket, qOverload<QAbstractSocket::SocketError>(&QUdpSocket::error), this, &CClientConnection::handleSocketError); connect(m_udpSocket, qOverload<QAbstractSocket::SocketError>(&QUdpSocket::error), this, &CClientConnection::handleSocketError);
} }
@@ -57,7 +57,7 @@ namespace BlackCore
this, [ = ](bool authenticated) this, [ = ](bool authenticated)
{ {
// callback when connection has been established // callback when connection has been established
if (!myself) { return; } if (!myself) { return; }
if (authenticated) if (authenticated)
{ {
@@ -70,6 +70,10 @@ namespace BlackCore
CLogMessage(this).info(u"Connected: '%1' to voice server, socket open: %2") << callsign << boolToYesNo(m_udpSocket->isOpen()); CLogMessage(this).info(u"Connected: '%1' to voice server, socket open: %2") << callsign << boolToYesNo(m_udpSocket->isOpen());
} }
else
{
m_connection.reset();
}
// Make sure crypto channels etc. are created // Make sure crypto channels etc. are created
m_connection.setConnected(authenticated); m_connection.setConnected(authenticated);
@@ -92,15 +96,15 @@ namespace BlackCore
// TODO emit disconnected(reason) // TODO emit disconnected(reason)
CLogMessage(this).debug(u"Disconnected client: %1") << reason; CLogMessage(this).debug(u"Disconnected client: %1") << reason;
if (! m_connection.getCallsign().isEmpty()) if (!m_connection.getCallsign().isEmpty())
{ {
m_apiServerConnection->removeCallsign(m_connection.getCallsign()); m_apiServerConnection->removeCallsign(m_connection.getCallsign());
} }
// TODO connectionCheckCancelTokenSource.Cancel(); //Stops connection check loop // TODO connectionCheckCancelTokenSource.Cancel(); // Stops connection check loop
disconnectFromVoiceServer(); disconnectFromVoiceServer();
m_apiServerConnection->forceDisconnect(); m_apiServerConnection->forceDisconnect();
m_connection.setTokens({}); m_connection.reset();
CLogMessage(this).debug(u"Disconnection complete"); CLogMessage(this).debug(u"Disconnection complete");
} }

View File

@@ -32,7 +32,14 @@ namespace BlackCore
bool CClientConnectionData::isVoiceServerAlive() const bool CClientConnectionData::isVoiceServerAlive() const
{ {
return m_lastVoiceServerHeartbeatAckUtc.secsTo(QDateTime::currentDateTimeUtc()) > ServerTimeoutSecs; return m_lastVoiceServerHeartbeatAckUtc.isValid() &&
m_lastVoiceServerHeartbeatAckUtc.secsTo(QDateTime::currentDateTimeUtc()) > ServerTimeoutSecs;
}
bool CClientConnectionData::isDataServerAlive() const
{
return m_lastDataServerHeartbeatAckUtc.isValid() &&
m_lastDataServerHeartbeatAckUtc.secsTo(QDateTime::currentDateTimeUtc()) > ServerTimeoutSecs;
} }
void CClientConnectionData::createCryptoChannels() void CClientConnectionData::createCryptoChannels()
@@ -52,13 +59,24 @@ namespace BlackCore
void CClientConnectionData::setTsHeartbeatToNow() void CClientConnectionData::setTsHeartbeatToNow()
{ {
m_lastVoiceServerHeartbeatAckUtc = QDateTime::currentDateTimeUtc(); const QDateTime now = QDateTime::currentDateTimeUtc();
m_lastVoiceServerHeartbeatAckUtc = now;
m_lastDataServerHeartbeatAckUtc = now;
}
void CClientConnectionData::reset()
{
m_userName.clear();
m_callsign.clear();
m_authenticatedDateTimeUtc = QDateTime();
m_lastVoiceServerHeartbeatAckUtc = QDateTime();
this->setTokens({});
} }
bool CClientConnectionData::voiceServerAlive() const bool CClientConnectionData::voiceServerAlive() const
{ {
return timeSinceAuthenticationSecs() < ServerTimeoutSecs || return (m_authenticatedDateTimeUtc.isValid() && timeSinceAuthenticationSecs() < ServerTimeoutSecs) ||
m_lastVoiceServerHeartbeatAckUtc.secsTo(QDateTime::currentDateTimeUtc()) < ServerTimeoutSecs; (m_lastVoiceServerHeartbeatAckUtc.isValid() && m_lastVoiceServerHeartbeatAckUtc.secsTo(QDateTime::currentDateTimeUtc()) < ServerTimeoutSecs);
} }
} // ns } // ns
} // ns } // ns

View File

@@ -78,11 +78,14 @@ namespace BlackCore
void setTsHeartbeatToNow(); void setTsHeartbeatToNow();
//! @} //! @}
//! Reset all login related data
void reset();
/* TODO /* TODO
public long VoiceServerBytesSent { get; set; } public long VoiceServerBytesSent { get; set; }
public long VoiceServerBytesReceived { get; set; } public long VoiceServerBytesReceived { get; set; }
public long DataServerBytesSent { get; set; } public long DataServerBytesSent { get; set; }
public long DataServerBytesReceived { get; set; } public long DataServerBytesReceived { get; set; }
*/ */
QScopedPointer<Crypto::CCryptoDtoChannel> m_voiceCryptoChannel; //!< used crypto channel QScopedPointer<Crypto::CCryptoDtoChannel> m_voiceCryptoChannel; //!< used crypto channel
@@ -101,6 +104,7 @@ namespace BlackCore
QDateTime m_authenticatedDateTimeUtc; QDateTime m_authenticatedDateTimeUtc;
QDateTime m_lastVoiceServerHeartbeatAckUtc; QDateTime m_lastVoiceServerHeartbeatAckUtc;
QDateTime m_lastDataServerHeartbeatAckUtc;
bool m_receiveAudio = true; //!< audio? bool m_receiveAudio = true; //!< audio?
bool m_connected = false; //!< connected? bool m_connected = false; //!< connected?

View File

@@ -208,6 +208,7 @@ namespace BlackCore
connect(m_voiceClient, &CAfvClient::stoppedAudio, this, &CContextAudioBase::stoppedAudio, Qt::QueuedConnection); connect(m_voiceClient, &CAfvClient::stoppedAudio, this, &CContextAudioBase::stoppedAudio, Qt::QueuedConnection);
connect(m_voiceClient, &CAfvClient::ptt, this, &CContextAudioBase::ptt, Qt::QueuedConnection); connect(m_voiceClient, &CAfvClient::ptt, this, &CContextAudioBase::ptt, Qt::QueuedConnection);
connect(m_voiceClient, &CAfvClient::connectionStatusChanged, this, &CContextAudioBase::onAfvConnectionStatusChanged, Qt::QueuedConnection); connect(m_voiceClient, &CAfvClient::connectionStatusChanged, this, &CContextAudioBase::onAfvConnectionStatusChanged, Qt::QueuedConnection);
connect(m_voiceClient, &CAfvClient::afvConnectionFailure, this, &CContextAudioBase::onAfvConnectionFailure, Qt::QueuedConnection);
} }
void CContextAudioBase::terminateVoiceClient() void CContextAudioBase::terminateVoiceClient()
@@ -640,6 +641,12 @@ namespace BlackCore
} }
} }
void CContextAudioBase::onAfvConnectionFailure(const CStatusMessage &msg)
{
if (!m_voiceClient) { return; }
emit this->voiceClientFailure(msg);
}
bool CContextAudioBase::isRunningWithLocalCore() bool CContextAudioBase::isRunningWithLocalCore()
{ {
return sApp && sApp->isLocalContext(); return sApp && sApp->isLocalContext();

View File

@@ -83,8 +83,10 @@ namespace BlackCore
//! Factory method //! Factory method
static IContextAudio *create(CCoreFacade *runtime, CCoreFacadeConfig::ContextMode mode, BlackMisc::CDBusServer *server, QDBusConnection &connection); static IContextAudio *create(CCoreFacade *runtime, CCoreFacadeConfig::ContextMode mode, BlackMisc::CDBusServer *server, QDBusConnection &connection);
// ------------- only use DBus signals here -------------
signals: signals:
// only use DBus signals here //! Authentication failed, ....
void voiceClientFailure(const BlackMisc::CStatusMessage &msg);
public slots: public slots:
// ------------- DBus --------------- // ------------- DBus ---------------
@@ -285,7 +287,9 @@ namespace BlackCore
//! PTT in voice client received //! PTT in voice client received
void ptt(bool active, BlackMisc::Audio::PTTCOM pttcom, const BlackMisc::CIdentifier &identifier); void ptt(bool active, BlackMisc::Audio::PTTCOM pttcom, const BlackMisc::CIdentifier &identifier);
/** Workaround those must be invisible for DBus /*
* Workaround those must be invisible for DBus
*
//! VU levels @{ //! VU levels @{
void inputVolumePeakVU (double value); void inputVolumePeakVU (double value);
@@ -298,7 +302,7 @@ namespace BlackCore
//! Client updated from own aicraft data //! Client updated from own aicraft data
void updatedFromOwnAircraftCockpit(); void updatedFromOwnAircraftCockpit();
** Workaround **/ * end workaround */
// ------------ local signals ------- // ------------ local signals -------
@@ -338,6 +342,9 @@ namespace BlackCore
//! AFV client connection status changed //! AFV client connection status changed
void onAfvConnectionStatusChanged(int status); void onAfvConnectionStatusChanged(int status);
//! AFV client authentication failed
void onAfvConnectionFailure(const BlackMisc::CStatusMessage &msg);
CActionBind m_actionPtt { BlackMisc::Input::pttHotkeyAction(), BlackMisc::Input::pttHotkeyIcon(), this, &CContextAudioBase::setVoiceTransmissionComActive }; CActionBind m_actionPtt { BlackMisc::Input::pttHotkeyAction(), BlackMisc::Input::pttHotkeyIcon(), this, &CContextAudioBase::setVoiceTransmissionComActive };
CActionBind m_actionPttCom1 { BlackMisc::Input::pttCom1HotkeyAction(), BlackMisc::Input::pttHotkeyIcon(), this, &CContextAudioBase::setVoiceTransmissionCom1 }; CActionBind m_actionPttCom1 { BlackMisc::Input::pttCom1HotkeyAction(), BlackMisc::Input::pttHotkeyIcon(), this, &CContextAudioBase::setVoiceTransmissionCom1 };
CActionBind m_actionPttCom2 { BlackMisc::Input::pttCom2HotkeyAction(), BlackMisc::Input::pttHotkeyIcon(), this, &CContextAudioBase::setVoiceTransmissionCom2 }; CActionBind m_actionPttCom2 { BlackMisc::Input::pttCom2HotkeyAction(), BlackMisc::Input::pttHotkeyIcon(), this, &CContextAudioBase::setVoiceTransmissionCom2 };

View File

@@ -83,8 +83,12 @@ namespace BlackCore
void CContextAudioProxy::relaySignals(const QString &serviceName, QDBusConnection &connection) void CContextAudioProxy::relaySignals(const QString &serviceName, QDBusConnection &connection)
{ {
/**
bool s = connection.connect(serviceName, IContextAudio::ObjectPath(), IContextAudio::InterfaceName(), bool s = connection.connect(serviceName, IContextAudio::ObjectPath(), IContextAudio::InterfaceName(),
"voiceClientFailure", this, SIGNAL(voiceClientFailure(BlackMisc::CStatusMessage)));
Q_ASSERT(s);
/**
s = connection.connect(serviceName, IContextAudio::ObjectPath(), IContextAudio::InterfaceName(),
"changedAudioVolume", this, SIGNAL(changedAudioVolume(int))); "changedAudioVolume", this, SIGNAL(changedAudioVolume(int)));
Q_ASSERT(s); Q_ASSERT(s);
s = connection.connect(serviceName, IContextAudio::ObjectPath(), IContextAudio::InterfaceName(), s = connection.connect(serviceName, IContextAudio::ObjectPath(), IContextAudio::InterfaceName(),

View File

@@ -161,11 +161,11 @@ namespace BlackGui
afv->setRxTx(true, true, true, false); afv->setRxTx(true, true, true, false);
QPointer<CAudioDeviceVolumeSetupComponent> myself(this); QPointer<CAudioDeviceVolumeSetupComponent> myself(this);
c = connect(afv, &CAfvClient::connectionStatusChanged, this, [ = ] c = connect(afv, &CAfvClient::connectionStatusChanged, this, [ = ](CAfvClient::ConnectionStatus status)
{ {
if (!myself || !sGui || sGui->isShuttingDown()) { return; } if (!myself || !sGui || sGui->isShuttingDown()) { return; }
myself->setTransmitReceiveInUiFromVoiceClient(); myself->setTransmitReceiveInUiFromVoiceClient();
Q_UNUSED(status)
}, ct); }, ct);
Q_ASSERT(c); Q_ASSERT(c);
m_afvConnections.append(c); m_afvConnections.append(c);

View File

@@ -444,6 +444,14 @@ void SwiftGuiStd::onRequestedConsoleMessage(const QString &logMsg, bool clear)
log->appendPlainTextToConsole(logMsg); log->appendPlainTextToConsole(logMsg);
} }
void SwiftGuiStd::onAudioClientFailure(const CStatusMessage &msg)
{
if (msg.isEmpty()) { return; }
if (!sGui || sGui->isShuttingDown()) { return; }
ui->fr_CentralFrameInside->showOverlayHTMLMessage(msg);
}
void SwiftGuiStd::focusInMainEntryField() void SwiftGuiStd::focusInMainEntryField()
{ {
ui->comp_MainKeypadArea->focusInEntryField(); ui->comp_MainKeypadArea->focusInEntryField();

View File

@@ -281,6 +281,9 @@ private:
//! UI Console message has been recevied //! UI Console message has been recevied
void onRequestedConsoleMessage(const QString &logMsg, bool clear); void onRequestedConsoleMessage(const QString &logMsg, bool clear);
//! Reported issue with the client
void onAudioClientFailure(const BlackMisc::CStatusMessage &msg);
//! Focus in main entry window //! Focus in main entry window
void focusInMainEntryField(); void focusInMainEntryField();

View File

@@ -30,6 +30,7 @@
#include "blackcore/webdataservices.h" #include "blackcore/webdataservices.h"
#include "blackcore/context/contextnetwork.h" #include "blackcore/context/contextnetwork.h"
#include "blackcore/context/contextsimulator.h" #include "blackcore/context/contextsimulator.h"
#include "blackcore/context/contextaudio.h"
#include "blacksound/audioutilities.h" #include "blacksound/audioutilities.h"
#include "blackmisc/network/networkutils.h" #include "blackmisc/network/networkutils.h"
#include "blackmisc/loghandler.h" #include "blackmisc/loghandler.h"
@@ -65,14 +66,14 @@ void SwiftGuiStd::init()
// POST(!) GUI init // POST(!) GUI init
Q_ASSERT_X(sGui, Q_FUNC_INFO, "Missing sGui"); Q_ASSERT_X(sGui, Q_FUNC_INFO, "Missing sGui");
Q_ASSERT_X(sGui->getWebDataServices(), Q_FUNC_INFO, "Missing web services"); Q_ASSERT_X(sGui->getWebDataServices(), Q_FUNC_INFO, "Missing web services");
Q_ASSERT_X(sGui->supportsContexts(), Q_FUNC_INFO, "Missing contexts"); Q_ASSERT_X(sGui->supportsContexts(), Q_FUNC_INFO, "Missing contexts");
if (m_init) { return; } if (m_init) { return; }
ui->dw_InfoBarStatus->initialFloating(); ui->dw_InfoBarStatus->initialFloating();
this->setVisible(false); // hide all, so no flashing windows during init this->setVisible(false); // hide all, so no flashing windows during init
m_mwaStatusBar = &m_statusBar; m_mwaStatusBar = &m_statusBar;
m_mwaOverlayFrame = ui->fr_CentralFrameInside; m_mwaOverlayFrame = ui->fr_CentralFrameInside;
m_mwaLogComponent = ui->comp_MainInfoArea->getLogComponent(); m_mwaLogComponent = ui->comp_MainInfoArea->getLogComponent();
sGui->initMainApplicationWidget(this); sGui->initMainApplicationWidget(this);
@@ -140,6 +141,12 @@ void SwiftGuiStd::init()
Q_ASSERT(s); Q_ASSERT(s);
s = connect(&m_timerContextWatchdog, &QTimer::timeout, this, &SwiftGuiStd::handleTimerBasedUpdates); s = connect(&m_timerContextWatchdog, &QTimer::timeout, this, &SwiftGuiStd::handleTimerBasedUpdates);
Q_ASSERT(s); Q_ASSERT(s);
if (sGui->getIContextAudio())
{
s = connect(sGui->getIContextAudio(), &IContextAudio::voiceClientFailure, this, &SwiftGuiStd::onAudioClientFailure, Qt::QueuedConnection);
Q_ASSERT(s);
}
Q_UNUSED(s) Q_UNUSED(s)
// check if DB data have been loaded // check if DB data have been loaded