swift
contextaudio.cpp
1 // SPDX-FileCopyrightText: Copyright (C) 2013 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
5 
6 #include "config/buildconfig.h"
10 #include "core/context/contextnetwork.h" // for user login
11 #include "core/context/contextownaircraft.h" // for COM integration
12 #include "core/context/contextsimulator.h" // for COM intergration
13 #include "misc/dbusserver.h"
14 #include "misc/icons.h"
16 #include "misc/stringutils.h"
17 #include "misc/verify.h"
18 
19 #ifdef Q_OS_WIN
20 # include "comdef.h"
21 #endif
22 
23 using namespace swift::misc;
24 using namespace swift::misc::aviation;
25 using namespace swift::misc::audio;
26 using namespace swift::misc::network;
27 using namespace swift::misc::physical_quantities;
28 using namespace swift::misc::simulation;
29 using namespace swift::sound;
30 using namespace swift::core::afv::clients;
31 
33 
34 namespace swift::core::context
35 {
36  IContextAudio::IContextAudio(CCoreFacadeConfig::ContextMode mode, CCoreFacade *runtime) : IContext(mode, runtime)
37  {
38  // void
39  }
40 
41  void IContextAudio::onChangedLocalDevices(const CAudioDeviceInfoList &devices) { this->registerDevices(devices); }
42 
43  const QString &IContextAudio::InterfaceName()
44  {
45  static const QString s(SWIFT_CORE_CONTEXTAUDIO_INTERFACENAME);
46  return s;
47  }
48 
49  const QString &IContextAudio::ObjectPath()
50  {
51  static const QString s(SWIFT_CORE_CONTEXTAUDIO_OBJECTPATH);
52  return s;
53  }
54 
55  IContextAudio *IContextAudio::create(CCoreFacade *runtime, CCoreFacadeConfig::ContextMode mode, CDBusServer *server,
56  QDBusConnection &connection)
57  {
58  // for audio no empty context is available
59  // since CContextAudioBaseImpl provides audio on either side (core/GUI) we do not use ContextAudioEmpty
60  // ContextAudioEmpty would cause issue, as it is initializing "common parts" during shutdown
61  switch (mode)
62  {
63  case CCoreFacadeConfig::Local: return new CContextAudio(mode, runtime);
64  case CCoreFacadeConfig::LocalInDBusServer:
65  {
66  auto *context = new CContextAudio(mode, runtime);
67  context->registerWithDBus(ObjectPath(), server);
68  return context;
69  }
70  case CCoreFacadeConfig::Remote:
71  return new CContextAudioProxy(CDBusServer::coreServiceName(connection), connection, mode, runtime);
72  case CCoreFacadeConfig::NotUsed:
73  SWIFT_VERIFY_X(false, Q_FUNC_INFO, "Empty context not supported for audio (since AFV)");
74  return nullptr;
75  default: SWIFT_VERIFY_X(false, Q_FUNC_INFO, "Unknown context mode"); return nullptr;
76  }
77  }
78 
79  bool CContextAudioBase::parseCommandLine(const QString &commandLine, const CIdentifier &originator)
80  {
81  Q_UNUSED(originator)
82  if (commandLine.isEmpty()) { return false; }
83  CSimpleCommandParser parser({
84  ".vol", ".volume", // output volume
85  ".mute", // mute
86  ".unmute", // unmute
87  });
88  parser.parse(commandLine);
89  if (!parser.isKnownCommand()) { return false; }
90 
91  if (parser.matchesCommand(".mute"))
92  {
93  this->setOutputMute(true);
94  return true;
95  }
96  else if (parser.matchesCommand(".unmute"))
97  {
98  this->setOutputMute(false);
99  return true;
100  }
101  else if (parser.commandStartsWith("vol") && parser.countParts() > 1)
102  {
103  const int v = parser.toInt(1);
104  this->setMasterOutputVolume(v);
105  return true;
106  }
107  return false;
108  }
109 
110  CContextAudioBase::CContextAudioBase(CCoreFacadeConfig::ContextMode mode, CCoreFacade *runtime)
111  : IContextAudio(mode, runtime), CIdentifiable(this)
112  {
113  CContextAudioBase::registerHelp();
114 
115  if (CContextAudioBase::isNoAudioSet()) { CLogMessage(this).info(u"Voice client disabled"); }
116  else { this->initVoiceClient(); }
117 
118  // here we are in a base class of one context
119  // the whole context/facade system is not initialized when this code here is executed
120 
121  QPointer<CContextAudioBase> myself(this);
122  QTimer::singleShot(5000, this, [=] {
123  if (!myself || !sApp || sApp->isShuttingDown()) { return; }
124 
125  const CSettings as = m_audioSettings.getThreadLocal();
126  this->setMasterOutputVolume(as.getOutVolume());
127  this->setComOutputVolume(CComSystem::Com1, as.getOutVolumeCom1());
128  this->setComOutputVolume(CComSystem::Com2, as.getOutVolumeCom2());
129  m_selcalPlayer = new CSelcalPlayer(CAudioDeviceInfo::getDefaultOutputDevice(), this);
130 
131  myself->changeDeviceSettings();
132  myself->onChangedAudioSettings();
133  myself->onChangedLocalDevices(m_activeLocalDevices);
134  });
135  }
136 
137  CContextAudioBase::~CContextAudioBase() { this->gracefulShutdown(); }
138 
139  void CContextAudioBase::initVoiceClient()
140  {
141  if (m_voiceClient || !sApp) { return; }
142 
143  const CAudioDeviceInfoList devices = CAudioDeviceInfoList::allDevices();
144  if (devices != m_activeLocalDevices)
145  {
146  m_activeLocalDevices = devices;
147  emit this->changedLocalAudioDevices(devices);
148  }
149 
150 #ifdef Q_OS_WIN
151  if (!m_winCoInitialized)
152  {
153  HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
154 
155  // RPC_E_CHANGED_MODE: CoInitializeEx was already called by someone else in this thread with a different
156  // mode.
157  if (hr == RPC_E_CHANGED_MODE)
158  {
159  CLogMessage(this).debug(u"CoInitializeEx was already called with a different mode. Trying again.");
160  hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
161  }
162 
163  // S_OK: The COM library was initialized successfully on this thread.
164  // S_FALSE: The COM library is already initialized on this thread. Reference count was incremented. This is
165  // not an error.
166  if (hr == S_OK || hr == S_FALSE) { m_winCoInitialized = true; }
167  }
168 #endif
169 
170  m_voiceClient = new CAfvClient(sApp->getGlobalSetup().getAfvApiServerUrl().toQString(), this);
171 
172  Q_ASSERT_X(m_voiceClient->thread() == qApp->thread(), Q_FUNC_INFO, "Should be in main thread");
173  m_voiceClient->start(); // thread
174  Q_ASSERT_X(m_voiceClient->owner() == this, Q_FUNC_INFO, "Wrong owner");
175  Q_ASSERT_X(m_voiceClient->thread() != qApp->thread(), Q_FUNC_INFO, "Must NOT be in main thread");
176 
177  // connect(m_voiceClient, &CAfvClient::outputVolumePeakVU, this,
178  // &CContextAudioBase::outputVolumePeakVU, Qt::QueuedConnection); connect(m_voiceClient,
179  // &CAfvClient::inputVolumePeakVU, this, &CContextAudioBase::inputVolumePeakVU,
180  // Qt::QueuedConnection); connect(m_voiceClient, &CAfvClient::receivingCallsignsChanged, this,
181  // &CContextAudioBase::receivingCallsignsChanged, Qt::QueuedConnection); connect(m_voiceClient,
182  // &CAfvClient::updatedFromOwnAircraftCockpit, this, &CContextAudioBase::updatedFromOwnAircraftCockpit,
183  // Qt::QueuedConnection);
184  connect(m_voiceClient, &CAfvClient::startedAudio, this, &CContextAudioBase::startedAudio, Qt::QueuedConnection);
185  connect(m_voiceClient, &CAfvClient::stoppedAudio, this, &CContextAudioBase::stoppedAudio, Qt::QueuedConnection);
186  connect(m_voiceClient, &CAfvClient::ptt, this, &CContextAudioBase::ptt, Qt::QueuedConnection);
187  connect(m_voiceClient, &CAfvClient::changedOutputMute, this, &CContextAudioBase::changedOutputMute,
188  Qt::QueuedConnection);
189  connect(m_voiceClient, &CAfvClient::connectionStatusChanged, this,
190  &CContextAudioBase::onAfvConnectionStatusChanged, Qt::QueuedConnection);
191  connect(m_voiceClient, &CAfvClient::afvConnectionFailure, this, &CContextAudioBase::onAfvConnectionFailure,
192  Qt::QueuedConnection);
193  }
194 
195  void CContextAudioBase::terminateVoiceClient()
196  {
197  if (m_voiceClient)
198  {
199  m_voiceClient->gracefulShutdown();
200  Q_ASSERT_X(CThreadUtils::isInThisThread(m_voiceClient), Q_FUNC_INFO, "Needs to be back in current thread");
201  m_voiceClient->deleteLater();
202  m_voiceClient = nullptr;
203 #ifdef Q_OS_WIN
204  if (m_winCoInitialized)
205  {
206  CoUninitialize();
207  m_winCoInitialized = false;
208  }
209 #endif
210  }
211  }
212 
213  void CContextAudioBase::gracefulShutdown()
214  {
215  this->terminateVoiceClient();
216  if (m_selcalPlayer)
217  {
218  m_selcalPlayer->gracefulShutdown();
219  m_selcalPlayer = nullptr;
220  }
221  QObject::disconnect(this);
222  }
223 
224  void CContextAudioBase::setRxTx(bool rx1, bool tx1, bool rx2, bool tx2)
225  {
226  if (m_voiceClient) { m_voiceClient->setRxTx(rx1, tx1, rx2, tx2); }
227  }
228 
229  void CContextAudioBase::getRxTx(bool &rx1, bool &tx1, bool &rx2, bool &tx2) const
230  {
231  if (m_voiceClient) { m_voiceClient->setRxTx(rx1, tx1, rx2, tx2); }
232  }
233 
234  const CIdentifier &CContextAudioBase::audioRunsWhere() const
235  {
236  static const CIdentifier i("CContextAudioBaseImpl");
237  return i;
238  }
239 
240  bool CContextAudioBase::isEnabledComUnit(CComSystem::ComUnit comUnit) const
241  {
242  if (!m_voiceClient) { return false; }
243  return m_voiceClient->isEnabledComUnit(comUnit);
244  }
245 
246  bool CContextAudioBase::isTransmittingComUnit(CComSystem::ComUnit comUnit) const
247  {
248  if (!m_voiceClient) { return false; }
249  return m_voiceClient->isTransmittingComUnit(comUnit);
250  }
251 
252  bool CContextAudioBase::connectAudioWithNetworkCredentials()
253  {
254  if (!m_voiceClient) { return false; }
255  if (!sApp || sApp->isShuttingDown() || !sApp->getIContextNetwork()) { return false; }
256 
257  const CEcosystem ecoSystem = this->getIContextNetwork()->getConnectedServer().getEcosystem();
258  if (ecoSystem != CEcosystem::vatsim())
259  {
260  CLogMessage(this).info(u"Will not use AFV as ecosystem is '%1'") << ecoSystem.toQString(true);
261  return false;
262  }
263 
264  const CUser connectedUser = this->getIContextNetwork()->getConnectedServer().getUser();
265  const QString client = "swift " % swift::config::CBuildConfig::getShortVersionString();
266  CCallsign cs = connectedUser.getCallsign();
267  this->unRegisterAudioCallsign(cs, this->identifier()); // un-register "myself"
268  if (this->hasRegisteredAudioCallsign(cs)) // anybody else using that callsign
269  {
271  cs = CCallsign(cs.asString() + "2");
272  }
273  CLogMessage(this).info(u"About to connect to voice as '%1' '%2'") << connectedUser.getId() << cs;
274  m_voiceClient->connectTo(connectedUser.getId(), connectedUser.getPassword(), cs.asString(), client);
275  this->registerAudioCallsign(cs, this->identifier()); // login can still fail, but we "block" this callsign
276  return true;
277  }
278 
279  bool CContextAudioBase::isAudioConnected() const { return m_voiceClient && m_voiceClient->isConnected(); }
280 
281  bool CContextAudioBase::isAudioStarted() const { return m_voiceClient && m_voiceClient->isStarted(); }
282 
283  bool CContextAudioBase::isComUnitIntegrated() const
284  {
285  return m_voiceClient && m_voiceClient->isComUnitIntegrated();
286  }
287 
288  const QList<QCommandLineOption> &CContextAudioBase::getCmdLineOptions()
289  {
290  static const QList<QCommandLineOption> opts { QCommandLineOption(
291  { { "n", "noaudio" },
292  QCoreApplication::translate("CContextAudioBase", "No audio for GUI or core.", "noaudio") }) };
293  return opts;
294  }
295 
296  bool CContextAudioBase::isNoAudioSet()
297  {
298  if (!sApp) { return false; }
299  return sApp->isParserOptionSet("noaudio");
300  }
301 
302  QString CContextAudioBase::audioRunsWhereInfo() const
303  {
304  const QString s = QStringLiteral("[%1] Audio on '%2', '%3'.")
305  .arg(boolToEnabledDisabled(this->isAudioStarted()), audioRunsWhere().getMachineName(),
306  audioRunsWhere().getProcessName());
307  return s;
308  }
309 
310  CAudioDeviceInfoList CContextAudioBase::getAudioDevices() const { return CAudioDeviceInfoList::allDevices(); }
311 
312  CAudioDeviceInfoList CContextAudioBase::getAudioInputDevices() const
313  {
314  return this->getAudioDevices().getInputDevices();
315  }
316 
317  CAudioDeviceInfoList CContextAudioBase::getAudioOutputDevices() const
318  {
319  return this->getAudioDevices().getOutputDevices();
320  }
321 
322  CAudioDeviceInfoList CContextAudioBase::getCurrentAudioDevices() const
323  {
324  const QString inputDeviceName = m_inputDeviceSetting.get();
325  const CAudioDeviceInfo inputDevice = this->getAudioInputDevices().findByNameOrDefault(
326  inputDeviceName, CAudioDeviceInfo::getDefaultInputDevice());
327 
328  const QString outputDeviceName = m_outputDeviceSetting.get();
329  const CAudioDeviceInfo outputDevice = this->getAudioOutputDevices().findByNameOrDefault(
330  outputDeviceName, CAudioDeviceInfo::getDefaultOutputDevice());
331 
332  CAudioDeviceInfoList devices;
333  devices.push_back(inputDevice);
334  devices.push_back(outputDevice);
335  return devices;
336  }
337 
338  void CContextAudioBase::setCurrentAudioDevices(const CAudioDeviceInfo &inputDevice,
339  const CAudioDeviceInfo &outputDevice)
340  {
341  if (!m_voiceClient) { return; }
342  if (!sApp) { return; }
343 
344  if (!inputDevice.getName().isEmpty() && inputDevice.getName() != m_inputDeviceSetting.get())
345  {
346  Q_ASSERT_X(inputDevice.isInputDevice(), Q_FUNC_INFO, "Need input device");
347  const CStatusMessage m = m_inputDeviceSetting.setAndSave(inputDevice.getName());
348  CLogMessage::preformatted(m);
349  }
350  if (!outputDevice.getName().isEmpty() && outputDevice.getName() != m_outputDeviceSetting.get())
351  {
352  Q_ASSERT_X(outputDevice.isOutputDevice(), Q_FUNC_INFO, "Need output device");
353  const CStatusMessage m = m_outputDeviceSetting.setAndSave(outputDevice.getName());
354  CLogMessage::preformatted(m);
355  }
356 
357  m_voiceClient->startAudio(inputDevice, outputDevice);
358  }
359 
360  void CContextAudioBase::setMasterOutputVolume(int volume)
361  {
362  if (!m_voiceClient) { return; }
363 
364  const bool wasMuted = this->isOutputMuted();
365  volume = CSettings::fixOutVolume(volume);
366 
367  const int currentVolume = m_voiceClient->getNormalizedMasterOutputVolume();
368  const bool changedVoiceOutput = (currentVolume != volume);
369  if (changedVoiceOutput)
370  {
371  // TODO: KB 2020-05 the mute handling should entirely go to AFV client!
372  m_voiceClient->setNormalizedMasterOutputVolume(volume);
373  m_outMasterVolumeBeforeMute = volume;
374 
375  emit this->changedAudioVolume(volume);
376  if ((volume > 0 && wasMuted) || (volume < 1 && !wasMuted))
377  {
378  // inform about muted
379  emit this->changedOutputMute(volume < 1);
380  }
381  }
382 
383  CSettings as(m_audioSettings.getThreadLocal());
384  if (as.getOutVolume() != volume)
385  {
386  as.setOutVolume(volume);
387  m_audioSettings.set(as);
388  }
389  }
390 
391  void CContextAudioBase::setComOutputVolume(CComSystem::ComUnit comUnit, int volume)
392  {
393  if (comUnit != CComSystem::Com1 && comUnit != CComSystem::Com2) { return; }
394  if (!m_voiceClient) { return; }
395 
396  volume = CSettings::fixOutVolume(volume);
397 
398  const int currentVolume = m_voiceClient->getNormalizedComOutputVolume(comUnit);
399  const bool changedVoiceOutput = (currentVolume != volume);
400  if (changedVoiceOutput)
401  {
402  m_voiceClient->setNormalizedComOutputVolume(comUnit, volume);
403  emit this->changedAudioVolume(volume);
404  }
405 
406  CSettings as(m_audioSettings.getThreadLocal());
407  if (comUnit == CComSystem::Com1 && as.getOutVolumeCom1() != volume)
408  {
409  as.setOutVolumeCom1(volume);
410  m_audioSettings.set(as);
411  }
412  else if (comUnit == CComSystem::Com2 && as.getOutVolumeCom2() != volume)
413  {
414  as.setOutVolumeCom2(volume);
415  m_audioSettings.set(as);
416  }
417  }
418 
419  int CContextAudioBase::getMasterOutputVolume() const
420  {
421  if (!m_voiceClient) { return 0; }
422  return m_voiceClient->getNormalizedMasterOutputVolume();
423  }
424 
425  int CContextAudioBase::getComOutputVolume(CComSystem::ComUnit comUnit) const
426  {
427  if (!m_voiceClient) { return 0; }
428  return m_voiceClient->getNormalizedComOutputVolume(comUnit);
429  }
430 
431  void CContextAudioBase::setOutputMute(bool muted)
432  {
433  if (!m_voiceClient) { return; }
434  if (this->isOutputMuted() == muted) { return; } // avoid roundtrips / unnecessary signals
435 
436  if (muted) { m_outMasterVolumeBeforeMute = m_voiceClient->getNormalizedMasterOutputVolume(); }
437 
438  m_voiceClient->setOutputMuted(muted);
439  if (!muted) { m_voiceClient->setNormalizedMasterOutputVolume(m_outMasterVolumeBeforeMute); }
440  }
441 
442  bool CContextAudioBase::isOutputMuted() const
443  {
444  if (!m_voiceClient) { return false; }
445  return m_voiceClient->isOutputMuted();
446  }
447 
448  void CContextAudioBase::playSelcalTone(const CSelcal &selcal)
449  {
450  using namespace std::chrono_literals;
451  const std::chrono::milliseconds ms = m_selcalPlayer->play(90, selcal);
452  if (ms > 10ms)
453  {
454  // Play additional notification
455  const QPointer<const CContextAudioBase> myself(this);
456  QTimer::singleShot(ms, this, [=] {
457  if (!sApp || sApp->isShuttingDown() || !myself) { return; }
458  this->playNotification(CNotificationSounds::NotificationTextMessageSupervisor, true);
459  });
460  }
461  }
462 
463  void CContextAudioBase::playNotification(CNotificationSounds::NotificationFlag notification, bool considerSettings,
464  int volume)
465  {
466  if (isDebugEnabled())
467  {
468  CLogMessage(this, CLogCategories::contextSlot()).debug() << Q_FUNC_INFO << notification;
469  }
470 
471  const CSettings settings = m_audioSettings.getThreadLocal();
472  const bool play = !considerSettings || settings.isNotificationFlagSet(notification);
473  if (!play) { return; }
474 
475  if (volume < 0 || volume > 100)
476  {
477  volume = 90;
478  if (considerSettings) { volume = qMax(25, settings.getNotificationVolume()); }
479  }
480  m_notificationPlayer.play(notification, volume);
481  }
482 
483  void CContextAudioBase::enableAudioLoopback(bool enable)
484  {
485  if (!m_voiceClient) { return; }
486  m_voiceClient->setLoopBack(enable);
487  }
488 
489  bool CContextAudioBase::isAudioLoopbackEnabled() const
490  {
491  if (!m_voiceClient) { return false; }
492  return m_voiceClient->isLoopback();
493  }
494 
495  void CContextAudioBase::setVoiceTransmission(bool enable)
496  {
497  if (!m_voiceClient) { return; }
498  m_voiceClient->setPtt(enable);
499  }
500 
501  void CContextAudioBase::changeDeviceSettings()
502  {
503  const CAudioDeviceInfoList devices = this->getCurrentAudioDevices();
504  Q_ASSERT_X(devices.size() == 2, Q_FUNC_INFO, "Expect INPUT and OUTPUT device");
505 
506  const CAudioDeviceInfo input = devices.front();
507  const CAudioDeviceInfo output = devices.back();
508  this->setCurrentAudioDevices(input, output);
509  }
510 
511  void CContextAudioBase::onChangedAudioSettings()
512  {
513  const CSettings s = m_audioSettings.get();
514  const QString dir = s.getNotificationSoundDirectory();
515  m_notificationPlayer.updateDirectory(dir);
516  this->setMasterOutputVolume(s.getOutVolume());
517  this->setComOutputVolume(CComSystem::Com1, s.getOutVolumeCom1());
518  this->setComOutputVolume(CComSystem::Com2, s.getOutVolumeCom2());
519  }
520 
521  void CContextAudioBase::audioIncreaseVolume(bool enabled)
522  {
523  if (!enabled) { return; }
524  const int v = qRound(this->getMasterOutputVolume() * 1.05);
525  this->setMasterOutputVolume(v);
526  }
527 
528  void CContextAudioBase::audioDecreaseVolume(bool enabled)
529  {
530  if (!enabled) { return; }
531  const int v = qRound(this->getMasterOutputVolume() / 1.05);
532  this->setMasterOutputVolume(v);
533  }
534 
535  void CContextAudioBase::audioIncreaseVolumeCom1(bool enabled)
536  {
537  if (!enabled) { return; }
538  if (isComUnitIntegrated()) { return; }
539  const int v = qRound(this->getComOutputVolume(CComSystem::Com1) * 1.05);
540  this->setComOutputVolume(CComSystem::Com1, v);
541  }
542 
543  void CContextAudioBase::audioDecreaseVolumeCom1(bool enabled)
544  {
545  if (!enabled) { return; }
546  if (isComUnitIntegrated()) { return; }
547  const int v = qRound(this->getComOutputVolume(CComSystem::Com1) / 1.05);
548  this->setComOutputVolume(CComSystem::Com1, v);
549  }
550 
551  void CContextAudioBase::audioIncreaseVolumeCom2(bool enabled)
552  {
553  if (!enabled) { return; }
554  if (isComUnitIntegrated()) { return; }
555  const int v = qRound(this->getComOutputVolume(CComSystem::Com2) * 1.05);
556  this->setComOutputVolume(CComSystem::Com2, v);
557  }
558 
559  void CContextAudioBase::audioDecreaseVolumeCom2(bool enabled)
560  {
561  if (!enabled) { return; }
562  if (isComUnitIntegrated()) { return; }
563  const int v = qRound(this->getComOutputVolume(CComSystem::Com2) / 1.05);
564  this->setComOutputVolume(CComSystem::Com2, v);
565  }
566 
567  void CContextAudioBase::xCtxNetworkConnectionStatusChanged(const CConnectionStatus &from,
568  const CConnectionStatus &to)
569  {
570  if (!m_voiceClient) { return; }
571 
572  Q_UNUSED(from)
573  SWIFT_VERIFY_X(this->getIContextNetwork(), Q_FUNC_INFO, "Missing network context");
574 
575  // we only change network connection of AFV client here
576  if (to.isConnected() && this->getIContextNetwork())
577  {
578  const bool connected = this->connectAudioWithNetworkCredentials();
579  Q_UNUSED(connected)
580 
581  // one reason for not connecting is NOT using the VATSIM ecosystem
582  }
583  else if (to.isDisconnected()) { m_voiceClient->disconnectFrom(); }
584  }
585 
586  void CContextAudioBase::onAfvConnectionStatusChanged(int status)
587  {
588  if (!m_voiceClient) { return; }
589 
590  const CCallsign cs = m_voiceClient->getCallsign();
591  const CAfvClient::ConnectionStatus s = static_cast<CAfvClient::ConnectionStatus>(status);
592 
593  switch (s)
594  {
595  case CAfvClient::Connected: this->registerAudioCallsign(cs, this->identifier()); break;
596  case CAfvClient::Disconnected: this->unRegisterAudioCallsign(cs, this->identifier()); break;
597  }
598  }
599 
600  void CContextAudioBase::onAfvConnectionFailure(const CStatusMessage &msg)
601  {
602  if (!m_voiceClient) { return; }
603  emit this->voiceClientFailure(msg);
604  }
605 
606  bool CContextAudioBase::isRunningWithLocalCore() { return sApp && sApp->isLocalContext(); }
607 
608 } // namespace swift::core::context
609 
SWIFT_CORE_EXPORT swift::core::CApplication * sApp
Single instance of application object.
Definition: application.cpp:71
static const QString & getShortVersionString()
Version as QVersionNumber.
bool isParserOptionSet(const QString &option) const
Delegates to QCommandLineParser::isSet.
data::CGlobalSetup getGlobalSetup() const
Global setup.
const context::IContextNetwork * getIContextNetwork() const
Direct access to contexts if a CCoreFacade has been initialized.
bool isShuttingDown() const
Is application shutting down?
bool isLocalContext() const
Local application? (not DBus)
ConnectionStatus
Connection status.
Definition: afvclient.h:53
swift::misc::network::CUrl getAfvApiServerUrl() const
AFV voice server URL.
Definition: globalsetup.h:137
Custom DBusServer.
Definition: dbusserver.h:34
Base class with a member CIdentifier to be inherited by a class which has an identity in the environm...
Definition: identifiable.h:24
Value object encapsulating information identifying a component of a modular distributed swift process...
Definition: identifier.h:29
Class for emitting a log message.
Definition: logmessage.h:27
Derived & debug()
Set the severity to debug.
Derived & info(const char16_t(&format)[N])
Set the severity to info, providing a format string.
size_type size() const
Returns number of elements in the sequence.
Definition: sequence.h:273
void push_back(const T &value)
Appends an element at the end of the sequence.
Definition: sequence.h:305
reference front()
Access the first element.
Definition: sequence.h:225
reference back()
Access the last element.
Definition: sequence.h:249
Utility methods for simple line parsing used with the command line.
void parse(const QString &commandLine)
Parse.
Streamable status message, e.g.
Value object encapsulating information of a audio device.
bool isInputDevice() const
Input device.
bool isOutputDevice() const
Output device.
const QString & getName() const
Get the device name.
Value object encapsulating a list of audio devices.
CAudioDeviceInfoList getOutputDevices() const
Get output devices in that list.
CAudioDeviceInfoList getInputDevices() const
Get output devices in that list.
Value object encapsulating information of audio related settings.
Definition: audiosettings.h:25
int getNotificationVolume() const
Get volume (notifications)
int getOutVolumeCom2() const
Get volume for com2 (audio) 0..100.
bool isNotificationFlagSet(CNotificationSounds::NotificationFlag notification) const
Notification flag (play notification?)
int getOutVolume() const
Get volume (audio) 0..100.
int getOutVolumeCom1() const
Get volume for com1 (audio) 0..100.
const QString & getNotificationSoundDirectory() const
Notification directory.
Definition: audiosettings.h:87
Value object encapsulating information of a callsign.
Definition: callsign.h:30
const QString & asString() const
Get callsign (normalized)
Definition: callsign.h:96
Value object for SELCAL.
Definition: selcal.h:31
QString toQString(bool i18n=false) const
Cast as QString.
Definition: mixinstring.h:76
Value object encapsulating information about a connection status.
bool isConnected() const
Query status.
bool isDisconnected() const
Query status.
Ecosystem of server belonging together.
Definition: ecosystem.h:21
Value object encapsulating information of a user.
Definition: user.h:28
const QString & getPassword() const
Get password.
Definition: user.h:65
const QString & getId() const
Get id.
Definition: user.h:119
const aviation::CCallsign & getCallsign() const
Get associated callsign.
Definition: user.h:140
#define SWIFT_CORE_CONTEXTAUDIO_INTERFACENAME
DBus interface for context.
Definition: contextaudio.h:39
#define SWIFT_CORE_CONTEXTAUDIO_OBJECTPATH
DBus object path for context.
Definition: contextaudio.h:43
Free functions in swift::misc.
SWIFT_MISC_EXPORT const QString & boolToEnabledDisabled(bool v)
Bool to enabled/disabled.
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...
Definition: threadutils.h:30
#define SWIFT_VERIFY_X(COND, WHERE, WHAT)
A weaker kind of assert.
Definition: verify.h:26