Ref T730, AFV client

* restart function
* bogus mute function (needs implementation)
* float -> double
* log categories
* settings
This commit is contained in:
Klaus Basan
2019-09-25 17:32:10 +02:00
committed by Mat Sutcliffe
parent 835fdc478a
commit 661a6576c5
2 changed files with 166 additions and 101 deletions

View File

@@ -10,6 +10,7 @@
#include "blackcore/context/contextownaircraft.h" #include "blackcore/context/contextownaircraft.h"
#include "blackcore/application.h" #include "blackcore/application.h"
#include "blacksound/audioutilities.h" #include "blacksound/audioutilities.h"
#include "blackmisc/audio/audiodeviceinfolist.h"
#include <QDebug> #include <QDebug>
using namespace BlackCore::Context; using namespace BlackCore::Context;
@@ -28,8 +29,14 @@ namespace BlackCore
{ {
namespace Clients namespace Clients
{ {
const CLogCategoryList &CAfvClient::getLogCategories()
{
static const CLogCategoryList cats { CLogCategory::audio(), CLogCategory::vatsimSpecific() };
return cats;
}
CAfvClient::CAfvClient(const QString &apiServer, QObject *parent) : CAfvClient::CAfvClient(const QString &apiServer, QObject *parent) :
QObject(parent) QObject(parent), CIdentifiable(this)
{ {
m_connection = new CClientConnection(apiServer, this); m_connection = new CClientConnection(apiServer, this);
m_connection->setReceiveAudio(false); m_connection->setReceiveAudio(false);
@@ -40,9 +47,7 @@ namespace BlackCore
m_output = new Output(this); m_output = new Output(this);
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_connection, &CClientConnection::audioReceived, this, &CAfvClient::audioOutDataAvailable);
connect(&m_voiceServerPositionTimer, &QTimer::timeout, this, qOverload<>(&CAfvClient::updateTransceivers)); connect(&m_voiceServerPositionTimer, &QTimer::timeout, this, qOverload<>(&CAfvClient::updateTransceivers));
m_transceivers = m_transceivers =
@@ -54,7 +59,10 @@ namespace BlackCore
m_enabledTransceivers = { 0, 1 }; m_enabledTransceivers = { 0, 1 };
m_transmittingTransceivers = { { 0 } }; // TxTransceiverDto m_transmittingTransceivers = { { 0 } }; // TxTransceiverDto
qDebug() << "UserClient instantiated"; // init by settings
this->onSettingsChanged();
CLogMessage(this).info(u"UserClient instantiated");
} }
void CAfvClient::initWithContext() void CAfvClient::initWithContext()
@@ -72,8 +80,8 @@ namespace BlackCore
m_connection->connectTo(cid, password, callsign); m_connection->connectTo(cid, password, callsign);
this->updateTransceivers(); this->updateTransceivers();
if (m_connection->isConnected()) { emit connectionStatusChanged(Connected); } if (m_connection->isConnected()) { emit this->connectionStatusChanged(Connected); }
else { emit connectionStatusChanged(Disconnected); } else { emit this->connectionStatusChanged(Disconnected); }
m_connection->getAllAliasedStations(); m_connection->getAllAliasedStations();
} }
@@ -86,26 +94,12 @@ namespace BlackCore
QStringList CAfvClient::availableInputDevices() const QStringList CAfvClient::availableInputDevices() const
{ {
const QList<QAudioDeviceInfo> inputDevices = QAudioDeviceInfo::availableDevices(QAudio::AudioInput); return CAudioDeviceInfoList::allQtInputDevices().getDeviceNames();
QStringList deviceNames;
for (const QAudioDeviceInfo &inputDevice : inputDevices)
{
deviceNames << inputDevice.deviceName();
}
return deviceNames;
} }
QStringList CAfvClient::availableOutputDevices() const QStringList CAfvClient::availableOutputDevices() const
{ {
const QList<QAudioDeviceInfo> outputDevices = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput); return CAudioDeviceInfoList::allQtOutputDevices().getDeviceNames();
QStringList deviceNames;
for (const QAudioDeviceInfo &outputDevice : outputDevices)
{
deviceNames << outputDevice.deviceName();
}
return deviceNames;
} }
void CAfvClient::setBypassEffects(bool value) void CAfvClient::setBypassEffects(bool value)
@@ -116,11 +110,28 @@ namespace BlackCore
} }
} }
bool CAfvClient::isMuted() const
{
return !this->isStarted();
}
void CAfvClient::setMuted(bool mute)
{
Q_UNUSED(mute)
}
bool CAfvClient::restartWithNewDevices(const QAudioDeviceInfo &inputDevice, const QAudioDeviceInfo &outputDevice)
{
this->stop();
this->start(inputDevice, outputDevice, allTransceiverIds());
return true;
}
void CAfvClient::start(const QAudioDeviceInfo &inputDevice, const QAudioDeviceInfo &outputDevice, const QVector<quint16> &transceiverIDs) void CAfvClient::start(const QAudioDeviceInfo &inputDevice, const QAudioDeviceInfo &outputDevice, const QVector<quint16> &transceiverIDs)
{ {
if (m_isStarted) if (m_isStarted)
{ {
qDebug() << "Client already started"; CLogMessage(this).info(u"Client already started");
return; return;
} }
@@ -129,59 +140,28 @@ namespace BlackCore
outputSampleProvider = new CVolumeSampleProvider(soundcardSampleProvider, this); outputSampleProvider = new CVolumeSampleProvider(soundcardSampleProvider, this);
outputSampleProvider->setVolume(m_outputVolume); outputSampleProvider->setVolume(m_outputVolume);
m_output->start(outputDevice, outputSampleProvider); m_output->start(outputDevice.isNull() ? QAudioDeviceInfo::defaultOutputDevice() : outputDevice, outputSampleProvider);
m_input->start(inputDevice); m_input->start(inputDevice.isNull() ? QAudioDeviceInfo::defaultInputDevice() : inputDevice);
m_startDateTimeUtc = QDateTime::currentDateTimeUtc(); m_startDateTimeUtc = QDateTime::currentDateTimeUtc();
m_connection->setReceiveAudio(true); m_connection->setReceiveAudio(true);
m_voiceServerPositionTimer.start(5000); m_voiceServerPositionTimer.start(5000);
m_isStarted = true; m_isStarted = true;
qDebug() << ("Started [Input: " + inputDevice.deviceName() + "] [Output: " + outputDevice.deviceName() + "]"); CLogMessage(this).info(u"Started [Input: %1] [Output: %2]") << inputDevice.deviceName() << outputDevice.deviceName();
} }
void CAfvClient::start(const QString &inputDeviceName, const QString &outputDeviceName) void CAfvClient::start(const QString &inputDeviceName, const QString &outputDeviceName)
{ {
if (m_isStarted) { return; } const QAudioDeviceInfo i = CAudioDeviceInfoList::allQtInputDevices().findByName(inputDeviceName).toAudioDeviceInfo();
const QAudioDeviceInfo o = CAudioDeviceInfoList::allQtOutputDevices().findByName(outputDeviceName).toAudioDeviceInfo();
soundcardSampleProvider = new CSoundcardSampleProvider(SampleRate, { 0, 1 }, this); this->start(i, o, allTransceiverIds());
connect(soundcardSampleProvider, &CSoundcardSampleProvider::receivingCallsignsChanged, this, &CAfvClient::receivingCallsignsChanged);
outputSampleProvider = new CVolumeSampleProvider(soundcardSampleProvider, this);
outputSampleProvider->setVolume(m_outputVolume);
QAudioDeviceInfo inputDevice = QAudioDeviceInfo::defaultInputDevice();
for (const auto &device : QAudioDeviceInfo::availableDevices(QAudio::AudioInput))
{
if (device.deviceName().startsWith(inputDeviceName))
{
inputDevice = device;
break;
}
}
QAudioDeviceInfo outputDevice = QAudioDeviceInfo::defaultOutputDevice();
for (const auto &device : QAudioDeviceInfo::availableDevices(QAudio::AudioOutput))
{
if (device.deviceName().startsWith(outputDeviceName))
{
outputDevice = device;
break;
}
}
m_output->start(outputDevice, outputSampleProvider);
m_input->start(inputDevice);
m_startDateTimeUtc = QDateTime::currentDateTimeUtc();
m_connection->setReceiveAudio(true);
m_voiceServerPositionTimer.start(5000);
m_isStarted = true;
} }
void CAfvClient::stop() void CAfvClient::stop()
{ {
if (! m_isStarted) if (!m_isStarted)
{ {
qDebug() << "Client not started"; CLogMessage(this).info(u"Client NOT started");
return; return;
} }
@@ -193,6 +173,7 @@ namespace BlackCore
m_input->stop(); m_input->stop();
m_output->stop(); m_output->stop();
CLogMessage(this).info(u"Client NOT stopped");
} }
void CAfvClient::enableTransceiver(quint16 id, bool enable) void CAfvClient::enableTransceiver(quint16 id, bool enable)
@@ -212,9 +193,9 @@ namespace BlackCore
if (m_transceivers.size() >= id + 1) if (m_transceivers.size() >= id + 1)
{ {
if (m_transceivers[id].frequency != roundedFrequencyHz) if (m_transceivers[id].frequencyHz != roundedFrequencyHz)
{ {
m_transceivers[id].frequency = roundedFrequencyHz; m_transceivers[id].frequencyHz = roundedFrequencyHz;
updateTransceivers(); updateTransceivers();
} }
} }
@@ -276,7 +257,14 @@ namespace BlackCore
void CAfvClient::setPtt(bool active) void CAfvClient::setPtt(bool active)
{ {
if (! m_isStarted) this->setPttForCom(active, COMUnspecified);
}
void CAfvClient::setPttForCom(bool active, PTTCOM com)
{
Q_UNUSED(com)
if (!m_isStarted)
{ {
qDebug() << "Client not started"; qDebug() << "Client not started";
return; return;
@@ -301,20 +289,50 @@ namespace BlackCore
m_maxDbReadingInPTTInterval = -100; m_maxDbReadingInPTTInterval = -100;
} }
emit this->ptt(active, com, this->identifier());
qDebug() << "PTT:" << active; qDebug() << "PTT:" << active;
} }
void CAfvClient::setPttForCom(bool active, PTTCOM com)
{
this->setPtt(active);
}
void CAfvClient::setInputVolumeDb(double value) void CAfvClient::setInputVolumeDb(double value)
{ {
if (value > 18) { value = 18; } if (value > MaxDb) { value = MaxDb; }
if (value < -18) { value = -18; } if (value < MinDb) { value = MinDb; }
m_inputVolumeDb = value; m_inputVolumeDb = value;
m_input->setVolume(qPow(10, value / 20)); m_input->setVolume(qPow(10, value / 20.0));
}
int CAfvClient::getNormalizedInputVolume() const
{
const double db = this->getInputVolumeDb();
const double range = MaxDb - MinDb;
const int i = qRound((db - MinDb) / range * 100);
return i;
}
int CAfvClient::getNormalizedOutputVolume() const
{
const double db = this->getOutputVolumeDb();
const double range = MaxDb - MinDb;
const int i = qRound((db - MinDb) / range * 100);
return i;
}
void CAfvClient::setNormalizedInputVolume(int volume)
{
if (volume < 0) { volume = 0; }
else if (volume > 100) { volume = 100; }
const double range = MaxDb - MinDb;
const double dB = MinDb + (volume * range / 100.0);
this->setInputVolumeDb(dB);
}
void CAfvClient::setNormalizedOutputVolume(int volume)
{
if (volume < 0) { volume = 0; }
else if (volume > 100) { volume = 100; }
const double range = MaxDb - MinDb;
const double dB = MinDb + (volume * range / 100.0);
this->setOutputVolumeDb(dB);
} }
void CAfvClient::opusDataAvailable(const OpusDataAvailableArgs &args) void CAfvClient::opusDataAvailable(const OpusDataAvailableArgs &args)
@@ -326,8 +344,9 @@ namespace BlackCore
audioData.callsign = "loopback"; audioData.callsign = "loopback";
audioData.lastPacket = false; audioData.lastPacket = false;
audioData.sequenceCounter = 0; audioData.sequenceCounter = 0;
RxTransceiverDto com1 = { 0, m_transceivers[0].frequency, 0.0 };
RxTransceiverDto com2 = { 1, m_transceivers[1].frequency, 0.0 }; RxTransceiverDto com1 = { 0, m_transceivers.size() > 0 ? m_transceivers[0].frequencyHz : UniCom, 0.0 };
RxTransceiverDto com2 = { 1, m_transceivers.size() > 1 ? m_transceivers[1].frequencyHz : UniCom, 0.0 };
soundcardSampleProvider->addOpusSamples(audioData, { com1, com2 }); soundcardSampleProvider->addOpusSamples(audioData, { com1, com2 });
return; return;
@@ -408,8 +427,10 @@ namespace BlackCore
void CAfvClient::onSettingsChanged() void CAfvClient::onSettingsChanged()
{ {
CSettings audioSettings = m_audioSettings.get(); const CSettings audioSettings = m_audioSettings.get();
this->setNormalizedInputVolume(audioSettings.getInVolume());
this->setNormalizedOutputVolume(audioSettings.getOutVolume());
this->setBypassEffects(!audioSettings.isAudioEffectsEnabled());
} }
void CAfvClient::updateTransceiversFromContext(const CSimulatedAircraft &aircraft, const CIdentifier &originator) void CAfvClient::updateTransceiversFromContext(const CSimulatedAircraft &aircraft, const CIdentifier &originator)
@@ -448,6 +469,20 @@ namespace BlackCore
} }
} }
const QAudioDeviceInfo &CAfvClient::getInputDevice() const
{
if (m_input) { return m_input->device(); }
static const QAudioDeviceInfo null = QAudioDeviceInfo();
return null;
}
const QAudioDeviceInfo &CAfvClient::getOutputDevice() const
{
if (m_output) { return m_output->device(); }
static const QAudioDeviceInfo null = QAudioDeviceInfo();
return null;
}
CAfvClient::ConnectionStatus CAfvClient::getConnectionStatus() const CAfvClient::ConnectionStatus CAfvClient::getConnectionStatus() const
{ {
return m_connection->isConnected() ? Connected : Disconnected; return m_connection->isConnected() ? Connected : Disconnected;

View File

@@ -20,10 +20,11 @@
#include "blackcore/blackcoreexport.h" #include "blackcore/blackcoreexport.h"
#include "blacksound/sampleprovider/volumesampleprovider.h" #include "blacksound/sampleprovider/volumesampleprovider.h"
#include "blackmisc/settingscache.h"
#include "blackmisc/audio/audiosettings.h" #include "blackmisc/audio/audiosettings.h"
#include "blackmisc/audio/ptt.h" #include "blackmisc/audio/ptt.h"
#include "blackmisc/logcategorylist.h"
#include "blackmisc/identifiable.h"
#include "blackmisc/settingscache.h"
#include <QAudioDeviceInfo> #include <QAudioDeviceInfo>
#include <QDateTime> #include <QDateTime>
@@ -40,16 +41,20 @@ namespace BlackCore
namespace Clients namespace Clients
{ {
//! AFV client //! AFV client
class BLACKCORE_EXPORT CAfvClient final : public QObject class BLACKCORE_EXPORT CAfvClient final : public QObject, public BlackMisc::CIdentifiable
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(double inputVolumePeakVU READ getInputVolumePeakVU NOTIFY inputVolumePeakVU) Q_PROPERTY(double inputVolumePeakVU READ getInputVolumePeakVU NOTIFY inputVolumePeakVU)
Q_PROPERTY(double outputVolumePeakVU READ getOutputVolumePeakVU NOTIFY outputVolumePeakVU) Q_PROPERTY(double outputVolumePeakVU READ getOutputVolumePeakVU NOTIFY outputVolumePeakVU)
Q_PROPERTY(ConnectionStatus connectionStatus READ getConnectionStatus NOTIFY connectionStatusChanged) Q_PROPERTY(ConnectionStatus connectionStatus READ getConnectionStatus NOTIFY connectionStatusChanged)
Q_PROPERTY(QString receivingCallsignsCom1 READ getReceivingCallsignsCom1 NOTIFY receivingCallsignsChanged) Q_PROPERTY(QString receivingCallsignsCom1 READ getReceivingCallsignsCom1 NOTIFY receivingCallsignsChanged)
Q_PROPERTY(QString receivingCallsignsCom2 READ getReceivingCallsignsCom2 NOTIFY receivingCallsignsChanged) Q_PROPERTY(QString receivingCallsignsCom2 READ getReceivingCallsignsCom2 NOTIFY receivingCallsignsChanged)
public: public:
//! Categories
static const BlackMisc::CLogCategoryList &getLogCategories();
//! Connection status
enum ConnectionStatus { Disconnected, Connected }; enum ConnectionStatus { Disconnected, Connected };
Q_ENUM(ConnectionStatus) Q_ENUM(ConnectionStatus)
@@ -57,13 +62,9 @@ namespace BlackCore
CAfvClient(const QString &apiServer, QObject *parent = nullptr); CAfvClient(const QString &apiServer, QObject *parent = nullptr);
//! Dtor //! Dtor
virtual ~CAfvClient() override virtual ~CAfvClient() override { this->stop(); }
{
this->stop();
}
// void setContextOwnAircraft(const BlackCore::Context::IContextOwnAircraft *contextOwnAircraft);
//! Corresponding callsign
QString callsign() const { return m_callsign; } QString callsign() const { return m_callsign; }
bool isConnected() const { return m_connection->isConnected(); } bool isConnected() const { return m_connection->isConnected(); }
@@ -72,14 +73,23 @@ namespace BlackCore
Q_INVOKABLE void connectTo(const QString &cid, const QString &password, const QString &callsign); Q_INVOKABLE void connectTo(const QString &cid, const QString &password, const QString &callsign);
Q_INVOKABLE void disconnectFrom(); Q_INVOKABLE void disconnectFrom();
//! Audio devices @{
Q_INVOKABLE QStringList availableInputDevices() const; Q_INVOKABLE QStringList availableInputDevices() const;
Q_INVOKABLE QStringList availableOutputDevices() const; Q_INVOKABLE QStringList availableOutputDevices() const;
//! @}
//! Enable/disable VHF simulation, true means effects are NOT used
Q_INVOKABLE void setBypassEffects(bool value); Q_INVOKABLE void setBypassEffects(bool value);
bool isStarted() const { return m_isStarted; } bool isStarted() const { return m_isStarted; }
QDateTime getStartDateTimeUt() const { return m_startDateTimeUtc; } QDateTime getStartDateTimeUt() const { return m_startDateTimeUtc; }
//! Muted @{
bool isMuted() const;
void setMuted(bool mute);
//! @}
bool restartWithNewDevices(const QAudioDeviceInfo &inputDevice, const QAudioDeviceInfo &outputDevice);
void start(const QAudioDeviceInfo &inputDevice, const QAudioDeviceInfo &outputDevice, const QVector<quint16> &transceiverIDs); void start(const QAudioDeviceInfo &inputDevice, const QAudioDeviceInfo &outputDevice, const QVector<quint16> &transceiverIDs);
Q_INVOKABLE void start(const QString &inputDeviceName, const QString &outputDeviceName); Q_INVOKABLE void start(const QString &inputDeviceName, const QString &outputDeviceName);
void stop(); void stop();
@@ -96,29 +106,52 @@ namespace BlackCore
void setPttForCom(bool active, BlackMisc::Audio::PTTCOM com); void setPttForCom(bool active, BlackMisc::Audio::PTTCOM com);
//! @} //! @}
//! Loopback @{
Q_INVOKABLE void setLoopBack(bool on) { m_loopbackOn = on; } Q_INVOKABLE void setLoopBack(bool on) { m_loopbackOn = on; }
Q_INVOKABLE bool isLoopback() const { return m_loopbackOn; }
//! @}
//! Input volume in DB, +-18DB @{ //! Input volume in dB, +-18dB @{
double getInputVolumeDb() const { return m_inputVolumeDb; } double getInputVolumeDb() const { return m_inputVolumeDb; }
Q_INVOKABLE void setInputVolumeDb(double value); Q_INVOKABLE void setInputVolumeDb(double value);
//! @} //! @}
//! Output volume in DB, +-18DB @{ //! Output volume in dB, +-18dB @{
double getOutputVolumeDb() const; double getOutputVolumeDb() const;
Q_INVOKABLE void setOutputVolumeDb(double outputVolume); Q_INVOKABLE void setOutputVolumeDb(double outputVolume);
//! @} //! @}
//! Normalized volumes 0..100 @{
int getNormalizedInputVolume() const;
int getNormalizedOutputVolume() const;
void setNormalizedInputVolume(int volume);
void setNormalizedOutputVolume(int volume);
//! @}
//! VU values, 0..1 @{ //! VU values, 0..1 @{
double getInputVolumePeakVU() const { return m_inputVolumeStream.PeakVU; } double getInputVolumePeakVU() const { return m_inputVolumeStream.PeakVU; }
double getOutputVolumePeakVU() const { return m_outputVolumeStream.PeakVU; } double getOutputVolumePeakVU() const { return m_outputVolumeStream.PeakVU; }
//! @} //! @}
//! Recently used device @{
const QAudioDeviceInfo &getInputDevice() const;
const QAudioDeviceInfo &getOutputDevice() const;
//! @}
signals: signals:
//! Callsigns have been changed
void receivingCallsignsChanged(const Audio::TransceiverReceivingCallsignsChangedArgs &args); void receivingCallsignsChanged(const Audio::TransceiverReceivingCallsignsChangedArgs &args);
//! Connection status has been changed
void connectionStatusChanged(ConnectionStatus status);
//! PTT status in this particular AFV client
void ptt(bool active, BlackMisc::Audio::PTTCOM pttcom, const BlackMisc::CIdentifier &identifier);
//! VU levels @{
void inputVolumePeakVU(double value); void inputVolumePeakVU(double value);
void outputVolumePeakVU(double value); void outputVolumePeakVU(double value);
void connectionStatusChanged(ConnectionStatus status); //! @}
private: private:
void opusDataAvailable(const Audio::OpusDataAvailableArgs &args); void opusDataAvailable(const Audio::OpusDataAvailableArgs &args);
@@ -135,12 +168,13 @@ namespace BlackCore
void updateTransceiversFromContext(const BlackMisc::Simulation::CSimulatedAircraft &aircraft, const BlackMisc::CIdentifier &originator); void updateTransceiversFromContext(const BlackMisc::Simulation::CSimulatedAircraft &aircraft, const BlackMisc::CIdentifier &originator);
static constexpr int SampleRate = 48000; static constexpr int SampleRate = 48000;
static constexpr int FrameSize = 960; // 20ms static constexpr int FrameSize = 960; // 20ms
static constexpr double MinDb = -18.0;
static constexpr double MaxDb = 18.0;
static constexpr quint32 UniCom = 122800000;
// Connection
Connection::CClientConnection *m_connection = nullptr; Connection::CClientConnection *m_connection = nullptr;
BlackMisc::CSetting<BlackMisc::Audio::TSettings> m_audioSettings { this, &CAfvClient::onSettingsChanged };
// Properties
QString m_callsign; QString m_callsign;
Audio::CInput *m_input = nullptr; Audio::CInput *m_input = nullptr;
@@ -152,17 +186,16 @@ namespace BlackCore
bool m_transmit = false; bool m_transmit = false;
bool m_transmitHistory = false; bool m_transmitHistory = false;
QVector<TxTransceiverDto> m_transmittingTransceivers; QVector<TxTransceiverDto> m_transmittingTransceivers;
static const QVector<quint16> &allTransceiverIds() { static const QVector<quint16> transceiverIds{0, 1}; return transceiverIds; }
bool m_isStarted = false; bool m_isStarted = false;
bool m_loopbackOn = false;
QDateTime m_startDateTimeUtc; QDateTime m_startDateTimeUtc;
double m_inputVolumeDb; double m_inputVolumeDb;
double m_outputVolume = 1.0; double m_outputVolume = 1.0;
double m_maxDbReadingInPTTInterval = -100; double m_maxDbReadingInPTTInterval = -100;
bool m_loopbackOn = false;
QTimer m_voiceServerPositionTimer; QTimer m_voiceServerPositionTimer;
QVector<TransceiverDto> m_transceivers; QVector<TransceiverDto> m_transceivers;
QSet<quint16> m_enabledTransceivers; QSet<quint16> m_enabledTransceivers;
@@ -170,11 +203,8 @@ namespace BlackCore
Audio::InputVolumeStreamArgs m_inputVolumeStream; Audio::InputVolumeStreamArgs m_inputVolumeStream;
Audio::OutputVolumeStreamArgs m_outputVolumeStream; Audio::OutputVolumeStreamArgs m_outputVolumeStream;
BlackMisc::CSetting<BlackMisc::Audio::TSettings> m_audioSettings { this, &CAfvClient::onSettingsChanged };
void initWithContext(); void initWithContext();
static bool hasContext(); static bool hasContext();
}; };
} // ns } // ns
} // ns } // ns