21 using namespace swift::core::context;
22 using namespace swift::core::afv::audio;
23 using namespace swift::core::afv::connection;
25 using namespace swift::misc::audio;
26 using namespace swift::misc::physical_quantities;
27 using namespace swift::misc::simulation;
28 using namespace swift::misc::aviation;
29 using namespace swift::sound;
30 using namespace swift::sound::sample_provider;
32 namespace swift::core::afv::clients
43 m_output(new
COutput(this)), m_voiceServerTimer(new
QTimer(this))
48 connect(m_input, &CInput::opusDataAvailable,
this, &CAfvClient::opusDataAvailable);
49 connect(m_input, &CInput::inputVolumeStream,
this, &CAfvClient::inputVolumeStream);
51 connect(m_output, &COutput::outputVolumeStream,
this, &CAfvClient::outputVolumeStream);
52 connect(m_connection, &CClientConnection::audioReceived,
this, &CAfvClient::audioOutDataAvailable);
68 m_callsign = callsign;
77 void CAfvClient::initTransceivers()
81 m_transceivers = { { 0, UniCom, 48.5, 11.5, 1000.0, 1000.0 }, { 1, UniCom, 48.5, 11.5, 1000.0, 1000.0 } };
83 m_enabledTransceivers = { 0, 1 };
84 m_transmittingTransceivers = { { 0 } };
88 this->connectWithContexts();
91 this->onTimerUpdate();
94 void CAfvClient::connectWithContexts()
96 if (m_connectedWithContext) {
return; }
97 if (!hasContexts()) {
return; }
103 context->disconnect(
this);
111 m_connectedWithContext =
true;
114 void CAfvClient::fetchSimulatorSettings()
117 if (!hasContexts()) {
return; }
124 if (myself) { this->fetchSimulatorSettings(); }
130 const bool changed = integrated != m_integratedComUnit;
132 m_integratedComUnit = integrated;
133 if (changed) { emit this->updatedFromOwnAircraftCockpit(); }
144 if (myself) { connectTo(cid, password, callsign, client); }
150 this->connectWithContexts();
151 this->setCallsign(callsign);
154 if (!this->isConnected() && m_retryConnectAttempt == 0)
158 if (!myself) {
return; }
159 if (m_retryConnectAttempt > 0) {
return; }
162 this->retryConnectTo(cid, password, callsign, client, QStringLiteral(
"No connection afer 20secs"));
171 m_connection->connectTo(
172 cid, password, callsign, client,
174 this, [=,
this](
bool authenticated) {
175 if (!myself) {
return; }
179 this->setAliasedStations(aliasedStations);
180 this->onTimerUpdate();
189 if (m_voiceServerTimer) { m_voiceServerTimer->start(PositionUpdatesMs); }
191 m_retryConnectAttempt = 0;
192 emit this->connectionStatusChanged(Connected);
196 myself->retryConnectTo(
197 cid, password, callsign, client,
198 QStringLiteral(
"AFV authentication failed for '%1' callsign '%2'").arg(cid, callsign));
199 emit this->connectionStatusChanged(Disconnected);
205 void CAfvClient::disconnectFrom(
bool stop)
212 if (myself) { disconnectFrom(stop); }
221 m_connection->disconnectFrom();
224 m_heartBeatFailures = 0;
225 m_retryConnectAttempt = 0;
226 m_fsdConnectMismatches = 0;
228 emit connectionStatusChanged(Disconnected);
230 if (stop) { this->stopAudio(); }
235 return CAudioDeviceInfoList::allInputDevices().getDeviceNames();
240 return CAudioDeviceInfoList::allOutputDevices().getDeviceNames();
243 void CAfvClient::setBypassEffects(
bool value)
246 if (m_soundcardSampleProvider) { m_soundcardSampleProvider->setBypassEffects(value); }
249 bool CAfvClient::isOutputMuted()
const
251 const int v = this->getNormalizedMasterOutputVolume();
255 void CAfvClient::setOutputMuted(
bool mute)
257 if (this->isOutputMuted() == mute) {
return; }
258 this->setNormalizedMasterOutputVolume(mute ? 0 : 50);
259 emit this->changedOutputMute(mute);
262 void CAfvClient::startAudio()
266 this->startAudio(inputDevice, outputDevice);
276 if (myself) { startAudio(inputDevice, outputDevice); }
282 inputDevice.
isValid() ? inputDevice : CAudioDeviceInfo::getDefaultInputDevice();
284 outputDevice.
isValid() ? outputDevice : CAudioDeviceInfo::getDefaultOutputDevice();
288 CLogMessage(
this).
error(u
"No audio output device found. Audio For VATSIM (AFV) "
297 if (this->usesSameDevices(useInputDevice, useOutputDevice))
306 this->initTransceivers();
313 if (m_soundcardSampleProvider)
315 m_soundcardSampleProvider->disconnect();
316 m_soundcardSampleProvider->deleteLater();
319 connect(m_soundcardSampleProvider, &CSoundcardSampleProvider::receivingCallsignsChanged,
this,
320 &CAfvClient::onReceivingCallsignsChanged);
322 if (m_outputSampleProvider) { m_outputSampleProvider->deleteLater(); }
332 m_output->start(useOutputDevice, m_outputSampleProvider);
334 if (useInputDevice.
getType() != CAudioDeviceInfo::Unknown) { m_input->start(useInputDevice); }
338 u
"No audio input device was found. Audio for VATSIM (AFV) will run in receive-only mode.");
342 m_voiceServerTimer->start(PositionUpdatesMs);
346 this->setReceiveAudio(
true);
348 this->onSettingsChanged();
353 this->onTimerUpdate();
355 emit this->startedAudio(useInputDevice, useOutputDevice);
357 if (this->isOutputMuted())
360 this->setOutputMuted(
false);
364 void CAfvClient::startAudio(
const QString &inputDeviceName,
const QString &outputDeviceName)
366 const CAudioDeviceInfo i = CAudioDeviceInfoList::allInputDevices().findByName(inputDeviceName);
367 const CAudioDeviceInfo o = CAudioDeviceInfoList::allOutputDevices().findByName(outputDeviceName);
368 this->startAudio(i, o);
371 void CAfvClient::stopAudio()
378 if (myself) stopAudio();
390 this->setReceiveAudio(
false);
400 if (this->isOutputMuted()) { this->setOutputMuted(
false); }
402 emit this->inputVolumePeakVU(0.0);
403 emit this->outputVolumePeakVU(0.0);
404 emit this->stoppedAudio();
407 void CAfvClient::restartAudio()
419 if (myself) { myself->startAudio(); }
449 void CAfvClient::setReceiveAudio(
bool receive)
452 if (!m_connection) {
return; }
453 m_connection->setReceiveAudio(receive);
456 void CAfvClient::enableTransceiver(quint16
id,
bool enable)
460 if (enable) { m_enabledTransceivers.insert(
id); }
461 else { m_enabledTransceivers.remove(
id); }
464 this->updateTransceivers();
469 this->enableTransceiver(comUnitToTransceiverId(comUnit), enable);
472 bool CAfvClient::isEnabledTransceiver(quint16
id)
const
475 const auto enabledTransceivers = this->getEnabledTransceivers();
476 if (!enabledTransceivers.contains(
id)) {
return false; }
478 const auto transceivers = this->getTransceivers();
479 return std::any_of(transceivers.cbegin(), transceivers.cend(),
485 return this->isEnabledTransceiver(comUnitToTransceiverId(comUnit));
488 void CAfvClient::updateComFrequency(quint16
id, quint32 frequencyHz)
490 if (
id != 0 &&
id != 1) {
return; }
493 quint32 roundedFrequencyHz =
static_cast<quint32
>(qRound(frequencyHz / 1000.0)) * 1000;
494 roundedFrequencyHz = this->getAliasFrequencyHz(roundedFrequencyHz);
499 if (m_transceivers.size() >=
id + 1)
501 if (m_transceivers[
id].frequencyHz != roundedFrequencyHz)
504 m_transceivers[id].frequencyHz = roundedFrequencyHz;
512 this->updateTransceivers(
false);
518 const auto freqHz =
static_cast<quint32
>(comFrequency.
valueInteger(CFrequencyUnit::Hz()));
519 this->updateComFrequency(comUnitToTransceiverId(comUnit), freqHz);
527 void CAfvClient::updatePosition(
double latitudeDeg,
double longitudeDeg,
double heightMeters)
532 transceiver.LatDeg = latitudeDeg;
533 transceiver.LonDeg = longitudeDeg;
534 transceiver.HeightAglM = heightMeters;
535 transceiver.HeightMslM = heightMeters;
539 void CAfvClient::updateTransceivers(
bool updateFrequencies)
546 this->updatePosition(ownAircraft.
latitude().
value(CAngleUnit::deg()),
550 if (updateFrequencies)
552 this->updateComFrequency(CComSystem::Com1, ownAircraft.
getCom1System());
553 this->updateComFrequency(CComSystem::Com2, ownAircraft.
getCom2System());
558 const auto transceivers = this->getTransceivers();
559 const auto enabledTransceivers = this->getEnabledTransceivers();
560 const QString callsign = this->getCallsign();
564 for (
const TransceiverDto &transceiver : transceivers)
566 if (enabledTransceivers.contains(transceiver.id)) { newEnabledTransceivers.
push_back(transceiver); }
572 if (m_connection) { m_connection->updateTransceivers(callsign, newEnabledTransceivers); }
576 if (m_soundcardSampleProvider)
578 m_soundcardSampleProvider->updateRadioTransceivers(newEnabledTransceivers);
583 void CAfvClient::setTransmittingTransceiver(quint16 transceiverID)
586 this->setTransmittingTransceivers({ tx });
591 this->setTransmittingTransceiver(comUnitToTransceiverId(comUnit));
597 m_transmittingTransceivers = transceivers;
600 bool CAfvClient::isTransmittingTransceiver(quint16
id)
const
603 return std::any_of(m_transmittingTransceivers.cbegin(), m_transmittingTransceivers.cend(),
609 return this->isTransmittingTransceiver(comUnitToTransceiverId(comUnit));
612 void CAfvClient::setRxTx(
bool rx1,
bool tx1,
bool rx2,
bool tx2)
625 this->setTransmittingTransceivers(txs);
628 if (rx1 || tx1) { enabledTransceivers.
insert(comUnitToTransceiverId(CComSystem::Com1)); }
630 if (rx2 || tx2) { enabledTransceivers.
insert(comUnitToTransceiverId(CComSystem::Com2)); }
634 m_enabledTransceivers = enabledTransceivers;
638 this->onTimerUpdate();
641 void CAfvClient::getRxTx(
bool &rx1,
bool &tx1,
bool &rx2,
bool &tx2)
const
649 rx1 = enabled.
contains(comUnitToTransceiverId(CComSystem::Com1));
650 rx2 = enabled.
contains(comUnitToTransceiverId(CComSystem::Com2));
655 if (dto.id == comUnitToTransceiverId(CComSystem::Com1)) { tx1 =
true; }
656 if (dto.id == comUnitToTransceiverId(CComSystem::Com2)) { tx2 =
true; }
663 return m_transceivers;
669 return m_enabledTransceivers;
675 return m_transmittingTransceivers;
678 void CAfvClient::setPtt(
bool active)
686 if (active && m_disableTransmissionCapability)
692 if (m_transmit == active) {
return; }
698 if (m_soundcardSampleProvider) { m_soundcardSampleProvider->pttUpdate(active, m_transmittingTransceivers); }
713 emit this->ptt(active, this->identifier());
716 double CAfvClient::getInputVolumeDb()
const
719 return m_inputVolumeDb;
722 bool CAfvClient::setInputVolumeDb(
double valueDb)
729 if (!myself || !CAfvClient::hasContexts()) {
return; }
730 myself->setInputVolumeDb(valueDb);
735 if (valueDb > MaxDbIn) { valueDb = MaxDbIn; }
736 else if (valueDb < MinDbIn) { valueDb = MinDbIn; }
739 bool changed = !qFuzzyCompare(m_inputVolumeDb, valueDb);
742 m_inputVolumeDb = valueDb;
745 const double gainRatio = qPow(10, valueDb / 20.0);
746 changed = m_input->setGainRatio(gainRatio);
755 if (comUnit == CComSystem::Com1)
return m_outputVolumeDbCom1;
756 if (comUnit == CComSystem::Com2)
return m_outputVolumeDbCom2;
757 qFatal(
"Invalid COM unit");
764 if (comUnit == CComSystem::Com1)
return m_outputGainRatioCom1;
765 if (comUnit == CComSystem::Com2)
return m_outputGainRatioCom2;
766 qFatal(
"Invalid COM unit");
770 int CAfvClient::getNormalizedInputVolume()
const
772 const double db = this->getInputVolumeDb();
773 const double range = MaxDbIn - MinDbIn;
774 const int i = qRound((db - MinDbIn) / range * 100);
778 int CAfvClient::getNormalizedMasterOutputVolume()
const
781 return m_outputMasterVolumeNormalized;
787 if (comUnit == CComSystem::Com1) {
return m_outputVolumeCom1Normalized; }
788 if (comUnit == CComSystem::Com2) {
return m_outputVolumeCom2Normalized; }
789 qFatal(
"Invalid ComUnit");
793 bool CAfvClient::setNormalizedInputVolume(
int volume)
795 if (volume < 0) { volume = 0; }
796 else if (volume > 100) { volume = 100; }
797 const double range = MaxDbIn - MinDbIn;
798 const double dB = MinDbIn + (volume * range / 100.0);
801 return this->setInputVolumeDb(dB);
804 bool CAfvClient::setNormalizedMasterOutputVolume(
int volume)
811 if (!myself || !CAfvClient::hasContexts()) {
return; }
812 myself->setNormalizedMasterOutputVolume(volume);
817 bool changed =
false;
820 changed = m_outputMasterVolumeNormalized != volume;
821 if (changed) { m_outputMasterVolumeNormalized = volume; }
825 int com1Normalized = getNormalizedComOutputVolume(CComSystem::Com1);
826 int com2Normalized = getNormalizedComOutputVolume(CComSystem::Com2);
827 setNormalizedComOutputVolume(CComSystem::Com1, com1Normalized);
828 setNormalizedComOutputVolume(CComSystem::Com2, com2Normalized);
835 if (volume < 0) { volume = 0; }
836 else if (volume > 100) { volume = 100; }
839 if (comUnit == CComSystem::Com1) { m_outputVolumeCom1Normalized = volume; }
840 else if (comUnit == CComSystem::Com2) { m_outputVolumeCom2Normalized = volume; }
841 else { qFatal(
"Invalid ComUnit"); }
844 volume = qRound((
double)volume * getNormalizedMasterOutputVolume() / 100);
847 double range = MaxDbOut;
849 if (volume >= 50) { volume -= 50; }
853 range = qAbs(MinDbOut);
855 dB += (volume * range / 50.0);
858 return this->setComOutputVolumeDb(comUnit, dB);
861 double CAfvClient::getInputVolumePeakVU()
const
864 return m_inputVolumeStream.PeakVU;
867 double CAfvClient::getOutputVolumePeakVU()
const
870 return m_outputVolumeStream.PeakVU;
875 const bool transmit = m_transmit;
876 const bool loopback = m_loopbackOn;
877 const bool transmitHistory = m_transmitHistory;
878 const auto transceivers = this->getTransceivers();
880 if (loopback && transmit)
884 audioData.
callsign = QStringLiteral(
"loopback");
888 const RxTransceiverDto com1 = { 0, transceivers.size() > 0 ? transceivers[0].frequencyHz : UniCom, 1.0 };
889 const RxTransceiverDto com2 = { 1, transceivers.size() > 1 ? transceivers[1].frequencyHz : UniCom, 1.0 };
892 m_soundcardSampleProvider->addOpusSamples(audioData, { com1, com2 });
896 if (!this->isConnected()) {
return; }
898 const QString callsign = this->getCallsign();
899 const auto transmittingTransceivers = this->getTransmittingTransceivers();
900 if (!transmittingTransceivers.isEmpty())
904 AudioTxOnTransceiversDto dto;
908 dto.lastPacket =
false;
910 std::vector<TxTransceiverDto>(transmittingTransceivers.begin(), transmittingTransceivers.end());
912 m_connection->sendToVoiceServer(dto);
915 if (!transmit && transmitHistory)
917 AudioTxOnTransceiversDto dto;
921 dto.lastPacket =
true;
923 std::vector<TxTransceiverDto>(transmittingTransceivers.begin(), transmittingTransceivers.end());
925 m_connection->sendToVoiceServer(dto);
927 m_transmitHistory = transmit;
931 void CAfvClient::audioOutDataAvailable(
const AudioRxOnTransceiversDto &dto)
934 audioData.
audio =
QByteArray(dto.audio.data(),
static_cast<int>(dto.audio.size()));
936 audioData.lastPacket = dto.lastPacket;
937 audioData.sequenceCounter = dto.sequenceCounter;
940 m_soundcardSampleProvider->addOpusSamples(
949 m_inputVolumeStream = args;
951 emit inputVolumePeakVU(args.
PeakVU);
959 m_outputVolumeStream = args;
961 emit outputVolumePeakVU(args.
PeakVU);
964 QString CAfvClient::getReceivingCallsignsStringCom1()
const
967 if (!m_soundcardSampleProvider)
return {};
968 return m_soundcardSampleProvider->getReceivingCallsignsString(comUnitToTransceiverId(CComSystem::Com1));
971 QString CAfvClient::getReceivingCallsignsStringCom2()
const
974 if (!m_soundcardSampleProvider)
return {};
975 return m_soundcardSampleProvider->getReceivingCallsignsString(comUnitToTransceiverId(CComSystem::Com2));
981 if (!m_soundcardSampleProvider)
return {};
982 return m_soundcardSampleProvider->getReceivingCallsigns(comUnitToTransceiverId(CComSystem::Com1));
988 if (!m_soundcardSampleProvider)
return {};
989 return m_soundcardSampleProvider->getReceivingCallsigns(comUnitToTransceiverId(CComSystem::Com2));
992 QStringList CAfvClient::getReceivingCallsignsStringCom1Com2()
const
996 if (!m_soundcardSampleProvider) {
return { {
QString(),
QString() } }; }
997 coms << m_soundcardSampleProvider->getReceivingCallsignsString(comUnitToTransceiverId(CComSystem::Com1));
998 coms << m_soundcardSampleProvider->getReceivingCallsignsString(comUnitToTransceiverId(CComSystem::Com2));
1002 bool CAfvClient::updateVoiceServerUrl(
const QString &url)
1005 if (!m_connection) {
return false; }
1006 return m_connection->updateVoiceServerUrl(url);
1009 void CAfvClient::gracefulShutdown()
1012 this->disconnectFrom();
1013 this->quitAndWait();
1017 void CAfvClient::initialize()
1022 void CAfvClient::cleanup()
1025 if (m_winCoInitialized)
1028 m_winCoInitialized =
false;
1033 void CAfvClient::onTimerUpdate()
1039 this->updateFromOwnAircraft(aircraft,
false);
1042 this->autoLogoffWithoutFsdNetwork();
1045 this->fetchSimulatorSettings();
1050 this->updateTransceivers();
1054 this->checkServerHeartbeat();
1057 void CAfvClient::checkServerHeartbeat()
1059 if (!this->isStarted()) {
return; }
1060 if (!this->isConnected()) {
return; }
1062 if (this->isVoiceServerAlive())
1064 m_heartBeatFailures = 0;
1070 const int failures = ++m_heartBeatFailures;
1071 if (failures < 2) {
return; }
1079 un = m_connection->getUserName();
1080 pw = m_connection->getPassword();
1081 cs = m_connection->getCallsign();
1082 client = m_connection->getClient();
1087 if (this->isConnected()) { this->disconnectFrom(
false); }
1091 if (!myself) {
return; }
1092 const QString reason = QStringLiteral(
"Heartbeat failed %1 times").
arg(failures);
1093 this->retryConnectTo(un, pw, cs, client, reason);
1097 void CAfvClient::onSettingsChanged()
1099 const CSettings audioSettings = m_audioSettings.get();
1105 this->setNormalizedInputVolume(iv);
1106 this->setNormalizedMasterOutputVolume(ov);
1107 this->setNormalizedComOutputVolume(CComSystem::Com1, ov1);
1108 this->setNormalizedComOutputVolume(CComSystem::Com2, ov2);
1112 void CAfvClient::autoLogoffWithoutFsdNetwork()
1114 if (!hasContexts()) {
return; }
1115 if (!this->isConnected())
1117 m_fsdConnectMismatches = 0;
1124 m_fsdConnectMismatches = 0;
1127 if (++m_fsdConnectMismatches < 2) {
return; }
1129 CLogMessage(
this).
warning(u
"Auto logoff AFV client because FSD no longer connected");
1130 this->disconnectFrom();
1139 transceiverCom1.
id = comUnitToTransceiverId(CComSystem::Com1);
1140 transceiverCom2.
id = comUnitToTransceiverId(CComSystem::Com2);
1143 const double latDeg = aircraft.
latitude().
value(CAngleUnit::deg());
1144 const double lngDeg = aircraft.
longitude().
value(CAngleUnit::deg());
1147 transceiverCom1.
LatDeg = transceiverCom2.
LatDeg = latDeg;
1148 transceiverCom1.
LonDeg = transceiverCom2.
LonDeg = lngDeg;
1158 transceiverCom1.
frequencyHz = this->getAliasFrequencyHz(f1);
1159 transceiverCom2.
frequencyHz = this->getAliasFrequencyHz(f2);
1162 if (m_integratedComUnit)
1172 this->setNormalizedComOutputVolume(CComSystem::Com1, vol1);
1173 this->setNormalizedComOutputVolume(CComSystem::Com2, vol2);
1178 const bool e1 = rx1;
1179 const bool e2 = rx2;
1187 newEnabledTransceivers.
push_back(transceiverCom1);
1188 newEnabledTransceiverIds.
insert(transceiverCom1.
id);
1192 newEnabledTransceivers.
push_back(transceiverCom2);
1193 newEnabledTransceiverIds.
insert(transceiverCom2.
id);
1197 if (tx1 && e1) { newTransmittingTransceivers.
push_back(transceiverCom1); }
1198 else if (tx2 && e2) { newTransmittingTransceivers.
push_back(transceiverCom2); }
1203 m_transceivers = newTransceivers;
1204 m_enabledTransceivers = newEnabledTransceiverIds;
1205 m_transmittingTransceivers = newTransmittingTransceivers;
1212 if (ids.
contains(comUnitToTransceiverId(CComSystem::Com1)))
1214 newEnabledTransceivers.
push_back(transceiverCom1);
1217 if (ids.
contains(comUnitToTransceiverId(CComSystem::Com2)))
1219 newEnabledTransceivers.
push_back(transceiverCom2);
1224 const QString callsign = this->getCallsign();
1231 m_connection->updateTransceivers(callsign, newEnabledTransceivers);
1237 if (m_soundcardSampleProvider)
1239 m_soundcardSampleProvider->updateRadioTransceivers(newEnabledTransceivers);
1244 if (withSignals) { emit this->updatedFromOwnAircraftCockpit(); }
1249 if (originator == this->identifier()) {
return; }
1250 this->updateFromOwnAircraft(aircraft);
1260 case CComSystem::Com1:
1263 callsignsCom2 = this->getReceivingCallsignsCom2();
1266 case CComSystem::Com2:
1268 callsignsCom1 = this->getReceivingCallsignsCom1();
1272 emit this->receivedCallsignsChanged(callsignsCom1, callsignsCom2);
1273 emit this->receivingCallsignsChanged(args);
1276 void CAfvClient::retryConnectTo(
const QString &cid,
const QString &password,
const QString &callsign,
1279 if (this->isConnected()) {
return; }
1280 m_retryConnectAttempt++;
1282 const int retrySecs = qMin(3 * 60, m_retryConnectAttempt * 30);
1284 << retrySecs << m_retryConnectAttempt;
1285 this->reconnectTo(cid, password, callsign, client, retrySecs * 1000, msg);
1294 emit this->afvConnectionFailure(msg);
1299 if (!myself) {
return; }
1300 if (myself->isConnected()) { return; }
1301 this->connectTo(cid, password, callsign, client);
1305 void CAfvClient::toggleTransmissionCapability(
bool disableTransmission)
1307 if (m_disableTransmissionCapability == disableTransmission) {
return; }
1308 m_disableTransmissionCapability = disableTransmission;
1310 if (disableTransmission)
1320 return m_aliasedStations;
1326 m_aliasedStations = stations;
1329 quint32 CAfvClient::getAliasFrequencyHz(quint32 frequencyHz)
const
1332 quint32 roundedFrequencyHz =
static_cast<quint32
>(qRound(frequencyHz / 1000.0)) * 1000;
1337 CFrequency roundedFrequency(
static_cast<int>(roundedFrequencyHz), CFrequencyUnit::Hz());
1338 const auto it = std::find_if(m_aliasedStations.constBegin(), m_aliasedStations.constEnd(),
1339 [roundedFrequency](
const StationDto &d) {
1340 if (d.frequencyAliasHz > 100000000 &&
1341 roundedFrequency.value(CFrequencyUnit::Hz()) > 100000000)
1343 const int aliasedFreqHz = qRound(d.frequencyAliasHz / 1000.0) * 1000;
1344 return CComSystem::isSameFrequency(
1345 CFrequency(aliasedFreqHz, CFrequencyUnit::Hz()), roundedFrequency);
1347 return d.frequencyAliasHz == roundedFrequency.value(CFrequencyUnit::Hz());
1350 if (it != m_aliasedStations.constEnd())
1355 const CFrequency f(
static_cast<int>(roundedFrequencyHz), CFrequencyUnit::Hz());
1366 roundedFrequencyHz = it->frequencyHz;
1368 << closest.
getCallsign() << frequencyHz << it->frequencyHz;
1374 u
"Station '%1' NOT found! Candidate was '%2'. Using original frequency %3 Hz")
1381 roundedFrequencyHz = it->frequencyHz;
1383 << frequencyHz << it->frequencyHz;
1387 return roundedFrequencyHz;
1390 bool CAfvClient::isVoiceServerAlive()
const
1393 return m_connection && m_connection->isVoiceServerAlive();
1396 const QString &CAfvClient::getVoiceServerUrl()
const
1401 if (!m_connection) {
return e; }
1402 return m_connection->getVoiceServerUrl();
1405 bool CAfvClient::fuzzyMatchCallsign(
const QString &callsign,
const QString &compareTo)
const
1413 this->getPrefixSuffix(callsign, prefixA, suffixA);
1414 this->getPrefixSuffix(compareTo, prefixB, suffixB);
1415 return (prefixA == prefixB) && (suffixA == suffixB);
1432 case CComSystem::Com1:
return 0;
1433 case CComSystem::Com2:
return 1;
1441 if (comUnitToTransceiverId(CComSystem::Com1) ==
id) {
return CComSystem::Com1; }
1442 if (comUnitToTransceiverId(CComSystem::Com2) ==
id) {
return CComSystem::Com2; }
1443 return CComSystem::Com1;
1446 void CAfvClient::deferredInit()
1449 this->initTransceivers();
1452 this->onSettingsChanged();
1458 bool CAfvClient::hasContexts()
1471 if (!myself || !CAfvClient::hasContexts()) {
return; }
1472 myself->setComOutputVolumeDb(comUnit, valueDb);
1476 if (comUnit != CComSystem::Com1 && comUnit != CComSystem::Com2) {
return false; }
1477 if (valueDb > MaxDbOut) { valueDb = MaxDbOut; }
1478 else if (valueDb < MinDbOut) { valueDb = MinDbOut; }
1480 const double gainRatio = qPow(10, valueDb / 20.0);
1481 bool changed =
false;
1484 if (comUnit == CComSystem::Com1)
1486 changed = !qFuzzyCompare(m_outputVolumeDbCom1, valueDb);
1489 m_outputVolumeDbCom1 = valueDb;
1490 m_outputGainRatioCom1 = gainRatio;
1495 changed = !qFuzzyCompare(m_outputVolumeDbCom2, valueDb);
1498 m_outputVolumeDbCom2 = valueDb;
1499 m_outputGainRatioCom2 = gainRatio;
1507 if (!m_mutexSampleProviders.tryLock(1000)) {
return false; }
1509 if (m_soundcardSampleProvider)
1511 changed = m_soundcardSampleProvider->setGainRatioForTransceiver(comUnit, gainRatio);
1513 m_mutexSampleProviders.unlock();
1520 if (m_input) {
return m_input->device(); }
1528 if (m_output) {
return m_output->device(); }
1536 if (!m_output || !m_input) {
return false; }
1546 return this->isConnected() ? Connected : Disconnected;
SWIFT_CORE_EXPORT swift::core::CApplication * sApp
Single instance of application object.
const context::IContextOwnAircraft * getIContextOwnAircraft() const
Direct access to contexts if a CCoreFacade has been initialized.
const context::IContextNetwork * getIContextNetwork() const
Direct access to contexts if a CCoreFacade has been initialized.
bool isShuttingDown() const
Is application shutting down?
const context::IContextSimulator * getIContextSimulator() const
Direct access to contexts if a CCoreFacade has been initialized.
ConnectionStatus
Connection status.
bool isConnected() const
Is connected to network?
QString getCallsign() const
}@
void setCallsign(const QString &getCallsign)
Copy operations.
void setReceiveAudio(bool value)
Receiving audio?
bool isConnected() const
Is connected?
virtual swift::misc::aviation::CAtcStationList getOnlineStationsForFrequency(const swift::misc::physical_quantities::CFrequency &frequency) const =0
Online stations for frequency.
virtual bool isConnected() const =0
Network connected?
virtual swift::misc::simulation::CSimulatedAircraft getOwnAircraft() const =0
Get own aircraft.
virtual swift::misc::aviation::CAircraftSituation getOwnAircraftSituation() const =0
Get own aircraft.
virtual swift::misc::simulation::settings::CSimulatorSettings getSimulatorSettings() const =0
Get the current simulator settings.
Base class for a long-lived worker object which lives in its own thread.
Base class with a member CIdentifier to be inherited by a class which has an identity in the environm...
Value object encapsulating information identifying a component of a modular distributed swift process...
static const QString & vatsimSpecific()
VATSIM specific.
static const QString & audio()
Audio related.
Class for emitting a log message.
static void preformatted(const CStatusMessage &statusMessage)
Sends a verbatim, preformatted message to the log.
Derived & warning(const char16_t(&format)[N])
Set the severity to warning, providing a format string.
Derived & validationError(const char16_t(&format)[N])
Set the severity to error, providing a format string, and adding the validation category.
Derived & error(const char16_t(&format)[N])
Set the severity to error, providing a format string.
Derived & debug()
Set the severity to debug.
Derived & info(const char16_t(&format)[N])
Set the severity to info, providing a format string.
Streamable status message, e.g.
bool isFailure() const
Operation considered unsuccessful.
static QString currentThreadInfo()
Info about current thread, for debug messages.
static bool isInThisThread(const QObject *toBeTested)
Is the current thread the object's thread?
Value object encapsulating information of a audio device.
DeviceType getType() const
Type.
bool isOutputDevice() const
Output device.
bool isValid() const
Valid audio device object?
bool matchesNameTypeMachineName(const CAudioDeviceInfo &device) const
Matching name, type and machine.
const QString & getName() const
Get the device name.
Value object encapsulating information of audio related settings.
int getOutVolumeCom2() const
Get volume for com2 (audio) 0..100.
int getOutVolume() const
Get volume (audio) 0..100.
bool isAudioEffectsEnabled() const
Audio effects enabled?
int getInVolume() const
Get mic.volume (audio 0..100)
int getOutVolumeCom1() const
Get volume for com1 (audio) 0..100.
const geo::CCoordinateGeodetic & getPosition() const
Get position.
Value object encapsulating information about an ATC station.
const CCallsign & getCallsign() const
Get callsign.
Value object for a list of ATC stations.
const QString & asString() const
Get callsign (normalized)
Value object for a set of callsigns.
bool isTransmitEnabled() const
Enabled?
int getVolumeReceive() const
Output volume 0..100.
bool isReceiveEnabled() const
Enabled?
swift::misc::physical_quantities::CFrequency getFrequencyActive() const
Active frequency.
CONTAINER findClosest(int number, const ICoordinateGeodetic &coordinate) const
Find 0..n objects closest to the given coordinate.
int valueInteger(MU unit) const
As integer value.
double value(MU unit) const
Value in given unit.
Comprehensive information of an aircraft.
geo::CLongitude longitude() const
Longitude.
const aviation::CComSystem & getCom2System() const
Get COM2 system.
geo::CLatitude latitude() const
Latitude.
const aviation::CAltitude & getAltitude() const
Get altitude.
const aviation::CComSystem & getCom1System() const
Get COM1 system.
bool isComIntegrated() const
COM unit integration.
Free functions in swift::misc.
auto singleShot(int msec, QObject *target, F &&task)
Starts a single-shot timer which will call a task in the thread of the given object when it times out...
QByteArray::iterator begin()
QByteArray::iterator end()
qsizetype size() const const
void push_back(QList< T >::parameter_type value)
qsizetype size() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool disconnect(const QMetaObject::Connection &connection)
void setObjectName(QAnyStringView name)
QThread * thread() const const
bool contains(const QSet< T > &other) const const
QSet< T >::iterator insert(QSet< T >::const_iterator it, const T &value)
QString arg(Args &&... args) const const
QString fromStdString(const std::string &str)
bool isEmpty() const const
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
std::string toStdString() const const
QThread * currentThread()
bool lastPacket
Used to indicate to receiver that the sender has stopped sending.
QByteArray audio
Opus compressed audio.
QString callsign
Callsign that audio originates from.
uint sequenceCounter
Receiver optionally uses this in reordering algorithm/gap detection.
double HeightMslM
Properties.
double HeightAglM
Properties.
quint32 frequencyHz
Properties.
Transmit transceiver DTO.
uint sequenceCounter
sequence counter
QByteArray audio
audio data
QStringList receivingCallsigns
callsigns
quint16 transceiverID
transceiver id