[AFV] Use heartbeat to re-connect to AFV

* some utility functions
* reset values after disconnect
This commit is contained in:
Klaus Basan
2020-04-30 22:02:13 +02:00
committed by Mat Sutcliffe
parent fccaf1fae1
commit 1e633a5704
7 changed files with 120 additions and 15 deletions

View File

@@ -180,6 +180,7 @@ namespace BlackCore
this->retryConnectTo(cid, password, callsign, client, QStringLiteral("No connection afer 20secs"));
});
}
// thread safe connect
{
QMutexLocker lock(&m_mutexConnection);
@@ -235,6 +236,11 @@ namespace BlackCore
QMutexLocker lock(&m_mutexConnection);
m_connection->disconnectFrom();
}
m_heartBeatFailures = 0;
m_retryConnectAttempt = 0;
m_fsdConnectMismatches = 0;
emit connectionStatusChanged(Disconnected);
if (stop) { this->stopAudio(); }
@@ -840,8 +846,8 @@ namespace BlackCore
if (loopback && transmit)
{
IAudioDto audioData;
audioData.audio = QByteArray(args.audio.data(), args.audio.size());
audioData.callsign = QStringLiteral("loopback");
audioData.audio = QByteArray(args.audio.data(), args.audio.size());
audioData.callsign = QStringLiteral("loopback");
audioData.lastPacket = false;
audioData.sequenceCounter = 0;
@@ -1023,6 +1029,47 @@ namespace BlackCore
// for AFV sample client
this->updateTransceivers();
}
// connection check
this->checkServerHeartbeat();
}
void CAfvClient::checkServerHeartbeat()
{
if (!this->isStarted()) { return; }
if (!this->isConnected()) { return; }
if (this->isVoiceServerAlive())
{
m_heartBeatFailures = 0;
return;
}
// Heartbeat failure
// it can happen that after connect we see an initial timeout
const int failures = ++m_heartBeatFailures;
if (failures < 2) { return; }
QString un, pw, cs, client;
{
QMutexLocker lock(&m_mutexConnection);
un = m_connection->getUserName();
pw = m_connection->getPassword();
cs = m_connection->getCallsign();
client = m_connection->getClient();
}
if (un.isEmpty() || pw.isEmpty()) { return; }
// make sure we are disconnected
if (this->isConnected()) { this->disconnectFrom(false); }
QPointer<CAfvClient> myself(this);
QTimer::singleShot(5 * 1000, this, [ = ]
{
if (!myself) { return; }
const QString reason = QStringLiteral("Heartbeat failed %1 times").arg(failures);
this->retryConnectTo(un, pw, cs, client, reason);
});
}
void CAfvClient::onSettingsChanged()
@@ -1263,6 +1310,21 @@ namespace BlackCore
return roundedFrequencyHz;
}
bool CAfvClient::isVoiceServerAlive() const
{
QMutexLocker lock(&m_mutexConnection);
return m_connection && m_connection->isVoiceServerAlive();
}
const QString &CAfvClient::getVoiceServerUrl() const
{
QMutexLocker lock(&m_mutexConnection);
static const QString e;
if (!m_connection) { return e; }
return m_connection->getVoiceServerUrl();
}
bool CAfvClient::fuzzyMatchCallsign(const QString &callsign, const QString &compareTo) const
{
if (callsign.isEmpty() || compareTo.isEmpty()) { return false; } // empty callsigns should NOT match

View File

@@ -133,7 +133,7 @@ namespace BlackCore
//! \threadsafe
bool isComUnitIntegrated() const { return m_integratedComUnit; }
/*
/* NOT used
//! The device's volume 0..1 @{
double getDeviceInputVolume() const;
bool setDeviceInputVolume(double volume);
@@ -180,7 +180,7 @@ namespace BlackCore
//! Get transceivers
//! \threadsafe
//! @{
QVector<TransceiverDto> getTransceivers() const;
QVector<TransceiverDto> getTransceivers() const;
QVector<TxTransceiverDto> getTransmittingTransceivers() const;
QSet<quint16> getEnabledTransceivers() const;
//! @}
@@ -352,6 +352,14 @@ namespace BlackCore
//! \threadsafe
quint32 getAliasFrequencyHz(quint32 frequencyHz) const;
//! Voice server alive
//! \threadsafe
bool isVoiceServerAlive() const;
//! Get voice server URL
//! \threadsafe
const QString &getVoiceServerUrl() const;
bool fuzzyMatchCallsign(const QString &callsign, const QString &compareTo) const;
void getPrefixSuffix(const QString &callsign, QString &prefix, QString &suffix) const;
@@ -385,10 +393,11 @@ namespace BlackCore
static const QVector<quint16> &allTransceiverIds() { static const QVector<quint16> transceiverIds{0, 1}; return transceiverIds; }
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_loopbackOn { false };
std::atomic_bool m_enableAliased { true };
std::atomic_int m_retryConnectAttempt { 0 }; //!< try to connect the n-th time
std::atomic_int m_heartBeatFailures { 0 }; //!< voice server heartbeat failures
std::atomic_bool m_isStarted { false };
std::atomic_bool m_loopbackOn { false };
std::atomic_bool m_enableAliased { true };
std::atomic_bool m_winCoInitialized { false }; //!< Windows only CoInitializeEx
std::atomic_bool m_integratedComUnit { false }; //!< is COM unit sychronized, integrated?
@@ -405,6 +414,7 @@ namespace BlackCore
Audio::InputVolumeStreamArgs m_inputVolumeStream;
Audio::OutputVolumeStreamArgs m_outputVolumeStream;
void checkServerHeartbeat();
void deferredInit();
void initTransceivers();
void connectWithContexts();

View File

@@ -80,6 +80,16 @@ namespace BlackCore
//! Set the URL
bool setUrl(const QString &url);
//! Get the URL
const QString &getUrl() const { return m_addressUrl; }
//! User data @{
const QString &getUserName() const { return m_username; }
const QString &getPassword() const { return m_password; }
const QString &getClient() const { return m_client; }
const QUuid &getNetworkVersion() const { return m_networkVersion; }
//! @}
private:
//! Post to resource
template<typename TResponse>

View File

@@ -65,6 +65,7 @@ namespace BlackCore
m_connection.setTokens(m_apiServerConnection->addCallsign(callsign));
m_connection.setTsAuthenticatedToNow();
m_connection.createCryptoChannels();
m_connection.setTsHeartbeatToNow();
this->connectToVoiceServer();
// taskServerConnectionCheck.Start();
@@ -125,6 +126,13 @@ namespace BlackCore
return m_apiServerConnection->setUrl(url);
}
const QString &CClientConnection::getVoiceServerUrl() const
{
static const QString e;
if (!m_apiServerConnection) { return e; }
return m_apiServerConnection->getUrl();
}
void CClientConnection::connectToVoiceServer()
{
const QHostAddress localAddress(QHostAddress::AnyIPv4);

View File

@@ -52,9 +52,11 @@ namespace BlackCore
//! Disconnect
void disconnectFrom(const QString &reason = {});
//! Is connected
//! Is connected?
bool isConnected() const { return m_connection.isConnected(); }
//! @}
//! Is alive?
bool isVoiceServerAlive() const { return m_connection.isVoiceServerAlive(); }
//! Receiving audio? @{
void setReceiveAudio(bool value) { m_connection.setReceiveAudio(value); }
@@ -89,9 +91,20 @@ namespace BlackCore
//! Update the voice server URL
bool updateVoiceServerUrl(const QString &url);
//! Get the voice server URL
const QString &getVoiceServerUrl() const;
//! Authenticated since when
qint64 secondsSinceAuthentication() const { return m_connection.secondsSinceAuthentication(); }
//! User data @{
const QString &getUserName() const { return m_connection.getUserName(); }
const QString &getCallsign() const { return m_connection.getCallsign(); }
const QString &getPassword() const { static const QString e; return m_apiServerConnection ? m_apiServerConnection->getPassword() : e; }
const QString &getClient() const { static const QString e; return m_apiServerConnection ? m_apiServerConnection->getClient() : e; }
const QUuid &getNetworkVersion() const { return m_networkVersion; }
//! @}
signals:
//! Audio has been received
void audioReceived(const AudioRxOnTransceiversDto &dto);

View File

@@ -32,14 +32,16 @@ namespace BlackCore
bool CClientConnectionData::isVoiceServerAlive() const
{
return m_lastVoiceServerHeartbeatAckUtc.isValid() &&
m_lastVoiceServerHeartbeatAckUtc.secsTo(QDateTime::currentDateTimeUtc()) > ServerTimeoutSecs;
if (!m_lastVoiceServerHeartbeatAckUtc.isValid()) { return false; }
const qint64 d = qAbs(m_lastVoiceServerHeartbeatAckUtc.secsTo(QDateTime::currentDateTimeUtc()));
return d < ServerTimeoutSecs;
}
bool CClientConnectionData::isDataServerAlive() const
{
return m_lastDataServerHeartbeatAckUtc.isValid() &&
m_lastDataServerHeartbeatAckUtc.secsTo(QDateTime::currentDateTimeUtc()) > ServerTimeoutSecs;
if (!m_lastDataServerHeartbeatAckUtc.isValid()) { return false; }
const qint64 d = qAbs(m_lastDataServerHeartbeatAckUtc.secsTo(QDateTime::currentDateTimeUtc()));
return d < ServerTimeoutSecs;
}
void CClientConnectionData::createCryptoChannels()

View File

@@ -42,7 +42,7 @@ namespace BlackCore
//! Servers alive @{
bool isVoiceServerAlive() const;
bool isDataServerAlive() const;
bool isDataServerAlive() const;
//! @}
//! Is connected? @{