mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-03-22 14:55:36 +08:00
[AFV] Use heartbeat to re-connect to AFV
* some utility functions * reset values after disconnect
This commit is contained in:
committed by
Mat Sutcliffe
parent
fccaf1fae1
commit
1e633a5704
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace BlackCore
|
||||
|
||||
//! Servers alive @{
|
||||
bool isVoiceServerAlive() const;
|
||||
bool isDataServerAlive() const;
|
||||
bool isDataServerAlive() const;
|
||||
//! @}
|
||||
|
||||
//! Is connected? @{
|
||||
|
||||
Reference in New Issue
Block a user