From c1b75f7532b45855bf0ea7b0f8d7a6918f540c95 Mon Sep 17 00:00:00 2001 From: Lars Toenning Date: Fri, 3 Sep 2021 00:54:40 +0200 Subject: [PATCH] Issue #100 Seperate COM1/2 output volumes --- .../afv/audio/receiversampleprovider.h | 3 + .../afv/audio/soundcardsampleprovider.cpp | 11 ++ .../afv/audio/soundcardsampleprovider.h | 3 + src/blackcore/afv/clients/afvclient.cpp | 78 +++++--- src/blackcore/afv/clients/afvclient.h | 16 +- src/blackcore/context/contextaudio.cpp | 54 ++++-- src/blackcore/context/contextaudio.h | 7 +- src/blackcore/context/contextownaircraft.h | 3 - .../context/contextownaircraftempty.h | 7 - .../context/contextownaircraftimpl.cpp | 7 - .../context/contextownaircraftimpl.h | 3 - .../context/contextownaircraftproxy.cpp | 5 - .../context/contextownaircraftproxy.h | 1 - .../audiodevicevolumesetupcomponent.cpp | 80 ++++++--- .../audiodevicevolumesetupcomponent.h | 9 +- .../audiodevicevolumesetupcomponent.ui | 68 ++++++- .../components/audiovolumecomponent.cpp | 155 ---------------- .../components/audiovolumecomponent.h | 64 ------- .../components/audiovolumecomponent.ui | 170 ------------------ .../components/mainkeypadareacomponent.cpp | 3 +- .../components/simulatorcomponent.cpp | 2 + src/blackmisc/audio/audiosettings.cpp | 9 +- src/blackmisc/audio/audiosettings.h | 20 ++- src/blackmisc/blackmisc.qrc | 1 + 24 files changed, 270 insertions(+), 509 deletions(-) delete mode 100644 src/blackgui/components/audiovolumecomponent.cpp delete mode 100644 src/blackgui/components/audiovolumecomponent.h delete mode 100644 src/blackgui/components/audiovolumecomponent.ui diff --git a/src/blackcore/afv/audio/receiversampleprovider.h b/src/blackcore/afv/audio/receiversampleprovider.h index cc0de44c7..efca08be4 100644 --- a/src/blackcore/afv/audio/receiversampleprovider.h +++ b/src/blackcore/afv/audio/receiversampleprovider.h @@ -89,6 +89,9 @@ namespace BlackCore //! Get frequency in Hz uint getFrequencyHz() const; + //! Set gain ratio + bool setGainRatio(double gainRatio) { return m_volume->setGainRatio(gainRatio); } + //! Log all inputs //! \private DEBUG only void logVoiceInputs(const QString &prefix = {}, qint64 timeCheckOffsetMs = -1); diff --git a/src/blackcore/afv/audio/soundcardsampleprovider.cpp b/src/blackcore/afv/audio/soundcardsampleprovider.cpp index ce7de3a6e..7789d7455 100644 --- a/src/blackcore/afv/audio/soundcardsampleprovider.cpp +++ b/src/blackcore/afv/audio/soundcardsampleprovider.cpp @@ -187,6 +187,17 @@ namespace BlackCore return m_receiverInputs.at(transceiverID)->getReceivingCallsignsString(); } + bool CSoundcardSampleProvider::setGainRatioForTransceiver(quint16 transceiverID, double gainRatio) + { + auto receiverInput = std::find_if(m_receiverInputs.begin(), m_receiverInputs.end(), + [&](const auto receiver) + { + return receiver->getId() == transceiverID; + }); + if (receiverInput == m_receiverInputs.end()) { return false; } + return (*receiverInput)->setGainRatio(gainRatio); + } + BlackMisc::Aviation::CCallsignSet CSoundcardSampleProvider::getReceivingCallsigns(quint16 transceiverID) const { return m_receiverInputs.at(transceiverID)->getReceivingCallsigns(); diff --git a/src/blackcore/afv/audio/soundcardsampleprovider.h b/src/blackcore/afv/audio/soundcardsampleprovider.h index 3c27a7546..a9064e06c 100644 --- a/src/blackcore/afv/audio/soundcardsampleprovider.h +++ b/src/blackcore/afv/audio/soundcardsampleprovider.h @@ -58,6 +58,9 @@ namespace BlackCore //! Receiving callsign as single string BlackMisc::Aviation::CCallsignSet getReceivingCallsigns(quint16 transceiverID) const; + //! Setting gain for specified receiver + bool setGainRatioForTransceiver(quint16 transceiverID, double gainRatio); + signals: //! Changed callsigns void receivingCallsignsChanged(const TransceiverReceivingCallsignsChangedArgs &args); diff --git a/src/blackcore/afv/clients/afvclient.cpp b/src/blackcore/afv/clients/afvclient.cpp index 8b84c7686..6fd0b878d 100644 --- a/src/blackcore/afv/clients/afvclient.cpp +++ b/src/blackcore/afv/clients/afvclient.cpp @@ -268,15 +268,16 @@ namespace BlackCore bool CAfvClient::isMuted() const { - const int v = this->getNormalizedOutputVolume(); - return v < 1; + const int v1 = this->getNormalizedOutputVolume(CComSystem::Com1); + const int v2 = this->getNormalizedOutputVolume(CComSystem::Com2); + return v1 < 1 && v2 < 1; } void CAfvClient::setMuted(bool mute) { if (this->isMuted() == mute) { return; } - this->setNormalizedOutputVolume(mute ? 0 : 50); - + this->setNormalizedOutputVolume(CComSystem::Com1, mute ? 0 : 50); + this->setNormalizedOutputVolume(CComSystem::Com2, mute ? 0 : 50); emit this->changedMute(mute); } @@ -316,7 +317,6 @@ namespace BlackCore this->initTransceivers(); // threadsafe block - const double outputVolume = this->getOutputGainRatio(); { // lock block 1 { @@ -331,7 +331,7 @@ namespace BlackCore if (m_outputSampleProvider) { m_outputSampleProvider->deleteLater(); } m_outputSampleProvider = new CVolumeSampleProvider(m_soundcardSampleProvider, this); - m_outputSampleProvider->setGainRatio(outputVolume); + //m_outputSampleProvider->setGainRatio(outputVolume); // 2021-09 LT Disabled. Output volume is controlled independently for COM1/2 } // lock block 2 @@ -768,16 +768,26 @@ namespace BlackCore return changed; } - double CAfvClient::getOutputVolumeDb() const + double CAfvClient::getOutputVolumeDb(CComSystem::ComUnit comUnit) const { QMutexLocker lock(&m_mutexVolume); - return m_outputVolumeDb; + if (comUnit == CComSystem::Com1) + return m_outputVolumeDbCom1; + else if (comUnit == CComSystem::Com2) + return m_outputVolumeDbCom2; + qFatal("Invalid COM unit"); + return 0; } - double CAfvClient::getOutputGainRatio() const + double CAfvClient::getOutputGainRatio(CComSystem::ComUnit comUnit) const { QMutexLocker lock(&m_mutexVolume); - return m_outputGainRatio; + if (comUnit == CComSystem::Com1) + return m_outputGainRatioCom1; + else if (comUnit == CComSystem::Com2) + return m_outputGainRatioCom2; + qFatal("Invalid COM unit"); + return 0; } int CAfvClient::getNormalizedInputVolume() const @@ -788,9 +798,9 @@ namespace BlackCore return i; } - int CAfvClient::getNormalizedOutputVolume() const + int CAfvClient::getNormalizedOutputVolume(CComSystem::ComUnit comUnit) const { - double db = this->getOutputVolumeDb(); + double db = this->getOutputVolumeDb(comUnit); double range = MaxDbOut; int v = 50; if (db < 0) @@ -814,7 +824,7 @@ namespace BlackCore return this->setInputVolumeDb(dB); } - void CAfvClient::setNormalizedOutputVolume(int volume) + void CAfvClient::setNormalizedOutputVolume(CComSystem::ComUnit comUnit, int volume) { if (volume < 0) { volume = 0; } else if (volume > 100) { volume = 100; } @@ -834,7 +844,7 @@ namespace BlackCore dB += (volume * range / 50.0); // converted to MinDbOut-MaxDbOut - this->setOutputVolumeDb(dB); + this->setOutputVolumeDb(comUnit, dB); } double CAfvClient::getInputVolumePeakVU() const @@ -1089,10 +1099,12 @@ namespace BlackCore { const CSettings audioSettings = m_audioSettings.get(); const int iv = audioSettings.getInVolume(); - const int ov = audioSettings.getOutVolume(); + const int ov1 = audioSettings.getOutVolumeCom1(); + const int ov2 = audioSettings.getOutVolumeCom2(); this->setNormalizedInputVolume(iv); - this->setNormalizedOutputVolume(ov); + this->setNormalizedOutputVolume(CComSystem::Com1, ov1); + this->setNormalizedOutputVolume(CComSystem::Com2, ov2); this->setBypassEffects(!audioSettings.isAudioEffectsEnabled()); } @@ -1145,6 +1157,12 @@ namespace BlackCore const bool tx2 = com2.isTransmitEnabled(); // we only allow one (1) transmit const bool rx2 = com2.isReceiveEnabled(); + const int vol1 = com1.getVolumeReceive(); + const int vol2 = com2.getVolumeReceive(); + + this->setNormalizedOutputVolume(CComSystem::Com1, vol1); + this->setNormalizedOutputVolume(CComSystem::Com2, vol2); + // enable, we currently treat receive as enable // flight sim cockpits normally use rx and tx // AFV uses tx and enable @@ -1397,7 +1415,7 @@ namespace BlackCore return sApp && !sApp->isShuttingDown() && sApp->getIContextOwnAircraft() && sApp->getIContextNetwork() && sApp->getIContextSimulator(); } - bool CAfvClient::setOutputVolumeDb(double valueDb) + bool CAfvClient::setOutputVolumeDb(CComSystem::ComUnit comUnit, double valueDb) { if (!CThreadUtils::isInThisThread(this)) { @@ -1406,11 +1424,11 @@ namespace BlackCore QTimer::singleShot(0, this, [ = ] { if (!myself || !CAfvClient::hasContexts()) { return; } - myself->setOutputVolumeDb(valueDb); + myself->setOutputVolumeDb(comUnit, valueDb); }); return true; // not exactly "true" as we do it async } - + if (comUnit != CComSystem::Com1 && comUnit != CComSystem::Com2) { return false; } if (valueDb > MaxDbOut) { valueDb = MaxDbOut; } else if (valueDb < MinDbOut) { valueDb = MinDbOut; } @@ -1418,11 +1436,23 @@ namespace BlackCore bool changed = false; { QMutexLocker lock(&m_mutexVolume); - changed = !qFuzzyCompare(m_outputVolumeDb, valueDb); - if (changed) + if (comUnit == CComSystem::Com1) { - m_outputVolumeDb = valueDb; - m_outputGainRatio = gainRatio; + changed = !qFuzzyCompare(m_outputVolumeDbCom1, valueDb); + if (changed) + { + m_outputVolumeDbCom1 = valueDb; + m_outputGainRatioCom1 = gainRatio; + } + } + else + { + changed = !qFuzzyCompare(m_outputVolumeDbCom2, valueDb); + if (changed) + { + m_outputVolumeDbCom2 = valueDb; + m_outputGainRatioCom2 = gainRatio; + } } } @@ -1436,7 +1466,7 @@ namespace BlackCore if (m_outputSampleProvider) { - changed = m_outputSampleProvider->setGainRatio(gainRatio); + changed = m_soundcardSampleProvider->setGainRatioForTransceiver(comUnit, gainRatio); } m_mutexSampleProviders.unlock(); return changed; diff --git a/src/blackcore/afv/clients/afvclient.h b/src/blackcore/afv/clients/afvclient.h index 51a75d219..684eebd34 100644 --- a/src/blackcore/afv/clients/afvclient.h +++ b/src/blackcore/afv/clients/afvclient.h @@ -237,21 +237,21 @@ namespace BlackCore //! Output volume in dB, [MinDbOut, MaxDbOut]dB //! \threadsafe //! @{ - double getOutputVolumeDb() const; - Q_INVOKABLE bool setOutputVolumeDb(double valueDb); + double getOutputVolumeDb(BlackMisc::Aviation::CComSystem::ComUnit comUnit) const; + Q_INVOKABLE bool setOutputVolumeDb(BlackMisc::Aviation::CComSystem::ComUnit comUnit, double valueDb); //! @} //! Gain ratio //! \threadsafe - double getOutputGainRatio() const; + double getOutputGainRatio(BlackMisc::Aviation::CComSystem::ComUnit comUnit) const; //! Normalized volumes 0..100 //! \threadsafe //! @{ int getNormalizedInputVolume() const; - int getNormalizedOutputVolume() const; + int getNormalizedOutputVolume(BlackMisc::Aviation::CComSystem::ComUnit comUnit) const; bool setNormalizedInputVolume(int volume); - void setNormalizedOutputVolume(int volume); + void setNormalizedOutputVolume(BlackMisc::Aviation::CComSystem::ComUnit comUnit, int volume); //! @} //! VU values, 0..1 @@ -412,8 +412,10 @@ namespace BlackCore QDateTime m_startDateTimeUtc; double m_inputVolumeDb = 0.0; - double m_outputVolumeDb = 0.0; - double m_outputGainRatio = 1.0; //!< 0dB + double m_outputVolumeDbCom1 = 0.0; + double m_outputGainRatioCom1 = 1.0; //!< 0dB + double m_outputVolumeDbCom2 = 0.0; + double m_outputGainRatioCom2 = 1.0; //!< 0dB double m_maxDbReadingInPTTInterval = -100; QTimer *m_voiceServerTimer = nullptr; diff --git a/src/blackcore/context/contextaudio.cpp b/src/blackcore/context/contextaudio.cpp index 6bcea3222..803233ad2 100644 --- a/src/blackcore/context/contextaudio.cpp +++ b/src/blackcore/context/contextaudio.cpp @@ -110,7 +110,8 @@ namespace BlackCore else if (parser.commandStartsWith("vol") && parser.countParts() > 1) { const int v = parser.toInt(1); - this->setVoiceOutputVolume(v); + this->setVoiceOutputVolume(CComSystem::Com1, v); + this->setVoiceOutputVolume(CComSystem::Com2, v); return true; } else if (afvClient() && parser.matchesCommand(".aliased") && parser.countParts() > 1) @@ -148,7 +149,8 @@ namespace BlackCore if (!myself || !sApp || sApp->isShuttingDown()) { return; } const CSettings as = m_audioSettings.getThreadLocal(); - this->setVoiceOutputVolume(as.getOutVolume()); + this->setVoiceOutputVolume(CComSystem::Com1, as.getOutVolumeCom1()); + this->setVoiceOutputVolume(CComSystem::Com2, as.getOutVolumeCom2()); m_selcalPlayer = new CSelcalPlayer(CAudioDeviceInfo::getDefaultOutputDevice(), this); myself->changeDeviceSettings(); @@ -419,20 +421,22 @@ namespace BlackCore m_voiceClient->startAudio(inputDevice, outputDevice); } - void CContextAudioBase::setVoiceOutputVolume(int volume) + void CContextAudioBase::setVoiceOutputVolume(CComSystem::ComUnit comUnit, int volume) { + if (comUnit != CComSystem::Com1 && comUnit != CComSystem::Com2) { return; } if (!m_voiceClient) { return; } const bool wasMuted = this->isMuted(); volume = CSettings::fixOutVolume(volume); - const int currentVolume = m_voiceClient->getNormalizedOutputVolume(); + const int currentVolume = m_voiceClient->getNormalizedOutputVolume(comUnit); const bool changedVoiceOutput = (currentVolume != volume); if (changedVoiceOutput) { // TODO: KB 2020-05 the mute handling should entirely go to AFV client! - m_voiceClient->setNormalizedOutputVolume(volume); - m_outVolumeBeforeMute = volume; + m_voiceClient->setNormalizedOutputVolume(comUnit, volume); + if (comUnit == CComSystem::Com1) { m_outVolumeBeforeMuteCom1 = volume; } + if (comUnit == CComSystem::Com2) { m_outVolumeBeforeMuteCom2 = volume; } emit this->changedAudioVolume(volume); if ((volume > 0 && wasMuted) || (volume < 1 && !wasMuted)) @@ -443,17 +447,22 @@ namespace BlackCore } CSettings as(m_audioSettings.getThreadLocal()); - if (as.getOutVolume() != volume) + if (comUnit == CComSystem::Com1 && as.getOutVolumeCom1() != volume) { - as.setOutVolume(volume); + as.setOutVolumeCom1(volume); + m_audioSettings.set(as); + } + else if (comUnit == CComSystem::Com2 && as.getOutVolumeCom2() != volume) + { + as.setOutVolumeCom2(volume); m_audioSettings.set(as); } } - int CContextAudioBase::getVoiceOutputVolume() const + int CContextAudioBase::getVoiceOutputVolume(CComSystem::ComUnit comUnit) const { if (!m_voiceClient) { return 0; } - return m_voiceClient->getNormalizedOutputVolume(); + return m_voiceClient->getNormalizedOutputVolume(comUnit); } void CContextAudioBase::setMute(bool muted) @@ -463,12 +472,16 @@ namespace BlackCore if (muted) { - const int nv = m_voiceClient->getNormalizedOutputVolume(); - m_outVolumeBeforeMute = nv; + m_outVolumeBeforeMuteCom1 = m_voiceClient->getNormalizedOutputVolume(CComSystem::Com1); + m_outVolumeBeforeMuteCom2 = m_voiceClient->getNormalizedOutputVolume(CComSystem::Com2); } m_voiceClient->setMuted(muted); - if (!muted) { m_voiceClient->setNormalizedOutputVolume(m_outVolumeBeforeMute); } + if (!muted) + { + m_voiceClient->setNormalizedOutputVolume(CComSystem::Com1, m_outVolumeBeforeMuteCom1); + m_voiceClient->setNormalizedOutputVolume(CComSystem::Com2, m_outVolumeBeforeMuteCom2); + } // signal no longer need, signaled by m_voiceClient->setMuted // emit this->changedMute(muted); @@ -581,7 +594,8 @@ namespace BlackCore const CSettings s = m_audioSettings.get(); const QString dir = s.getNotificationSoundDirectory(); m_notificationPlayer.updateDirectory(dir); - this->setVoiceOutputVolume(s.getOutVolume()); + this->setVoiceOutputVolume(CComSystem::Com1, s.getOutVolumeCom1()); + this->setVoiceOutputVolume(CComSystem::Com2, s.getOutVolumeCom2()); } void CContextAudioBase::onChangedVoiceSettings() @@ -593,15 +607,19 @@ namespace BlackCore void CContextAudioBase::audioIncreaseVolume(bool enabled) { if (!enabled) { return; } - const int v = qRound(this->getVoiceOutputVolume() * 1.05); - this->setVoiceOutputVolume(v); + const int v1 = qRound(this->getVoiceOutputVolume(CComSystem::Com1) * 1.05); + const int v2 = qRound(this->getVoiceOutputVolume(CComSystem::Com2) * 1.05); + this->setVoiceOutputVolume(CComSystem::Com1, v1); + this->setVoiceOutputVolume(CComSystem::Com2, v2); } void CContextAudioBase::audioDecreaseVolume(bool enabled) { if (!enabled) { return; } - const int v = qRound(this->getVoiceOutputVolume() / 1.05); - this->setVoiceOutputVolume(v); + const int v1 = qRound(this->getVoiceOutputVolume(CComSystem::Com1) / 1.05); + const int v2 = qRound(this->getVoiceOutputVolume(CComSystem::Com2) / 1.05); + this->setVoiceOutputVolume(CComSystem::Com1, v1); + this->setVoiceOutputVolume(CComSystem::Com2, v2); } void CContextAudioBase::xCtxNetworkConnectionStatusChanged(const CConnectionStatus &from, const CConnectionStatus &to) diff --git a/src/blackcore/context/contextaudio.h b/src/blackcore/context/contextaudio.h index cef196ad5..218f5c9cd 100644 --- a/src/blackcore/context/contextaudio.h +++ b/src/blackcore/context/contextaudio.h @@ -178,8 +178,8 @@ namespace BlackCore //! Volume //! @{ - void setVoiceOutputVolume(int volume); - int getVoiceOutputVolume() const; + void setVoiceOutputVolume(BlackMisc::Aviation::CComSystem::ComUnit comUnit, int volume); + int getVoiceOutputVolume(BlackMisc::Aviation::CComSystem::ComUnit comUnit) const; void setMute(bool muted); bool isMuted() const; //! @} @@ -354,7 +354,8 @@ namespace BlackCore CActionBind m_actionAudioVolumeIncrease { BlackMisc::Input::audioVolumeIncreaseHotkeyAction(), BlackMisc::Input::audioVolumeIncreaseHotkeyIcon(), this, &CContextAudioBase::audioIncreaseVolume }; CActionBind m_actionAudioVolumeDecrease { BlackMisc::Input::audioVolumeDecreaseHotkeyAction(), BlackMisc::Input::audioVolumeDecreaseHotkeyIcon(), this, &CContextAudioBase::audioDecreaseVolume }; - int m_outVolumeBeforeMute = 90; + int m_outVolumeBeforeMuteCom1 = 90; + int m_outVolumeBeforeMuteCom2 = 90; static constexpr int MinUnmuteVolume = 20; //!< minimum volume when unmuted //! Do we use a local core diff --git a/src/blackcore/context/contextownaircraft.h b/src/blackcore/context/contextownaircraft.h index 1d5e65e25..b3cd5c366 100644 --- a/src/blackcore/context/contextownaircraft.h +++ b/src/blackcore/context/contextownaircraft.h @@ -156,9 +156,6 @@ namespace BlackCore //! Own SELCAL code virtual bool updateSelcal(const BlackMisc::Aviation::CSelcal &selcal, const BlackMisc::CIdentifier &originator) = 0; - //! Output volume 0..300 - virtual void setAudioOutputVolume(int outputVolume) = 0; - //! Default situation //! \remark normally used when no driver is attached static const BlackMisc::Aviation::CAircraftSituation &getDefaultSituation(); diff --git a/src/blackcore/context/contextownaircraftempty.h b/src/blackcore/context/contextownaircraftempty.h index e925543f5..8cbf26873 100644 --- a/src/blackcore/context/contextownaircraftempty.h +++ b/src/blackcore/context/contextownaircraftempty.h @@ -134,13 +134,6 @@ namespace BlackCore return false; } - //! \copydoc IContextOwnAircraft::setAudioOutputVolume - virtual void setAudioOutputVolume(int outputVolume) override - { - Q_UNUSED(outputVolume); - logEmptyContextWarning(Q_FUNC_INFO); - } - //! \copydoc IContextOwnAircraft::toggleTransponderMode virtual void toggleTransponderMode() override { diff --git a/src/blackcore/context/contextownaircraftimpl.cpp b/src/blackcore/context/contextownaircraftimpl.cpp index 0cc50f9b7..ed472f3ee 100644 --- a/src/blackcore/context/contextownaircraftimpl.cpp +++ b/src/blackcore/context/contextownaircraftimpl.cpp @@ -474,13 +474,6 @@ namespace BlackCore return true; } - void CContextOwnAircraft::setAudioOutputVolume(int outputVolume) - { - if (m_debugEnabled) { CLogMessage(this, CLogCategories::contextSlot()).debug() << Q_FUNC_INFO << outputVolume; } - CContextAudioBase *audio = qobject_cast(this->getIContextAudio()); - if (audio) { audio->setVoiceOutputVolume(outputVolume); } - } - void CContextOwnAircraft::xCtxChangedAtcStationOnlineConnectionStatus(const CAtcStation &atcStation, bool connected) { Q_UNUSED(connected) diff --git a/src/blackcore/context/contextownaircraftimpl.h b/src/blackcore/context/contextownaircraftimpl.h index 45cdb4edf..2812a71bb 100644 --- a/src/blackcore/context/contextownaircraftimpl.h +++ b/src/blackcore/context/contextownaircraftimpl.h @@ -176,9 +176,6 @@ namespace BlackCore //! \copydoc IContextOwnAircraft::setTransponderMode virtual bool setTransponderMode(BlackMisc::Aviation::CTransponder::TransponderMode mode) override; - //! \copydoc IContextOwnAircraft::setAudioOutputVolume - virtual void setAudioOutputVolume(int outputVolume) override; - //! \addtogroup swiftdotcommands //! @{ //!
diff --git a/src/blackcore/context/contextownaircraftproxy.cpp b/src/blackcore/context/contextownaircraftproxy.cpp
index b45e62bab..6c0448792 100644
--- a/src/blackcore/context/contextownaircraftproxy.cpp
+++ b/src/blackcore/context/contextownaircraftproxy.cpp
@@ -132,11 +132,6 @@ namespace BlackCore
             return m_dBusInterface->callDBusRet(QLatin1String("updateOwnIcaoCodes"), aircraftIcaoCode, airlineIcaoCode);
         }
 
-        void CContextOwnAircraftProxy::setAudioOutputVolume(int outputVolume)
-        {
-            m_dBusInterface->callDBus(QLatin1String("setAudioOutputVolume"), outputVolume);
-        }
-
         void CContextOwnAircraftProxy::toggleTransponderMode()
         {
             m_dBusInterface->callDBus(QLatin1String("toggleTransponderMode"));
diff --git a/src/blackcore/context/contextownaircraftproxy.h b/src/blackcore/context/contextownaircraftproxy.h
index e783727f3..ee0375b8d 100644
--- a/src/blackcore/context/contextownaircraftproxy.h
+++ b/src/blackcore/context/contextownaircraftproxy.h
@@ -76,7 +76,6 @@ namespace BlackCore
             virtual bool updateSelcal(const BlackMisc::Aviation::CSelcal &selcal, const BlackMisc::CIdentifier &originator) override;
             virtual bool updateOwnCallsign(const BlackMisc::Aviation::CCallsign &callsign) override;
             virtual bool updateOwnIcaoCodes(const BlackMisc::Aviation::CAircraftIcaoCode &aircraftIcaoCode, const BlackMisc::Aviation::CAirlineIcaoCode &airlineIcaoCode) override;
-            virtual void setAudioOutputVolume(int outputVolume) override;
             virtual void toggleTransponderMode() override;
             virtual bool setTransponderMode(BlackMisc::Aviation::CTransponder::TransponderMode mode) override;
             virtual bool parseCommandLine(const QString &commandLine, const BlackMisc::CIdentifier &originator) override;
diff --git a/src/blackgui/components/audiodevicevolumesetupcomponent.cpp b/src/blackgui/components/audiodevicevolumesetupcomponent.cpp
index 18b7504c3..cb82e3a76 100644
--- a/src/blackgui/components/audiodevicevolumesetupcomponent.cpp
+++ b/src/blackgui/components/audiodevicevolumesetupcomponent.cpp
@@ -47,12 +47,14 @@ namespace BlackGui
             ui(new Ui::CAudioDeviceVolumeSetupComponent)
         {
             ui->setupUi(this);
-            connect(ui->hs_VolumeIn,         &QSlider::valueChanged, this, &CAudioDeviceVolumeSetupComponent::onVolumeSliderChanged);
-            connect(ui->hs_VolumeOut,        &QSlider::valueChanged, this, &CAudioDeviceVolumeSetupComponent::onVolumeSliderChanged);
-            connect(ui->tb_RefreshInDevice,  &QToolButton::released, this, &CAudioDeviceVolumeSetupComponent::onReloadDevices,  Qt::QueuedConnection);
-            connect(ui->tb_RefreshOutDevice, &QToolButton::released, this, &CAudioDeviceVolumeSetupComponent::onReloadDevices,  Qt::QueuedConnection);
-            connect(ui->tb_ResetInVolume,    &QToolButton::released, this, &CAudioDeviceVolumeSetupComponent::onResetVolumeIn,  Qt::QueuedConnection);
-            connect(ui->tb_ResetOutVolume,   &QToolButton::released, this, &CAudioDeviceVolumeSetupComponent::onResetVolumeOut, Qt::QueuedConnection);
+            connect(ui->hs_VolumeIn,             &QSlider::valueChanged, this, &CAudioDeviceVolumeSetupComponent::onVolumeSliderChanged);
+            connect(ui->hs_VolumeOutCom1,        &QSlider::valueChanged, this, &CAudioDeviceVolumeSetupComponent::onVolumeSliderChanged);
+            connect(ui->hs_VolumeOutCom2,        &QSlider::valueChanged, this, &CAudioDeviceVolumeSetupComponent::onVolumeSliderChanged);
+            connect(ui->tb_RefreshInDevice,      &QToolButton::released, this, &CAudioDeviceVolumeSetupComponent::onReloadDevices,  Qt::QueuedConnection);
+            connect(ui->tb_RefreshOutDevice,     &QToolButton::released, this, &CAudioDeviceVolumeSetupComponent::onReloadDevices,  Qt::QueuedConnection);
+            connect(ui->tb_ResetInVolume,        &QToolButton::released, this, &CAudioDeviceVolumeSetupComponent::onResetVolumeIn,  Qt::QueuedConnection);
+            connect(ui->tb_ResetOutVolumeCom1,   &QToolButton::released, this, &CAudioDeviceVolumeSetupComponent::onResetVolumeOutCom1, Qt::QueuedConnection);
+            connect(ui->tb_ResetOutVolumeCom2,   &QToolButton::released, this, &CAudioDeviceVolumeSetupComponent::onResetVolumeOutCom2, Qt::QueuedConnection);
 
             connect(ui->cb_1Tx,  &QCheckBox::toggled, this, &CAudioDeviceVolumeSetupComponent::onRxTxChanged, Qt::QueuedConnection);
             connect(ui->cb_2Tx,  &QCheckBox::toggled, this, &CAudioDeviceVolumeSetupComponent::onRxTxChanged, Qt::QueuedConnection);
@@ -62,14 +64,18 @@ namespace BlackGui
 
             ui->hs_VolumeIn->setMaximum(CSettings::InMax);
             ui->hs_VolumeIn->setMinimum(CSettings::InMin);
-            ui->hs_VolumeOut->setMaximum(CSettings::OutMax);
-            ui->hs_VolumeOut->setMinimum(CSettings::OutMin);
+            ui->hs_VolumeOutCom1->setMaximum(CSettings::OutMax);
+            ui->hs_VolumeOutCom1->setMinimum(CSettings::OutMin);
+            ui->hs_VolumeOutCom2->setMaximum(CSettings::OutMax);
+            ui->hs_VolumeOutCom2->setMinimum(CSettings::OutMin);
 
             const CSettings as(m_audioSettings.getThreadLocal());
             const int i = this->getInValue();
-            const int o = this->getOutValue();
+            const int o1 = this->getOutValueCom1();
+            const int o2 = this->getOutValueCom2();
             ui->hs_VolumeIn->setValue(i);
-            ui->hs_VolumeOut->setValue(o);
+            ui->hs_VolumeOutCom1->setValue(o1);
+            ui->hs_VolumeOutCom2->setValue(o2);
             ui->cb_SetupAudioLoopback->setChecked(false);
             ui->cb_DisableAudioEffects->setChecked(!as.isAudioEffectsEnabled());
 
@@ -183,11 +189,18 @@ namespace BlackGui
             return qRound(ui->hs_VolumeIn->value() / r * tr);
         }
 
-        int CAudioDeviceVolumeSetupComponent::getOutValue(int from, int to) const
+        int CAudioDeviceVolumeSetupComponent::getOutValueCom1(int from, int to) const
         {
-            const double r  = ui->hs_VolumeOut->maximum() - ui->hs_VolumeOut->minimum();
+            const double r  = ui->hs_VolumeOutCom1->maximum() - ui->hs_VolumeOutCom1->minimum();
             const double tr = to - from;
-            return qRound(ui->hs_VolumeOut->value() / r * tr);
+            return qRound(ui->hs_VolumeOutCom1->value() / r * tr);
+        }
+
+        int CAudioDeviceVolumeSetupComponent::getOutValueCom2(int from, int to) const
+        {
+            const double r  = ui->hs_VolumeOutCom2->maximum() - ui->hs_VolumeOutCom2->minimum();
+            const double tr = to - from;
+            return qRound(ui->hs_VolumeOutCom2->value() / r * tr);
         }
 
         void CAudioDeviceVolumeSetupComponent::setInValue(int value, int from, int to)
@@ -199,13 +212,22 @@ namespace BlackGui
             ui->hs_VolumeIn->setValue(qRound(value / tr * r));
         }
 
-        void CAudioDeviceVolumeSetupComponent::setOutValue(int value, int from, int to)
+        void CAudioDeviceVolumeSetupComponent::setOutValueCom1(int value, int from, int to)
         {
             if (value > to) { value = to; }
             else if (value < from) { value = from; }
-            const double r = ui->hs_VolumeOut->maximum() - ui->hs_VolumeOut->minimum();
+            const double r = ui->hs_VolumeOutCom1->maximum() - ui->hs_VolumeOutCom1->minimum();
             const double tr = to - from;
-            ui->hs_VolumeOut->setValue(qRound(value / tr * r));
+            ui->hs_VolumeOutCom1->setValue(qRound(value / tr * r));
+        }
+
+        void CAudioDeviceVolumeSetupComponent::setOutValueCom2(int value, int from, int to)
+        {
+            if (value > to) { value = to; }
+            else if (value < from) { value = from; }
+            const double r = ui->hs_VolumeOutCom2->maximum() - ui->hs_VolumeOutCom2->minimum();
+            const double tr = to - from;
+            ui->hs_VolumeOutCom2->setValue(qRound(value / tr * r));
         }
 
         void CAudioDeviceVolumeSetupComponent::setInLevel(double value)
@@ -258,6 +280,12 @@ namespace BlackGui
 
             const bool integrated = this->isComIntegrated();
             this->setTransmitReceiveInUi(com1Tx, com1Rx, com2Tx, com2Rx, integrated);
+
+            // Set transmit volume in GUI
+            const int vol1 = sGui->getCContextAudioBase()->getVoiceOutputVolume(CComSystem::Com1);
+            const int vol2 = sGui->getCContextAudioBase()->getVoiceOutputVolume(CComSystem::Com2);
+            ui->hs_VolumeOutCom1->setValue(vol1);
+            ui->hs_VolumeOutCom2->setValue(vol2);
         }
 
         void CAudioDeviceVolumeSetupComponent::setCheckBoxesReadOnly(bool readonly)
@@ -280,7 +308,8 @@ namespace BlackGui
             const CSettings as(m_audioSettings.getThreadLocal());
             ui->cb_DisableAudioEffects->setChecked(!as.isAudioEffectsEnabled());
             this->setInValue(as.getInVolume());
-            this->setOutValue(as.getOutVolume());
+            this->setOutValueCom1(as.getOutVolumeCom1());
+            this->setOutValueCom2(as.getOutVolumeCom2());
         }
 
         void CAudioDeviceVolumeSetupComponent::initAudioDeviceLists()
@@ -312,10 +341,12 @@ namespace BlackGui
         {
             CSettings as(m_audioSettings.getThreadLocal());
             const int i = this->getInValue();
-            const int o = this->getOutValue();
-            if (as.getInVolume() == i && as.getOutVolume() == o) { return; }
+            const int o1 = this->getOutValueCom1();
+            const int o2 = this->getOutValueCom2();
+            if (as.getInVolume() == i && as.getOutVolumeCom1() == o1 && as.getOutVolumeCom2() == o2) { return; }
             as.setInVolume(i);
-            as.setOutVolume(o);
+            as.setOutVolumeCom1(o1);
+            as.setOutVolumeCom2(o2);
             m_audioSettings.setAndSave(as);
         }
 
@@ -343,9 +374,14 @@ namespace BlackGui
             ui->hs_VolumeIn->setValue((ui->hs_VolumeIn->maximum() - ui->hs_VolumeIn->minimum()) / 2);
         }
 
-        void CAudioDeviceVolumeSetupComponent::onResetVolumeOut()
+        void CAudioDeviceVolumeSetupComponent::onResetVolumeOutCom1()
         {
-            ui->hs_VolumeOut->setValue((ui->hs_VolumeOut->maximum() - ui->hs_VolumeOut->minimum()) / 2);
+            ui->hs_VolumeOutCom1->setValue((ui->hs_VolumeOutCom1->maximum() - ui->hs_VolumeOutCom1->minimum()) / 2);
+        }
+
+        void CAudioDeviceVolumeSetupComponent::onResetVolumeOutCom2()
+        {
+            ui->hs_VolumeOutCom2->setValue((ui->hs_VolumeOutCom2->maximum() - ui->hs_VolumeOutCom2->minimum()) / 2);
         }
 
         void CAudioDeviceVolumeSetupComponent::setAudioRunsWhere()
diff --git a/src/blackgui/components/audiodevicevolumesetupcomponent.h b/src/blackgui/components/audiodevicevolumesetupcomponent.h
index 25d450322..eab00b938 100644
--- a/src/blackgui/components/audiodevicevolumesetupcomponent.h
+++ b/src/blackgui/components/audiodevicevolumesetupcomponent.h
@@ -45,13 +45,15 @@ namespace BlackGui
             //! Get input and output volume values
             //! @{
             int getInValue(int from  = BlackMisc::Audio::CSettings::InMin,  int to = BlackMisc::Audio::CSettings::InMax) const;
-            int getOutValue(int from = BlackMisc::Audio::CSettings::OutMin, int to = BlackMisc::Audio::CSettings::OutMax) const;
+            int getOutValueCom1(int from = BlackMisc::Audio::CSettings::OutMin, int to = BlackMisc::Audio::CSettings::OutMax) const;
+            int getOutValueCom2(int from = BlackMisc::Audio::CSettings::OutMin, int to = BlackMisc::Audio::CSettings::OutMax) const;
             //! @}
 
             //! Set input and output volume values
             //! @{
             void setInValue(int value,  int from = BlackMisc::Audio::CSettings::InMin,  int to = BlackMisc::Audio::CSettings::InMax);
-            void setOutValue(int value, int from = BlackMisc::Audio::CSettings::OutMin, int to = BlackMisc::Audio::CSettings::OutMax);
+            void setOutValueCom1(int value, int from = BlackMisc::Audio::CSettings::OutMin, int to = BlackMisc::Audio::CSettings::OutMax);
+            void setOutValueCom2(int value, int from = BlackMisc::Audio::CSettings::OutMin, int to = BlackMisc::Audio::CSettings::OutMax);
             //! @}
 
             //! Set input and output level values 0..1
@@ -112,7 +114,8 @@ namespace BlackGui
 
             void onReloadDevices();
             void onResetVolumeIn();
-            void onResetVolumeOut();
+            void onResetVolumeOutCom1();
+            void onResetVolumeOutCom2();
 
             void setAudioRunsWhere();
 
diff --git a/src/blackgui/components/audiodevicevolumesetupcomponent.ui b/src/blackgui/components/audiodevicevolumesetupcomponent.ui
index d136ee1b0..f89ae620c 100644
--- a/src/blackgui/components/audiodevicevolumesetupcomponent.ui
+++ b/src/blackgui/components/audiodevicevolumesetupcomponent.ui
@@ -26,11 +26,15 @@
    
     4
    
-   
+   
     
      
       ...
      
+      
+        
+          :/pastel/icons/pastel/16/undo.png:/pastel/icons/pastel/16/undo.png
+      
     
    
    
@@ -120,17 +124,39 @@
      
     
    
-   
-    
+   
+    
      
       ...
      
+      
+        
+          :/pastel/icons/pastel/16/undo.png:/pastel/icons/pastel/16/undo.png
+      
+    
+   
+   
+    
+     
+      ...
+     
+     
+      
+        :/pastel/icons/pastel/16/undo.png:/pastel/icons/pastel/16/undo.png
+      
     
    
    
-    
+    
      
-      Out
+      Out COM1
+     
+    
+   
+  
+    
+     
+      Out COM2
      
     
    
@@ -277,7 +303,7 @@
     
    
    
-    
+    
      
       50
      
@@ -287,6 +313,23 @@
     
    
    
+    
+     
+      50
+     
+     
+      Qt::Horizontal
+     
+    
+   
+  
+    
+     
+      Output
+     
+    
+   
+   
     
      
       
@@ -296,6 +339,13 @@
      
     
    
+  
+    
+     
+      Input
+     
+    
+  
    
     
      
@@ -344,8 +394,10 @@
   cb_SetupAudioLoopback
   hs_VolumeIn
   tb_ResetInVolume
-  hs_VolumeOut
-  tb_ResetOutVolume
+  hs_VolumeOutCom1
+  tb_ResetOutVolumeCom1
+  hs_VolumeOutCom2
+  tb_ResetOutVolumeCom2
  
  
   
diff --git a/src/blackgui/components/audiovolumecomponent.cpp b/src/blackgui/components/audiovolumecomponent.cpp
deleted file mode 100644
index 488bc961a..000000000
--- a/src/blackgui/components/audiovolumecomponent.cpp
+++ /dev/null
@@ -1,155 +0,0 @@
-/* Copyright (C) 2013
- * swift project Community / Contributors
- *
- * This file is part of swift Project. It is subject to the license terms in the LICENSE file found in the top-level
- * directory of this distribution. No part of swift project, including this file, may be copied, modified, propagated,
- * or distributed except according to the terms contained in the LICENSE file.
- */
-
-#include "audiovolumecomponent.h"
-#include "blackcore/context/contextaudio.h"
-#include "blackgui/components/audiovolumecomponent.h"
-#include "blackgui/guiapplication.h"
-#include "blackmisc/audio/audioutils.h"
-#include "ui_audiovolumecomponent.h"
-
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-
-using namespace BlackMisc;
-using namespace BlackMisc::Audio;
-using namespace BlackCore;
-using namespace BlackCore::Context;
-
-namespace BlackGui
-{
-    namespace Components
-    {
-        CAudioVolumeComponent::CAudioVolumeComponent(QWidget *parent) :
-            QFrame(parent),
-            ui(new Ui::CAudioVolumeComponent)
-        {
-            ui->setupUi(this);
-            const int volume = sGui && sGui->getIContextAudio() ?
-                               sGui->getCContextAudioBase()->getVoiceOutputVolume() :
-                               100;
-            ui->hs_Volume->setValue(volumeToSliderValue(volume));
-            ui->sb_Volume->setValue(volume);
-
-            bool c = connect(ui->pb_ShowWinMixer, &QPushButton::pressed, this, &CAudioVolumeComponent::onWindowsMixerRequested);
-            Q_ASSERT(c);
-            Q_UNUSED(c)
-            c = connect(ui->hs_Volume, &QSlider::valueChanged, this, &CAudioVolumeComponent::changeOutputVolumeFromSlider);
-            Q_ASSERT(c);
-            Q_UNUSED(c)
-            c = connect(ui->sb_Volume, qOverload(&QSpinBox::valueChanged), this, &CAudioVolumeComponent::changeOutputVolumeFromSpinBox);
-            Q_ASSERT(c);
-            Q_UNUSED(c)
-            c = connect(ui->pb_Volume100, &QPushButton::clicked, this, &CAudioVolumeComponent::setVolume100);
-            Q_ASSERT(c);
-            Q_UNUSED(c)
-
-            c = connect(sGui->getCContextAudioBase(), &CContextAudioBase::changedMute, this, &CAudioVolumeComponent::onMuteChanged);
-            Q_ASSERT(c);
-            Q_UNUSED(c)
-            connect(sGui->getCContextAudioBase(), &CContextAudioBase::changedAudioVolume, this, &CAudioVolumeComponent::onOutputVolumeChanged);
-            Q_ASSERT(c);
-            Q_UNUSED(c)
-
-            // to audio audio context
-            c = connect(ui->pb_Mute, &QPushButton::toggled, sGui->getCContextAudioBase(), &CContextAudioBase::setMute);
-            Q_ASSERT(c);
-            Q_UNUSED(c)
-
-            if (sGui->getIContextAudio()->isUsingImplementingObject())
-            {
-                ui->lbl_ContextLocation->setText("local");
-            }
-            else
-            {
-                ui->lbl_ContextLocation->setText("remote");
-            }
-
-            // init volume
-            this->changeOutputVolumeFromSpinBox(volume); // init volume
-        }
-
-        CAudioVolumeComponent::~CAudioVolumeComponent()
-        { }
-
-        void CAudioVolumeComponent::onMuteChanged(bool muted)
-        {
-            if (muted == ui->pb_Mute->isChecked()) { return; } // avoid roundtrips
-            ui->pb_Mute->setChecked(muted);
-        }
-
-        void CAudioVolumeComponent::onOutputVolumeChanged(int volume)
-        {
-            ui->hs_Volume->setToolTip(QString::number(volume));
-
-            // comparisons to avoid rountrips
-            const QString v = QString::number(volume);
-            if (volume != ui->sb_Volume->value())
-            {
-                ui->sb_Volume->setValue(volume);
-                ui->sb_Volume->setToolTip(v);
-            }
-
-            if (volume != ui->hs_Volume->value())
-            {
-                ui->hs_Volume->setValue(volumeToSliderValue(volume));
-                ui->hs_Volume->setToolTip(v);
-            }
-        }
-
-        int CAudioVolumeComponent::volumeToSliderValue(int volume)
-        {
-            if (volume <= 100) { return volume; }
-            const int vol = volume - 100;
-            return 100 + vol / 5;
-        }
-
-        void CAudioVolumeComponent::setVolume100()
-        {
-            this->onOutputVolumeChanged(100);
-        }
-
-        void CAudioVolumeComponent::changeOutputVolumeFromSlider(int volume)
-        {
-            if (!sGui || sGui->isShuttingDown() || !sGui->getIContextAudio()) { return; }
-            if (volume > 100)
-            {
-                // 100 -> 100, 120 -> 200, 140 -> 300
-                const int v = volume - 100;
-                volume = 100 + v * 5;
-            }
-            ui->hs_Volume->setToolTip(QString::number(volume));
-
-            if (sGui->getCContextAudioBase()->getVoiceOutputVolume() != volume)
-            {
-                sGui->getCContextAudioBase()->setVoiceOutputVolume(volume);
-            }
-        }
-
-        void CAudioVolumeComponent::changeOutputVolumeFromSpinBox(int volume)
-        {
-            if (!sGui || sGui->isShuttingDown() || !sGui->getIContextAudio()) { return; }
-            ui->sb_Volume->setToolTip(QString::number(volume));
-            Q_ASSERT(sGui->getIContextAudio());
-            if (sGui->getCContextAudioBase()->getVoiceOutputVolume() != volume)
-            {
-                sGui->getCContextAudioBase()->setVoiceOutputVolume(volume);
-            }
-        }
-
-        void CAudioVolumeComponent::onWindowsMixerRequested()
-        {
-            startWindowsMixer();
-        }
-
-    } // namespace
-} // namespace
diff --git a/src/blackgui/components/audiovolumecomponent.h b/src/blackgui/components/audiovolumecomponent.h
deleted file mode 100644
index 1cb929b97..000000000
--- a/src/blackgui/components/audiovolumecomponent.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/* Copyright (C) 2013
- * swift project Community / Contributors
- *
- * This file is part of swift Project. It is subject to the license terms in the LICENSE file found in the top-level
- * directory of this distribution. No part of swift project, including this file, may be copied, modified, propagated,
- * or distributed except according to the terms contained in the LICENSE file.
- */
-
-//! \file
-
-#ifndef BLACKGUI_AUDIOVOLUME_H
-#define BLACKGUI_AUDIOVOLUME_H
-
-#include "blackgui/blackguiexport.h"
-
-#include 
-#include 
-#include 
-
-namespace Ui { class CAudioVolumeComponent; }
-namespace BlackGui
-{
-    namespace Components
-    {
-        //! Audio volume, mixer
-        class BLACKGUI_EXPORT CAudioVolumeComponent : public QFrame
-        {
-            Q_OBJECT
-
-        public:
-            //! Constructor
-            explicit CAudioVolumeComponent(QWidget *parent = nullptr);
-
-            //! Destructor
-            virtual ~CAudioVolumeComponent() override;
-
-        private:
-            //! Mute toggleBlackGui::Components::CHotkeyDialog
-            void onMuteChanged(bool muted);
-
-            //! Volumes changed (elsewhere)
-            void onOutputVolumeChanged(int volume);
-
-            //! Set volume to 100
-            void setVolume100();
-
-            //! Change values because of volume GUI controls
-            void changeOutputVolumeFromSlider(int volume);
-
-            //! Change values because of volume GUI controls
-            void changeOutputVolumeFromSpinBox(int volume);
-
-            //! Requested windows mixer
-            void onWindowsMixerRequested();
-
-            //! slider value
-            static int volumeToSliderValue(int volume);
-
-            QScopedPointer ui;
-        };
-    } // namespace
-} // namespace
-
-#endif // guard
diff --git a/src/blackgui/components/audiovolumecomponent.ui b/src/blackgui/components/audiovolumecomponent.ui
deleted file mode 100644
index b3d49ad52..000000000
--- a/src/blackgui/components/audiovolumecomponent.ui
+++ /dev/null
@@ -1,170 +0,0 @@
-
-
- CAudioVolumeComponent
- 
-  
-   
-    0
-    0
-    193
-    50
-   
-  
-  
-   Frame
-  
-  
-   
-    2
-   
-   
-    2
-   
-   
-    2
-   
-   
-    2
-   
-   
-    
-     
-      140
-     
-     
-      5
-     
-     
-      20
-     
-     
-      90
-     
-     
-      90
-     
-     
-      Qt::Horizontal
-     
-     
-      QSlider::TicksAbove
-     
-     
-      100
-     
-    
-   
-   
-    
-     
-      local
-     
-    
-   
-   
-    
-     
-      
-       0
-       0
-      
-     
-     
-      Sound
-     
-    
-   
-   
-    
-     
-      300
-     
-     
-      5
-     
-     
-      90
-     
-    
-   
-   
-    
-     
-      Volume
-     
-    
-   
-   
-    
-     
-      
-       0
-      
-      
-       0
-      
-      
-       0
-      
-      
-       0
-      
-      
-       0
-      
-      
-       
-        
-         Windows sound mixer
-        
-        
-         
-        
-        
-         
-          :/diagona/icons/diagona/icons/speaker--pencil.png:/diagona/icons/diagona/icons/speaker--pencil.png
-        
-       
-      
-      
-       
-        
-         Toggle mute
-        
-        
-         
-        
-        
-         
-          :/diagona/icons/diagona/icons/speaker-volume.png
-          :/diagona/icons/diagona/icons/speaker-volume-control-mute.png:/diagona/icons/diagona/icons/speaker-volume.png
-        
-        
-         true
-        
-        
-         false
-        
-       
-      
-      
-       
-        
-         
-          40
-          16777215
-         
-        
-        
-         100%
-        
-       
-      
-     
-    
-   
-  
- 
- 
- 
-
diff --git a/src/blackgui/components/mainkeypadareacomponent.cpp b/src/blackgui/components/mainkeypadareacomponent.cpp
index 7a5e5e7e0..9a8c7a91a 100644
--- a/src/blackgui/components/mainkeypadareacomponent.cpp
+++ b/src/blackgui/components/mainkeypadareacomponent.cpp
@@ -144,7 +144,8 @@ namespace BlackGui
             }
             else if (senderButton == ui->pb_SoundMaxVolume && sGui->getIContextAudio())
             {
-                sGui->getCContextAudioBase()->setVoiceOutputVolume(100);
+                sGui->getCContextAudioBase()->setVoiceOutputVolume(CComSystem::Com1, 100);
+                sGui->getCContextAudioBase()->setVoiceOutputVolume(CComSystem::Com2, 100);
             }
             else if (senderButton == ui->pb_SoundMute && sGui->getIContextAudio())
             {
diff --git a/src/blackgui/components/simulatorcomponent.cpp b/src/blackgui/components/simulatorcomponent.cpp
index 885c0b458..96d3d70b1 100644
--- a/src/blackgui/components/simulatorcomponent.cpp
+++ b/src/blackgui/components/simulatorcomponent.cpp
@@ -205,6 +205,8 @@ namespace BlackGui
             this->addOrUpdateLiveDataByName(QStringLiteral("COM2 active"), c2.getFrequencyActive().toQString(), iconRadio);
             this->addOrUpdateLiveDataByName(QStringLiteral("COM1 standby"), c1.getFrequencyStandby().toQString(), iconRadio);
             this->addOrUpdateLiveDataByName(QStringLiteral("COM2 standby"), c2.getFrequencyStandby().toQString(), iconRadio);
+            this->addOrUpdateLiveDataByName(QStringLiteral("COM1 volume"), QString::number(c1.getVolumeReceive()) , iconRadio);
+            this->addOrUpdateLiveDataByName(QStringLiteral("COM2 volume"), QString::number(c2.getVolumeReceive()), iconRadio);
             this->addOrUpdateLiveDataByName(QStringLiteral("Transponder"), ownAircraft.getTransponderCodeFormatted(), iconRadio);
         }
 
diff --git a/src/blackmisc/audio/audiosettings.cpp b/src/blackmisc/audio/audiosettings.cpp
index e0f05268e..f69411a24 100644
--- a/src/blackmisc/audio/audiosettings.cpp
+++ b/src/blackmisc/audio/audiosettings.cpp
@@ -92,9 +92,14 @@ namespace BlackMisc
             else if (m_notificationVolume > 100) { m_notificationVolume = 100; }
         }
 
-        void CSettings::setOutVolume(int volume)
+        void CSettings::setOutVolumeCom1(int volume)
         {
-            m_outVolume = fixOutVolume(volume);
+            m_outVolumeCom1 = fixOutVolume(volume);
+        }
+
+        void CSettings::setOutVolumeCom2(int volume)
+        {
+            m_outVolumeCom2 = fixOutVolume(volume);
         }
 
         void CSettings::setInVolume(int volume)
diff --git a/src/blackmisc/audio/audiosettings.h b/src/blackmisc/audio/audiosettings.h
index 60ca8c16c..de4aa163e 100644
--- a/src/blackmisc/audio/audiosettings.h
+++ b/src/blackmisc/audio/audiosettings.h
@@ -95,11 +95,17 @@ namespace BlackMisc
             //! Get volume (notifications)
             int getNotificationVolume() const { return m_notificationVolume; }
 
-            //! Set volume (audio) 0..100
-            void setOutVolume(int volume);
+            //! Set volume for com1 (audio) 0..100
+            void setOutVolumeCom1(int volume);
 
-            //! Get volume (audio) 0..100
-            int getOutVolume() const { return m_outVolume; }
+            //! Get volume for com1 (audio) 0..100
+            int getOutVolumeCom1() const { return m_outVolumeCom1; }
+
+            //! Set volume for com2 (audio) 0..100
+            void setOutVolumeCom2(int volume);
+
+            //! Get volume for com2 (audio) 0..100
+            int getOutVolumeCom2() const { return m_outVolumeCom2; }
 
             //! Set mic.volume 0..100
             void setInVolume(int volume);
@@ -123,7 +129,8 @@ namespace BlackMisc
             QString m_notificationSoundDir;
             int m_notification = static_cast(CNotificationSounds::DefaultNotifications); //!< play notification for notification x, a little trick to use a string here (streamable, hashable, ..)
             int m_notificationVolume = 90;   //!< 0-90
-            int m_outVolume          = 50;   //!< 0-100, AFV
+            int m_outVolumeCom1      = 50;   //!< 0-100, AFV
+            int m_outVolumeCom2      = 50;   //!< 0-100, AFV
             int m_inVolume           = 50;   //!< AFV range
             bool m_audioEffects      = true; //!< Audio effects en
             void initNotificationFlags();    //!< init flags
@@ -133,7 +140,8 @@ namespace BlackMisc
                 BLACK_METAMEMBER(notificationSoundDir),
                 BLACK_METAMEMBER(notification),
                 BLACK_METAMEMBER(notificationVolume),
-                BLACK_METAMEMBER(outVolume),
+                BLACK_METAMEMBER(outVolumeCom1),
+                BLACK_METAMEMBER(outVolumeCom2),
                 BLACK_METAMEMBER(inVolume),
                 BLACK_METAMEMBER(audioEffects)
             );
diff --git a/src/blackmisc/blackmisc.qrc b/src/blackmisc/blackmisc.qrc
index 5e6d5c367..2911ea208 100644
--- a/src/blackmisc/blackmisc.qrc
+++ b/src/blackmisc/blackmisc.qrc
@@ -119,6 +119,7 @@
         icons/pastel/16/folder-green.png
         icons/pastel/16/folder-pink.png
         icons/pastel/16/folder-purple.png
+        icons/pastel/16/undo.png
     
     
         icons/vatsim/C1.png