Files
pilotclient/src/blackcore/context/contextaudio.h
Lars Toenning a203fc0c1f refactor: Remove unused PTT enum
Currently, the PTT can only be activated on the active frequency
anyway.
2024-04-24 22:51:55 +02:00

372 lines
15 KiB
C++

// SPDX-FileCopyrightText: Copyright (C) 2013 swift Project Community / Contributors
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
//! \file
#ifndef BLACKCORE_CONTEXT_CONTEXTAUDIO_H
#define BLACKCORE_CONTEXT_CONTEXTAUDIO_H
#include "blackcore/audio/audiosettings.h"
#include "blackcore/context/context.h"
#include "blackcore/actionbind.h"
#include "blackcore/corefacade.h"
#include "blackcore/corefacadeconfig.h"
#include "blackcore/blackcoreexport.h"
#include "blackcore/afv/audio/receiversampleprovider.h"
#include "blacksound/selcalplayer.h"
#include "blacksound/notificationplayer.h"
#include "blackmisc/macos/microphoneaccess.h"
#include "blackmisc/audio/audiodeviceinfolist.h"
#include "blackmisc/audio/notificationsounds.h"
#include "blackmisc/audio/audiosettings.h"
#include "blackmisc/aviation/callsignset.h"
#include "blackmisc/aviation/comsystem.h"
#include "blackmisc/aviation/selcal.h"
#include "blackmisc/network/connectionstatus.h"
#include "blackmisc/network/userlist.h"
#include "blackmisc/input/actionhotkeydefs.h"
#include "blackmisc/genericdbusinterface.h"
#include "blackmisc/simplecommandparser.h"
#include "blackmisc/identifiable.h"
#include "blackmisc/identifier.h"
#include <QObject>
#include <QString>
#include <QCommandLineOption>
// clazy:excludeall=const-signal-or-slot
//! \ingroup dbus
//! DBus interface for context
#define BLACKCORE_CONTEXTAUDIO_INTERFACENAME "org.swift_project.blackcore.contextaudio"
//! \ingroup dbus
//! DBus object path for context
#define BLACKCORE_CONTEXTAUDIO_OBJECTPATH "/audio"
class QDBusConnection;
namespace BlackMisc
{
class CDBusServer;
}
namespace BlackCore
{
namespace Afv::Clients
{
class CAfvClient;
}
namespace Context
{
//! Audio context interface
class BLACKCORE_EXPORT IContextAudio : public IContext
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", BLACKCORE_CONTEXTAUDIO_INTERFACENAME)
friend class BlackCore::CCoreFacade;
public:
//! Interface name
static const QString &InterfaceName();
//! Object path
static const QString &ObjectPath();
//! \copydoc IContext::getPathAndContextId()
virtual QString getPathAndContextId() const override { return this->buildPathAndContextId(ObjectPath()); }
//! Factory method
static IContextAudio *create(CCoreFacade *runtime, CCoreFacadeConfig::ContextMode mode, BlackMisc::CDBusServer *server, QDBusConnection &connection);
// ------------- only use DBus signals here -------------
signals:
//! Authentication failed, ....
void voiceClientFailure(const BlackMisc::CStatusMessage &msg);
public slots:
// ------------- DBus ---------------
//! All registered devices
virtual BlackMisc::Audio::CAudioDeviceInfoList getRegisteredDevices() const = 0;
//! Register a device on a machine (for core/GUI it will return all known devices on all machines)
virtual void registerDevices(const BlackMisc::Audio::CAudioDeviceInfoList &devices) = 0;
//! Unregister devices
virtual void unRegisterDevices(const BlackMisc::Audio::CAudioDeviceInfoList &devices) = 0;
//! Remove all devices for identifer (i.e. "a machine")
virtual void unRegisterDevicesFor(const BlackMisc::CIdentifier &identifier) = 0;
//! Register an audio callsign (used with AFV)
//! \remarks normally called with login
virtual void registerAudioCallsign(const BlackMisc::Aviation::CCallsign &callsign, const BlackMisc::CIdentifier &identifier) = 0;
//! Un-register an audio callsign (used with AFV)
//! \remarks normally called with logoff
virtual void unRegisterAudioCallsign(const BlackMisc::Aviation::CCallsign &callsign, const BlackMisc::CIdentifier &identifier) = 0;
//! Un-register an audio callsign (used with AFV)
//! \remarks normally called with logoff
virtual bool hasRegisteredAudioCallsign(const BlackMisc::Aviation::CCallsign &callsign) const = 0;
// ------------- DBus ---------------
protected:
//! Constructor
IContextAudio(CCoreFacadeConfig::ContextMode mode, CCoreFacade *runtime);
//! Devices have been changed
void onChangedLocalDevices(const BlackMisc::Audio::CAudioDeviceInfoList &devices);
};
//! Audio context interface
class BLACKCORE_EXPORT CContextAudioBase :
public IContextAudio,
public BlackMisc::CIdentifiable
{
Q_OBJECT
friend class BlackCore::CCoreFacade;
protected:
//! Constructor
CContextAudioBase(CCoreFacadeConfig::ContextMode mode, CCoreFacade *runtime);
public:
//! Destructor
virtual ~CContextAudioBase() override;
//! Graceful shutdown
void gracefulShutdown();
//! @{
//! Enable/disable
void enableVoiceClient() { this->initVoiceClient(); }
void enableVoiceClientAndStart();
void disableVoiceClient() { this->terminateVoiceClient(); }
//! @}
//! @{
//! Receive/transmit
void setRxTx(bool rx1, bool tx1, bool rx2, bool tx2);
void getRxTx(bool &rx1, bool &tx1, bool &rx2, bool &tx2) const;
//! @}
// -------- parts which can run in core and GUI, referring to local voice client ------------
//! @{
//! Audio devices
BlackMisc::Audio::CAudioDeviceInfoList getAudioDevices() const;
BlackMisc::Audio::CAudioDeviceInfoList getAudioInputDevices() const;
BlackMisc::Audio::CAudioDeviceInfoList getAudioOutputDevices() const;
BlackMisc::Audio::CAudioDeviceInfoList getAudioDevicesPlusDefault() const;
BlackMisc::Audio::CAudioDeviceInfoList getAudioInputDevicesPlusDefault() const;
BlackMisc::Audio::CAudioDeviceInfoList getAudioOutputDevicesPlusDefault() const;
//! @}
//! Get current audio device
//! \return input and output devices
BlackMisc::Audio::CAudioDeviceInfoList getCurrentAudioDevices() const;
//! Set current audio devices
void setCurrentAudioDevices(const BlackMisc::Audio::CAudioDeviceInfo &inputDevice, const BlackMisc::Audio::CAudioDeviceInfo &outputDevice);
//! @{
//! Volume
void setMasterOutputVolume(int volume);
void setComOutputVolume(BlackMisc::Aviation::CComSystem::ComUnit comUnit, int volume);
int getMasterOutputVolume() const;
int getComOutputVolume(BlackMisc::Aviation::CComSystem::ComUnit comUnit) const;
void setMute(bool muted);
bool isMuted() const;
//! @}
//! SELCAL
void playSelcalTone(const BlackMisc::Aviation::CSelcal &selcal);
//! Notification sounds
void playNotification(BlackMisc::Audio::CNotificationSounds::NotificationFlag notification, bool considerSettings, int volume = -1);
//! @{
//! Loopback
void enableAudioLoopback(bool enable = true);
bool isAudioLoopbackEnabled() const;
//! @}
//! Info string about audio
QString audioRunsWhereInfo() const;
//! Audio runs where
const BlackMisc::CIdentifier &audioRunsWhere() const;
//! Is COM unit enabled?
bool isEnabledComUnit(BlackMisc::Aviation::CComSystem::ComUnit comUnit) const;
//! Is COM unit transmitting?
bool isTransmittingComUnit(BlackMisc::Aviation::CComSystem::ComUnit comUnit) const;
//! Connect to audio with network credentials
//! \remark if there is no network connection/credential this just returns
bool connectAudioWithNetworkCredentials();
//! Is audio connected?
bool isAudioConnected() const;
//! Is audio started?
bool isAudioStarted() const;
//! Is audio enabled?
bool isAudioEnabled() const { return m_voiceClient; }
//! Integrated with COM unit?
bool isComUnitIntegrated() const;
//! \todo WORKAROUND to hide the "local signals"
Afv::Clients::CAfvClient *afvClient() const { return m_voiceClient; }
//! Cmd.line arguments
static const QList<QCommandLineOption> &getCmdLineOptions();
//! No audio?
static bool isNoAudioSet();
//! Register the commands
static void registerHelp()
{
if (BlackMisc::CSimpleCommandParser::registered("BlackCore::Context::CContextAudioBase")) { return; }
BlackMisc::CSimpleCommandParser::registerCommand({ ".mute", "mute audio" });
BlackMisc::CSimpleCommandParser::registerCommand({ ".unmute", "unmute audio" });
BlackMisc::CSimpleCommandParser::registerCommand({ ".vol volume", "volume 0..100" });
BlackMisc::CSimpleCommandParser::registerCommand({ ".aliased on|off", "aliased HF frequencies" });
}
// -------- parts which can run in core and GUI, referring to local voice client ------------
public slots:
// ------------- DBus ---------------
//! \cond
//! Parse command line
//! \ingroup swiftdotcommands
//! <pre>
//! .mute mute BlackCore::Context::CContextAudioBase
//! .unmute unmute BlackCore::Context::CContextAudioBase
//! .vol .volume volume 0..100 set volume BlackCore::Context::CContextAudioBase
//! .aliased on|off aliased stations BlackCore::Context::CContextAudioBase
//! </pre>
virtual bool parseCommandLine(const QString &commandLine, const BlackMisc::CIdentifier &originator) override;
//! \endcond
// ------------- DBus ---------------
// ------------ local signals -------
signals:
//! Audio volume changed
//! \sa setVoiceOutputVolume
void changedAudioVolume(int volume);
//! Mute changed
void changedMute(bool muted);
//! Changed audio devices (e.g. device enabled/disable)
void changedLocalAudioDevices(const BlackMisc::Audio::CAudioDeviceInfoList &devices);
//! Audio started with devices
void startedAudio(const BlackMisc::Audio::CAudioDeviceInfo &input, const BlackMisc::Audio::CAudioDeviceInfo &output);
//! Audio stopped
void stoppedAudio();
//! PTT in voice client received
void ptt(bool active, const BlackMisc::CIdentifier &identifier);
/*
* Workaround those must be invisible for DBus
*
//! @{
//! VU levels
void inputVolumePeakVU (double value);
void outputVolumePeakVU(double value);
//! @}
//! Callsigns I receive have changed
void receivingCallsignsChanged(const BlackCore::Afv::Audio::TransceiverReceivingCallsignsChangedArgs &args);
//! Client updated from own aicraft data
void updatedFromOwnAircraftCockpit();
* end workaround */
// ------------ local signals -------
private:
//! Init the voice client
void initVoiceClient();
//! Terminate the voice client
void terminateVoiceClient();
//! Enable/disable voice transmission, normally used with hotkey
void setVoiceTransmission(bool enable);
//! Change the device settings
void changeDeviceSettings();
//! Changed audio settings
void onChangedAudioSettings();
//! @{
//! Audio increase/decrease volume
void audioIncreaseVolume(bool enabled);
void audioDecreaseVolume(bool enabled);
void audioIncreaseVolumeCom1(bool enabled);
void audioDecreaseVolumeCom1(bool enabled);
void audioIncreaseVolumeCom2(bool enabled);
void audioDecreaseVolumeCom2(bool enabled);
//! @}
//! Network connection status
void xCtxNetworkConnectionStatusChanged(const BlackMisc::Network::CConnectionStatus &from, const BlackMisc::Network::CConnectionStatus &to);
//! AFV client connection status changed
void onAfvConnectionStatusChanged(int status);
//! AFV client authentication failed
void onAfvConnectionFailure(const BlackMisc::CStatusMessage &msg);
CActionBind m_actionPtt { BlackMisc::Input::pttHotkeyAction(), BlackMisc::Input::pttHotkeyIcon(), this, &CContextAudioBase::setVoiceTransmission };
CActionBind m_actionAudioVolumeIncrease { BlackMisc::Input::audioVolumeIncreaseHotkeyAction(), BlackMisc::Input::audioVolumeIncreaseHotkeyIcon(), this, &CContextAudioBase::audioIncreaseVolume };
CActionBind m_actionAudioVolumeDecrease { BlackMisc::Input::audioVolumeDecreaseHotkeyAction(), BlackMisc::Input::audioVolumeDecreaseHotkeyIcon(), this, &CContextAudioBase::audioDecreaseVolume };
CActionBind m_actionAudioVolumeIncreaseCom1 { BlackMisc::Input::audioVolumeIncreaseCom1HotkeyAction(), BlackMisc::Input::audioVolumeIncreaseHotkeyIcon(), this, &CContextAudioBase::audioIncreaseVolumeCom1 };
CActionBind m_actionAudioVolumeDecreaseCom1 { BlackMisc::Input::audioVolumeDecreaseCom1HotkeyAction(), BlackMisc::Input::audioVolumeDecreaseHotkeyIcon(), this, &CContextAudioBase::audioDecreaseVolumeCom1 };
CActionBind m_actionAudioVolumeIncreaseCom2 { BlackMisc::Input::audioVolumeIncreaseCom2HotkeyAction(), BlackMisc::Input::audioVolumeIncreaseHotkeyIcon(), this, &CContextAudioBase::audioIncreaseVolumeCom2 };
CActionBind m_actionAudioVolumeDecreaseCom2 { BlackMisc::Input::audioVolumeDecreaseCom2HotkeyAction(), BlackMisc::Input::audioVolumeDecreaseHotkeyIcon(), this, &CContextAudioBase::audioDecreaseVolumeCom2 };
int m_outMasterVolumeBeforeMute = 50;
static constexpr int MinUnmuteVolume = 20; //!< minimum volume when unmuted
//! Do we use a local core
static bool isRunningWithLocalCore();
// settings
BlackMisc::CSetting<BlackMisc::Audio::TSettings> m_audioSettings { this, &CContextAudioBase::onChangedAudioSettings };
BlackMisc::CSetting<Audio::TInputDevice> m_inputDeviceSetting { this, &CContextAudioBase::changeDeviceSettings };
BlackMisc::CSetting<Audio::TOutputDevice> m_outputDeviceSetting { this, &CContextAudioBase::changeDeviceSettings };
// AFV
Afv::Clients::CAfvClient *m_voiceClient = nullptr;
bool m_winCoInitialized = false;
BlackMisc::Audio::CAudioDeviceInfoList m_activeLocalDevices;
// Players
BlackSound::CSelcalPlayer *m_selcalPlayer = nullptr;
BlackSound::CNotificationPlayer m_notificationPlayer;
};
} // ns
} // ns
#endif // guard