Ref T730, Ref T739 update from own aircraft in one step

* update all values from own aircraft in "one step"
* rational: avoid "single property" updates and numerous round trips (signals, transceiver updates)
* also allow updates of not yet connect, as "a kind of preset"
* do NOT send to network if not authenticated
This commit is contained in:
Klaus Basan
2019-10-09 22:58:11 +02:00
committed by Mat Sutcliffe
parent caa78395a9
commit ef9e7b0bf1
4 changed files with 171 additions and 87 deletions

View File

@@ -51,9 +51,9 @@ namespace BlackCore
connect(m_input, &CInput::opusDataAvailable, this, &CAfvClient::opusDataAvailable);
connect(m_input, &CInput::inputVolumeStream, this, &CAfvClient::inputVolumeStream);
connect(m_output, &Output::outputVolumeStream, this, &CAfvClient::outputVolumeStream);
connect(m_output, &Output::outputVolumeStream, this, &CAfvClient::outputVolumeStream);
connect(m_connection, &CClientConnection::audioReceived, this, &CAfvClient::audioOutDataAvailable);
connect(m_voiceServerPositionTimer, &QTimer::timeout, this, &CAfvClient::onPositionUpdateTimer);
connect(m_voiceServerPositionTimer, &QTimer::timeout, this, &CAfvClient::onPositionUpdateTimer);
// deferred init
QTimer::singleShot(1000, this, &CAfvClient::deferredInit);
@@ -87,11 +87,9 @@ namespace BlackCore
// init with context values
this->connectWithContexts();
if (m_connectedWithContext && hasContext())
{
// update from context
this->updateTransceivers();
}
// update from context
this->onPositionUpdateTimer();
}
void CAfvClient::connectWithContexts()
@@ -119,12 +117,12 @@ namespace BlackCore
this->setCallsign(callsign);
m_connection->connectTo(cid, password, callsign);
this->updateTransceivers(); // uses context if available
m_aliasedStations = m_connection->getAllAliasedStations();
this->onPositionUpdateTimer();
if (m_connection->isConnected()) { emit this->connectionStatusChanged(Connected); }
else { emit this->connectionStatusChanged(Disconnected); }
m_aliasedStations = m_connection->getAllAliasedStations();
}
void CAfvClient::disconnectFrom()
@@ -221,6 +219,8 @@ namespace BlackCore
this->onSettingsChanged(); // make sure all settings are applied
m_isStarted = true;
CLogMessage(this).info(u"Started [Input: %1] [Output: %2]") << inputDevice.getName() << outputDevice.getName();
this->onPositionUpdateTimer(); // update values
}
void CAfvClient::startAudio(const QString &inputDeviceName, const QString &outputDeviceName)
@@ -249,13 +249,6 @@ namespace BlackCore
m_isStarted = false;
m_connection->setReceiveAudio(false);
// transceivers
{
QMutexLocker lock(&m_mutexTransceivers);
m_transceivers.clear();
}
this->updateTransceivers(false);
// stop input/output
m_updateTimer.stop();
m_input->stop();
@@ -304,19 +297,7 @@ namespace BlackCore
// Fix rounding issues like 128074999 Hz -> 128075000 Hz
quint32 roundedFrequencyHz = static_cast<quint32>(qRound(frequencyHz / 1000.0)) * 1000;
{
QMutexLocker lock(&m_mutex);
auto it = std::find_if(m_aliasedStations.begin(), m_aliasedStations.end(), [roundedFrequencyHz](const StationDto & d)
{
return d.frequencyAliasHz == roundedFrequencyHz;
});
if (it != m_aliasedStations.end())
{
CLogMessage(this).debug(u"Aliasing %1Hz [VHF] to %2Hz [HF]") << frequencyHz << it->frequencyHz;
roundedFrequencyHz = it->frequencyHz;
}
}
roundedFrequencyHz = this->getAliasFrequencyHz(roundedFrequencyHz);
bool updateTransceivers = false;
{
@@ -363,7 +344,8 @@ namespace BlackCore
void CAfvClient::updateTransceivers(bool updateFrequencies)
{
if (!m_connection->isConnected()) { return; }
// also update if NOT connected, values will be preset
if (hasContext())
{
const CSimulatedAircraft ownAircraft = sApp->getIContextOwnAircraft()->getOwnAircraft();
@@ -400,7 +382,7 @@ namespace BlackCore
void CAfvClient::setTransmittingTransceiver(quint16 transceiverID)
{
TxTransceiverDto tx = { transceiverID };
const TxTransceiverDto tx = { transceiverID };
this->setTransmittingTransceivers({ tx });
}
@@ -475,7 +457,7 @@ namespace BlackCore
if (!active)
{
//AGC
// AGC
// if (maxDbReadingInPTTInterval > -1) InputVolumeDb = InputVolumeDb - 1;
// if (maxDbReadingInPTTInterval < -4) InputVolumeDb = InputVolumeDb + 1;
m_maxDbReadingInPTTInterval = -100;
@@ -485,6 +467,12 @@ namespace BlackCore
emit this->ptt(active, com, this->identifier());
}
double CAfvClient::getInputVolumeDb() const
{
QMutexLocker lock(&m_mutex);
return m_inputVolumeDb;
}
void CAfvClient::setInputVolumeDb(double valueDb)
{
if (valueDb > MaxDbIn) { valueDb = MaxDbIn; }
@@ -498,6 +486,12 @@ namespace BlackCore
}
}
double CAfvClient::getOutputVolumeDb() const
{
QMutexLocker lock(&m_mutex);
return m_outputVolumeDb;
}
int CAfvClient::getNormalizedInputVolume() const
{
const double db = this->getInputVolumeDb();
@@ -635,26 +629,20 @@ namespace BlackCore
QString CAfvClient::getReceivingCallsignsCom1()
{
QMutexLocker lock(&m_mutex);
if (m_soundcardSampleProvider)
{
return m_soundcardSampleProvider->getReceivingCallsigns(0);
}
return {};
if (!m_soundcardSampleProvider) return {};
return m_soundcardSampleProvider->getReceivingCallsigns(0);
}
QString CAfvClient::getReceivingCallsignsCom2()
{
QMutexLocker lock(&m_mutex);
if (m_soundcardSampleProvider)
{
return m_soundcardSampleProvider->getReceivingCallsigns(1);
}
return {};
if (!m_soundcardSampleProvider) return {};
return m_soundcardSampleProvider->getReceivingCallsigns(1);
}
bool CAfvClient::updateVoiceServerUrl(const QString &url)
{
if (m_connection) { return false; }
if (!m_connection) { return false; }
return m_connection->updateVoiceServerUrl(url);
}
@@ -665,7 +653,16 @@ namespace BlackCore
void CAfvClient::onPositionUpdateTimer()
{
this->updateTransceivers();
if (hasContext())
{
// for pilot client
this->updateFromOwnAircraft(sApp->getIContextOwnAircraft()->getOwnAircraft(), false);
}
else
{
// for AFV sample client
this->updateTransceivers();
}
}
void CAfvClient::onSettingsChanged()
@@ -676,38 +673,101 @@ namespace BlackCore
this->setBypassEffects(!audioSettings.isAudioEffectsEnabled());
}
void CAfvClient::onUpdateTransceiversFromContext(const CSimulatedAircraft &aircraft, const CIdentifier &originator)
void CAfvClient::updateFromOwnAircraft(const CSimulatedAircraft &aircraft, bool withSignals)
{
Q_UNUSED(originator)
this->updatePosition(aircraft.latitude().value(CAngleUnit::deg()),
aircraft.longitude().value(CAngleUnit::deg()),
aircraft.getAltitude().value(CLengthUnit::ft()));
if (!sApp || sApp->isShuttingDown()) { return; }
TransceiverDto transceiverCom1;
TransceiverDto transceiverCom2;
transceiverCom1.id = comUnitToTransceiverId(CComSystem::Com1);
transceiverCom2.id = comUnitToTransceiverId(CComSystem::Com2);
// position
const double latDeg = aircraft.latitude().value(CAngleUnit::deg());
const double lngDeg = aircraft.longitude().value(CAngleUnit::deg());
const double altM = aircraft.getAltitude().value(CLengthUnit::m());
transceiverCom1.LatDeg = transceiverCom2.LatDeg = latDeg;
transceiverCom1.LonDeg = transceiverCom2.LonDeg = lngDeg;
transceiverCom1.HeightAglM = transceiverCom2.HeightAglM = altM;
transceiverCom1.HeightMslM = transceiverCom2.HeightMslM = altM;
// enabled, rx/tx, frequency
const CComSystem com1 = aircraft.getCom1System();
const CComSystem com2 = aircraft.getCom2System();
this->updateComFrequency(CComSystem::Com1, com1);
this->updateComFrequency(CComSystem::Com2, com2);
const quint32 f1 = static_cast<quint32>(com1.getFrequencyActive().valueInteger(CFrequencyUnit::Hz()));
const quint32 f2 = static_cast<quint32>(com2.getFrequencyActive().valueInteger(CFrequencyUnit::Hz()));
transceiverCom1.frequencyHz = this->getAliasFrequencyHz(f1);
transceiverCom2.frequencyHz = this->getAliasFrequencyHz(f2);
const bool tx1 = com1.isTransmitEnabled();
const bool rx1 = com1.isReceiveEnabled();
const bool tx2 = com2.isTransmitEnabled();
const bool tx2 = com2.isTransmitEnabled(); // we only allow one (1) transmit
const bool rx2 = com2.isReceiveEnabled();
this->enableComUnit(CComSystem::Com1, tx1 || rx1);
this->enableComUnit(CComSystem::Com2, tx2 || rx2);
// enable, we currently treat receive as enable
// flight sim cockpits normally use rx and tx
// AFV uses tx and enable
const bool e1 = rx1;
const bool e2 = rx2;
// currently only transmitting at one unit
if (tx1)
// transceivers
QSet<quint16> newEnabledTransceiverIds;
QVector<TransceiverDto> newTransceivers { transceiverCom1, transceiverCom2 };
QVector<TransceiverDto> newEnabledTransceivers;
QVector<TxTransceiverDto> newTransmittingTransceivers;
if (e1) { newEnabledTransceivers.push_back(transceiverCom1); newEnabledTransceiverIds.insert(transceiverCom1.id); }
if (e2) { newEnabledTransceivers.push_back(transceiverCom2); newEnabledTransceiverIds.insert(transceiverCom2.id); }
// Transmitting transceivers, currently ALLOW ONLY ONE
if (tx1 && e1) { newTransmittingTransceivers.push_back(transceiverCom1); }
else if (tx2 && e2) { newTransmittingTransceivers.push_back(transceiverCom2); }
// lock and update
{
this->setTransmittingComUnit(CComSystem::Com1);
QMutexLocker lock(&m_mutexTransceivers);
m_transceivers = newTransceivers;
m_enabledTransceivers = newEnabledTransceiverIds;
m_transmittingTransceivers = newTransmittingTransceivers;
}
else if (tx2)
// in connection and soundcard only use the enabled tarnsceivers
const QString callsign = this->getCallsign();
{
this->setTransmittingComUnit(CComSystem::Com2);
QMutexLocker lock(&m_mutex);
if (m_connection) { m_connection->updateTransceivers(callsign, newEnabledTransceivers); }
if (m_soundcardSampleProvider) { m_soundcardSampleProvider->updateRadioTransceivers(newEnabledTransceivers); }
}
this->updateTransceivers();
emit this->updatedFromOwnAircraftCockpit();
if (withSignals) { emit this->updatedFromOwnAircraftCockpit(); }
}
void CAfvClient::onUpdateTransceiversFromContext(const CSimulatedAircraft &aircraft, const CIdentifier &originator)
{
if (originator == this->identifier()) { return; }
this->updateFromOwnAircraft(aircraft);
}
quint32 CAfvClient::getAliasFrequencyHz(quint32 frequencyHz) const
{
// void rounding issues from float/double
quint32 roundedFrequencyHz = static_cast<quint32>(qRound(frequencyHz / 1000.0)) * 1000;
// change to aliased frequency if needed
{
QMutexLocker lock(&m_mutex);
auto it = std::find_if(m_aliasedStations.begin(), m_aliasedStations.end(), [roundedFrequencyHz](const StationDto & d)
{
return d.frequencyAliasHz == roundedFrequencyHz;
});
if (it != m_aliasedStations.end())
{
CLogMessage(this).debug(u"Aliasing %1Hz [VHF] to %2Hz [HF]") << frequencyHz << it->frequencyHz;
roundedFrequencyHz = it->frequencyHz;
}
}
return roundedFrequencyHz;
}
quint16 CAfvClient::comUnitToTransceiverId(CComSystem::ComUnit comUnit)
@@ -716,8 +776,7 @@ namespace BlackCore
{
case CComSystem::Com1: return 0;
case CComSystem::Com2: return 1;
default:
break;
default: break;
}
return 0;
}

View File

@@ -106,10 +106,12 @@ namespace BlackCore
void setMuted(bool mute);
//! @}
//! Start/stop client @{
bool restartWithNewDevices(const BlackMisc::Audio::CAudioDeviceInfo &inputDevice, const BlackMisc::Audio::CAudioDeviceInfo &outputDevice);
void startAudio(const BlackMisc::Audio::CAudioDeviceInfo &inputDevice, const BlackMisc::Audio::CAudioDeviceInfo &outputDevice, const QVector<quint16> &transceiverIDs);
Q_INVOKABLE void startAudio(const QString &inputDeviceName, const QString &outputDeviceName);
void stopAudio();
//! @}
//! Enable COM unit/transceiver
//! \threadsafe
@@ -155,6 +157,11 @@ namespace BlackCore
//! \threadsafe
Q_INVOKABLE void updatePosition(double latitudeDeg, double longitudeDeg, double heightMeters);
//! Update from own aircraft
//! \remark full update of frequency, position and enabled transceivers in one step
//! \threadsafe
void updateFromOwnAircraft(const BlackMisc::Simulation::CSimulatedAircraft &aircraft, bool withSignals = true);
//! Push to talk @{
Q_INVOKABLE void setPtt(bool active);
void setPttForCom(bool active, BlackMisc::Audio::PTTCOM com);
@@ -167,34 +174,46 @@ namespace BlackCore
Q_INVOKABLE bool isLoopback() const { return m_loopbackOn; }
//! @}
//! Input volume in dB, +-18dB @{
double getInputVolumeDb() const { return m_inputVolumeDb; }
//! Input volume in dB, +-18dB
//! \threadsafe
//! @{
double getInputVolumeDb() const;
Q_INVOKABLE void setInputVolumeDb(double valueDb);
//! @}
//! Output volume in dB, +-18dB @{
double getOutputVolumeDb() const { return m_outputVolumeDb; }
//! Output volume in dB, +-18dB
//! \threadsafe
//! @{
double getOutputVolumeDb() const;
Q_INVOKABLE void setOutputVolumeDb(double valueDb);
//! @}
//! Normalized volumes 0..100 @{
//! Normalized volumes 0..100
//! \threadsafe
//! @{
int getNormalizedInputVolume() const;
int getNormalizedOutputVolume() const;
void setNormalizedInputVolume(int volume);
void setNormalizedOutputVolume(int volume);
//! @}
//! VU values, 0..1 @{
//! VU values, 0..1
//! \threadsafe
//! @{
double getInputVolumePeakVU() const;
double getOutputVolumePeakVU() const;
//! @}
//! Recently used device @{
//! Recently used device
//! \threadsafe
//! @{
const BlackMisc::Audio::CAudioDeviceInfo &getInputDevice() const;
const BlackMisc::Audio::CAudioDeviceInfo &getOutputDevice() const;
//! @}
//! Callsigns currently received @{
//! Callsigns currently received
//! \threadsafe
//! @{
QString getReceivingCallsignsCom1();
QString getReceivingCallsignsCom2();
//! @}
@@ -238,6 +257,10 @@ namespace BlackCore
void updateTransceivers(bool updateFrequencies = true);
void onUpdateTransceiversFromContext(const BlackMisc::Simulation::CSimulatedAircraft &aircraft, const BlackMisc::CIdentifier &originator);
//! Frequency from aliased stations
//! \threadsafe
quint32 getAliasFrequencyHz(quint32 frequencyHz) const;
static constexpr int PositionUpdatesMs = 5000; //!< position timer
static constexpr int SampleRate = 48000;
static constexpr int FrameSize = 960; // 20ms
@@ -276,8 +299,8 @@ namespace BlackCore
double m_outputVolume = 1.0;
double m_maxDbReadingInPTTInterval = -100;
QTimer *m_voiceServerPositionTimer = nullptr;
QVector<StationDto> m_aliasedStations;
QTimer *m_voiceServerPositionTimer = nullptr;
QVector<StationDto> m_aliasedStations;
Audio::InputVolumeStreamArgs m_inputVolumeStream;
Audio::OutputVolumeStreamArgs m_outputVolumeStream;

View File

@@ -138,6 +138,7 @@ namespace BlackCore
void CApiServerConnection::updateTransceivers(const QString &callsign, const QVector<TransceiverDto> &transceivers)
{
if (!this->sendToNetworkIfAuthenticated()) { return; }
QJsonArray array;
for (const TransceiverDto &tx : transceivers)
{
@@ -239,13 +240,7 @@ namespace BlackCore
void CApiServerConnection::postNoResponse(const QString &resource, const QJsonDocument &json)
{
if (isShuttingDown()) { return; } // avoid crash
if (!m_isAuthenticated)
{
CLogMessage(this).debug(u"AFV not authenticated");
return;
}
if (isShuttingDown()) { return; }
this->checkExpiry();
QUrl url(m_addressUrl);
@@ -273,8 +268,7 @@ namespace BlackCore
void CApiServerConnection::deleteResource(const QString &resource)
{
if (isShuttingDown()) { return; }
if (!m_isAuthenticated) { return; }
if (isShuttingDown()) { return; }
QUrl url(m_addressUrl);
url.setPath(resource);
@@ -345,6 +339,11 @@ namespace BlackCore
return loop;
}
bool CApiServerConnection::sendToNetworkIfAuthenticated() const
{
return m_isAuthenticated && !isShuttingDown();
}
bool CApiServerConnection::isShuttingDown()
{
return !sApp || sApp->isShuttingDown();

View File

@@ -80,9 +80,9 @@ namespace BlackCore
template<typename TResponse>
TResponse postNoRequest(const QString &resource)
{
if (!m_isAuthenticated)
if (!this->sendToNetworkIfAuthenticated())
{
BlackMisc::CLogMessage(this).debug(u"AFV not authenticated");
// BlackMisc::CLogMessage(this).debug(u"AFV not authenticated");
return {};
}
@@ -103,9 +103,9 @@ namespace BlackCore
template<typename TResponse>
QVector<TResponse> getAsVector(const QString &resource)
{
if (! m_isAuthenticated)
if (!this->sendToNetworkIfAuthenticated())
{
BlackMisc::CLogMessage(this).debug(u"AFV not authenticated");
// BlackMisc::CLogMessage(this).debug(u"AFV not authenticated");
return {};
}
@@ -156,6 +156,9 @@ namespace BlackCore
//! Get QLoop for network access, using class must delete the loop
QEventLoop *newEventLoop();
//! Send to network
bool sendToNetworkIfAuthenticated() const;
//! Application shutting down
static bool isShuttingDown();