refs #335, improved audio setup

* changed volume methods from QList<qint32> to qint32 (DBus compliance)
* methods for changed devices
* command parser for audio
* volume display in status bar (pseudo mute)
This commit is contained in:
Klaus Basan
2014-11-05 16:49:49 +01:00
committed by Roland Winklmeier
parent 3fd1f3c8c4
commit 1ea330cc06
11 changed files with 228 additions and 65 deletions

View File

@@ -83,11 +83,17 @@ namespace BlackCore
// KB: Is see some potential changes here, which we should do when we have the new 2.0 vatlib // KB: Is see some potential changes here, which we should do when we have the new 2.0 vatlib
// 1. volume integrated in voice room? // 1. volume integrated in voice room?
// 2. Value object for volumes CVolume / CVolumeList? // 2. Value object for volumes CVolume / CVolumeList?
void changedAudioVolumes(QList<qint32> volumes); void changedAudioVolumes(qint32 com1Volume, qint32 com2Volume);
//! Mute changed //! Mute changed
void changedMute(bool muted); void changedMute(bool muted);
//! Changed audio devices (e.g. device enabled/disable)
void changedAudioDevices(const BlackMisc::Audio::CAudioDeviceList &devices);
//! Changed slection of audio devices
void changedSelectedAudioDevices(const BlackMisc::Audio::CAudioDeviceList &devices);
public slots: public slots:
//! Get voice rooms for COM1, COM2: //! Get voice rooms for COM1, COM2:
virtual BlackMisc::Audio::CVoiceRoomList getComVoiceRoomsWithAudioStatus() const = 0; virtual BlackMisc::Audio::CVoiceRoomList getComVoiceRoomsWithAudioStatus() const = 0;
@@ -182,6 +188,9 @@ namespace BlackCore
//! Enable audio loopback //! Enable audio loopback
virtual void enableAudioLoopback(bool enable = true) = 0; virtual void enableAudioLoopback(bool enable = true) = 0;
//! Command line was entered
virtual bool parseCommandLine(const QString &commandLine) = 0;
}; };
} }

View File

@@ -14,6 +14,7 @@
#include "blackmisc/voiceroomlist.h" #include "blackmisc/voiceroomlist.h"
#include "blackmisc/hotkeyfunction.h" #include "blackmisc/hotkeyfunction.h"
#include "blackmisc/logmessage.h" #include "blackmisc/logmessage.h"
#include "blackmisc/simplecommandparser.h"
#include <QTimer> #include <QTimer>
@@ -154,13 +155,27 @@ namespace BlackCore
Q_ASSERT(this->m_voice); Q_ASSERT(this->m_voice);
Q_ASSERT(audioDevice.getType() != CAudioDevice::Unknown); Q_ASSERT(audioDevice.getType() != CAudioDevice::Unknown);
CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO << audioDevice; CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO << audioDevice;
bool changed = false;
if (audioDevice.getType() == CAudioDevice::InputDevice) if (audioDevice.getType() == CAudioDevice::InputDevice)
{ {
this->m_voice->setInputDevice(audioDevice); if (this->m_voice->getCurrentInputDevice() != audioDevice)
{
this->m_voice->setInputDevice(audioDevice);
changed = true;
}
} }
else else
{ {
this->m_voice->setOutputDevice(audioDevice); if (this->m_voice->getCurrentOutputDevice() != audioDevice)
{
this->m_voice->setOutputDevice(audioDevice);
changed = true;
}
}
if (changed)
{
emit changedSelectedAudioDevices(this->getCurrentAudioDevices());
} }
} }
@@ -176,28 +191,45 @@ namespace BlackCore
qint32 vol1 = com1.getVolumeOutput(); qint32 vol1 = com1.getVolumeOutput();
qint32 vol2 = com2.getVolumeOutput(); qint32 vol2 = com2.getVolumeOutput();
this->setVolumes(vol1, vol2); this->setVolumes(vol1, vol2);
// enable / disable in the same step
m_channelCom1->switchAudioOutput(com1.isEnabled());
m_channelCom2->switchAudioOutput(com2.isEnabled());
} }
void CContextAudio::setVolumes(qint32 com1Volume, qint32 com2Volume) void CContextAudio::setVolumes(qint32 com1Volume, qint32 com2Volume)
{ {
if (m_channelCom1->getVolume() == com1Volume && m_channelCom2->getVolume() == com2Volume) { return; } if (m_channelCom1->getVolume() == com1Volume && m_channelCom2->getVolume() == com2Volume) { return; }
m_channelCom1->setRoomOutputVolume(com1Volume); bool enable1 = com1Volume > 0;
m_channelCom2->setRoomOutputVolume(com2Volume); bool enable2 = com2Volume > 0;
m_channelCom1->switchAudioOutput(com1Volume < 1); bool muted = !enable1 && !enable2;
m_channelCom2->switchAudioOutput(com2Volume < 1);
emit changedAudioVolumes(QList<qint32>({com1Volume, com2Volume})); //! \todo m_channelCom1->setVolume here crashed, also what is correct setRoomOutputVolume or setVolume
m_channelCom1->setVolume(com1Volume);
m_channelCom2->setVolume(com2Volume);
this->setMute(muted);
emit changedAudioVolumes(com1Volume, com2Volume);
} }
void CContextAudio::setMute(bool muted) void CContextAudio::setMute(bool muted)
{ {
if (this->isMuted() == muted) { return; } // avoid roundtrips / unnecessary signals if (this->isMuted() == muted) { return; } // avoid roundtrips / unnecessary signals
m_channelCom1->switchAudioOutput(!muted); m_channelCom1->switchAudioOutput(!muted);
m_channelCom2->switchAudioOutput(!muted); m_channelCom2->switchAudioOutput(!muted);
m_channelCom1->setRoomOutputVolume(muted ? 0 : VoiceRoomEnabledVolume);
m_channelCom2->setRoomOutputVolume(muted ? 0 : VoiceRoomEnabledVolume);
// adjust volume when unmuted
if (!muted)
{
bool adjusted = false;
qint32 v1 = this->m_channelCom1->getVolume();
qint32 v2 = this->m_channelCom2->getVolume();
if (this->m_channelCom1->getVolume() < MinUnmuteVolume) { v1 = MinUnmuteVolume; adjusted = true; }
if (this->m_channelCom2->getVolume() < MinUnmuteVolume) { v2 = MinUnmuteVolume; adjusted = true; }
if (adjusted) { this->setVolumes(v1, v2); }
}
// signal
emit changedMute(muted); emit changedMute(muted);
} }
@@ -385,6 +417,54 @@ namespace BlackCore
m_voice->enableAudioLoopback(enable); m_voice->enableAudioLoopback(enable);
} }
bool CContextAudio::parseCommandLine(const QString &commandLine)
{
static CSimpleCommandParser parser(
{
".vol", ".volume", // all volumes
".vol1", ".volume1", // COM1 volume
".vol2", ".volume2", // COM2 volume
".mute", // mute
".unmute" // unmute
});
if (commandLine.isEmpty()) return false;
parser.parse(commandLine);
if (!parser.isKnownCommand()) return false;
if (parser.matchesCommand(".mute"))
{
this->setMute(true);
return true;
}
else if (parser.matchesCommand(".unmute"))
{
this->setMute(false);
return true;
}
else if (parser.commandStartsWith("vol") && parser.countParts() > 1)
{
qint32 v = parser.toInt(1);
if (v >= 0 && v <= 100)
{
qint32 v1 = this->m_channelCom1->getVolume();
qint32 v2 = this->m_channelCom2->getVolume();
if (parser.commandEndsWith("1"))
{
this->setVolumes(v, v2);
}
else if (parser.commandEndsWith("2"))
{
this->setVolumes(v1, v);
}
else
{
this->setVolumes(v, v);
}
}
}
return false;
}
/* /*
* Connection status changed * Connection status changed
*/ */

View File

@@ -118,6 +118,19 @@ namespace BlackCore
//! \copydoc IContextAudio::enableAudioLoopback() //! \copydoc IContextAudio::enableAudioLoopback()
virtual void enableAudioLoopback(bool enable = true) override; virtual void enableAudioLoopback(bool enable = true) override;
//! \addtogroup commandline
//! @{
//! <pre>
//! .mute mute CContextAudio
//! .unmute unmute CContextAudio
//! .vol .volume volume 0..100 set volume CContextAudio
//! .vol1 .volume1 volume 0..100 set volume COM1 CContextAudio
//! .vol2 .volume2 volume 0..100 set volume COM2 CContextAudio
//! </pre>
//! @}
//! \copydoc IContextAudio::parseCommandLine
virtual bool parseCommandLine(const QString &commandLine) override;
protected: protected:
//! Constructor //! Constructor
CContextAudio(CRuntimeConfig::ContextMode mode, CRuntime *runtime); CContextAudio(CRuntimeConfig::ContextMode mode, CRuntime *runtime);
@@ -144,6 +157,9 @@ namespace BlackCore
void ps_initNotificationSounds(); void ps_initNotificationSounds();
private: private:
const qint32 MinUnmuteVolume = 20; //!< minimum volume when unmuted
const qint32 VoiceRoomEnabledVolume = 95; //!< voice room volume when enabled
//! Connection in transition //! Connection in transition
bool inTransitionState() const; bool inTransitionState() const;
@@ -156,6 +172,6 @@ namespace BlackCore
QPointer<IVoiceChannel> m_channelCom1; QPointer<IVoiceChannel> m_channelCom1;
QPointer<IVoiceChannel> m_channelCom2; QPointer<IVoiceChannel> m_channelCom2;
}; };
} } // namespace
#endif // guard #endif // guard

View File

@@ -39,7 +39,13 @@ namespace BlackCore
"changedVoiceRooms", this, SIGNAL(changedVoiceRooms(BlackMisc::Audio::CVoiceRoomList, bool))); "changedVoiceRooms", this, SIGNAL(changedVoiceRooms(BlackMisc::Audio::CVoiceRoomList, bool)));
Q_ASSERT(s); Q_ASSERT(s);
s = connection.connect(serviceName, IContextAudio::ObjectPath(), IContextAudio::InterfaceName(), s = connection.connect(serviceName, IContextAudio::ObjectPath(), IContextAudio::InterfaceName(),
"changedAudioVolumes", this, SIGNAL(changedAudioVolumes(QList<qint32>))); "changedAudioVolumes", this, SIGNAL(changedAudioVolumes(qint32, qint32)));
Q_ASSERT(s);
s = connection.connect(serviceName, IContextAudio::ObjectPath(), IContextAudio::InterfaceName(),
"changedAudioDevices", this, SIGNAL(changedAudioDevices(BlackMisc::Audio::CAudioDeviceList)));
Q_ASSERT(s);
s = connection.connect(serviceName, IContextAudio::ObjectPath(), IContextAudio::InterfaceName(),
"changedSelectedAudioDevices", this, SIGNAL(changedSelectedAudioDevices(BlackMisc::Audio::CAudioDeviceList)));
Q_ASSERT(s); Q_ASSERT(s);
s = connection.connect(serviceName, IContextAudio::ObjectPath(), IContextAudio::InterfaceName(), s = connection.connect(serviceName, IContextAudio::ObjectPath(), IContextAudio::InterfaceName(),
"changedMute", this, SIGNAL(changedMute(bool))); "changedMute", this, SIGNAL(changedMute(bool)));
@@ -239,4 +245,12 @@ namespace BlackCore
return this->m_dBusInterface->callDBus(QLatin1Literal("enableAudioLoopback"), enable); return this->m_dBusInterface->callDBus(QLatin1Literal("enableAudioLoopback"), enable);
} }
/*
* Parse command line
*/
bool CContextAudioProxy::parseCommandLine(const QString &commandLine)
{
return this->m_dBusInterface->callDBusRet<bool>(QLatin1Literal("parseCommandLine"), commandLine);
}
} // namespace } // namespace

View File

@@ -122,6 +122,10 @@ namespace BlackCore
//! \copydoc IContextAudio::enableAudioLoopback() //! \copydoc IContextAudio::enableAudioLoopback()
virtual void enableAudioLoopback(bool enable = true) override; virtual void enableAudioLoopback(bool enable = true) override;
//! \copydoc IContextOwnAircraft::parseCommandLine
virtual bool parseCommandLine(const QString &commandLine) override;
}; };
} }

View File

@@ -50,18 +50,23 @@ namespace BlackGui
// based on audio context // based on audio context
Q_ASSERT(this->getIContextAudio()); Q_ASSERT(this->getIContextAudio());
bool connected = false;
if (this->getIContextAudio()) if (this->getIContextAudio())
{ {
this->initAudioDeviceLists(); this->initAudioDeviceLists();
connected = this->connect(this->getIContextAudio(), &IContextAudio::audioTestCompleted, this, &CAudioSetupComponent::ps_audioTestUpdate);
Q_ASSERT(connected); // the connects depend on initAudioDeviceLists
connected = this->connect(this->ui->cb_SetupAudioInputDevice, SIGNAL(currentIndexChanged(int)), this, SLOT(ps_audioDeviceSelected(int))); bool connected = this->connect(this->ui->cb_SetupAudioInputDevice, SIGNAL(currentIndexChanged(int)), this, SLOT(ps_audioDeviceSelected(int)));
Q_ASSERT(connected); Q_ASSERT(connected);
connected = this->connect(this->ui->cb_SetupAudioOutputDevice, SIGNAL(currentIndexChanged(int)), this, SLOT(ps_audioDeviceSelected(int))); connected = this->connect(this->ui->cb_SetupAudioOutputDevice, SIGNAL(currentIndexChanged(int)), this, SLOT(ps_audioDeviceSelected(int)));
Q_ASSERT(connected); Q_ASSERT(connected);
this->connect(this->ui->pb_SetupAudioMicrophoneTest, &QPushButton::clicked, this, &CAudioSetupComponent::ps_startAudioTest); this->connect(this->ui->pb_SetupAudioMicrophoneTest, &QPushButton::clicked, this, &CAudioSetupComponent::ps_startAudioTest);
this->connect(this->ui->pb_SetupAudioSquelchTest, &QPushButton::clicked, this, &CAudioSetupComponent::ps_startAudioTest); this->connect(this->ui->pb_SetupAudioSquelchTest, &QPushButton::clicked, this, &CAudioSetupComponent::ps_startAudioTest);
// context
this->connect(this->getIContextAudio(), &IContextAudio::audioTestCompleted, this, &CAudioSetupComponent::ps_audioTestUpdate);
this->connect(this->getIContextAudio(), &IContextAudio::changedAudioDevices, this, &CAudioSetupComponent::ps_onAudioDevicesChanged);
this->connect(this->getIContextAudio(), &IContextAudio::changedSelectedAudioDevices, this, &CAudioSetupComponent::ps_onCurrentAudioDevicesChanged);
} }
this->reloadSettings(); this->reloadSettings();
} }
@@ -92,33 +97,9 @@ namespace BlackGui
*/ */
void CAudioSetupComponent::initAudioDeviceLists() void CAudioSetupComponent::initAudioDeviceLists()
{ {
if (!this->getIContextAudio()) return; if (!this->getIContextAudio()) { return; }
this->ui->cb_SetupAudioOutputDevice->clear(); this->ps_onAudioDevicesChanged(this->getIContextAudio()->getAudioDevices());
this->ui->cb_SetupAudioInputDevice->clear(); this->ps_onCurrentAudioDevicesChanged(this->getIContextAudio()->getCurrentAudioDevices());
foreach(CAudioDevice device, this->getIContextAudio()->getAudioDevices())
{
if (device.getType() == CAudioDevice::InputDevice)
{
this->ui->cb_SetupAudioInputDevice->addItem(device.toQString(true));
}
else if (device.getType() == CAudioDevice::OutputDevice)
{
this->ui->cb_SetupAudioOutputDevice->addItem(device.toQString(true));
}
}
foreach(CAudioDevice device, this->getIContextAudio()->getCurrentAudioDevices())
{
if (device.getType() == CAudioDevice::InputDevice)
{
this->ui->cb_SetupAudioInputDevice->setCurrentText(device.toQString(true));
}
else if (device.getType() == CAudioDevice::OutputDevice)
{
this->ui->cb_SetupAudioOutputDevice->setCurrentText(device.toQString(true));
}
}
} }
/* /*
@@ -236,6 +217,38 @@ namespace BlackGui
} }
} }
void CAudioSetupComponent::ps_onCurrentAudioDevicesChanged(const BlackMisc::Audio::CAudioDeviceList &devices)
{
foreach(CAudioDevice device, devices)
{
if (device.getType() == CAudioDevice::InputDevice)
{
this->ui->cb_SetupAudioInputDevice->setCurrentText(device.toQString(true));
}
else if (device.getType() == CAudioDevice::OutputDevice)
{
this->ui->cb_SetupAudioOutputDevice->setCurrentText(device.toQString(true));
}
}
}
void CAudioSetupComponent::ps_onAudioDevicesChanged(const BlackMisc::Audio::CAudioDeviceList &devices)
{
this->ui->cb_SetupAudioOutputDevice->clear();
this->ui->cb_SetupAudioInputDevice->clear();
foreach(CAudioDevice device, devices)
{
if (device.getType() == CAudioDevice::InputDevice)
{
this->ui->cb_SetupAudioInputDevice->addItem(device.toQString(true));
}
else if (device.getType() == CAudioDevice::OutputDevice)
{
this->ui->cb_SetupAudioOutputDevice->addItem(device.toQString(true));
}
}
}
} // namespace } // namespace
} // namespace } // namespace

View File

@@ -65,6 +65,12 @@ namespace BlackGui
*/ */
void ps_audioDeviceSelected(int index); void ps_audioDeviceSelected(int index);
//! Current audio devices changed
void ps_onCurrentAudioDevicesChanged(const Audio::CAudioDeviceList &devices);
//! Audio devices changed
void ps_onAudioDevicesChanged(const Audio::CAudioDeviceList &devices);
private: private:
//! Audio test modes //! Audio test modes
enum AudioTest enum AudioTest

View File

@@ -23,8 +23,16 @@ namespace BlackGui
ui(new Ui::CAudioVolumeComponent) ui(new Ui::CAudioVolumeComponent)
{ {
ui->setupUi(this); ui->setupUi(this);
bool c = connect(this->ui->pb_ShowWinMixer, &QPushButton::pressed, this, &CAudioVolumeComponent::ps_onWindowsMixer); bool c = connect(this->ui->pb_ShowWinMixer, &QPushButton::pressed, this, &CAudioVolumeComponent::ps_onWindowsMixerRequested);
Q_ASSERT(c); Q_ASSERT(c);
c = connect(this->ui->hs_VolumeCom1, &QSlider::sliderReleased, this, &CAudioVolumeComponent::ps_changeVolume);
Q_ASSERT(c);
c = connect(this->ui->hs_VolumeCom2, &QSlider::sliderReleased, this, &CAudioVolumeComponent::ps_changeVolume);
Q_ASSERT(c);
Q_UNUSED(c);
} }
CAudioVolumeComponent::~CAudioVolumeComponent() CAudioVolumeComponent::~CAudioVolumeComponent()
@@ -32,8 +40,13 @@ namespace BlackGui
void CAudioVolumeComponent::runtimeHasBeenSet() void CAudioVolumeComponent::runtimeHasBeenSet()
{ {
// from audio context
bool c = connect(this->getIContextAudio(), &IContextAudio::changedMute, this, &CAudioVolumeComponent::ps_onMuteChanged); bool c = connect(this->getIContextAudio(), &IContextAudio::changedMute, this, &CAudioVolumeComponent::ps_onMuteChanged);
Q_ASSERT(c); Q_ASSERT(c);
connect(this->getIContextAudio(), &IContextAudio::changedAudioVolumes, this, &CAudioVolumeComponent::ps_onVolumesChanged);
Q_ASSERT(c);
// to audio audio context
c = connect(this->ui->pb_Mute, &QPushButton::toggled, this->getIContextAudio(), &IContextAudio::setMute); c = connect(this->ui->pb_Mute, &QPushButton::toggled, this->getIContextAudio(), &IContextAudio::setMute);
Q_ASSERT(c); Q_ASSERT(c);
} }
@@ -44,15 +57,24 @@ namespace BlackGui
this->ui->pb_Mute->setChecked(muted); this->ui->pb_Mute->setChecked(muted);
} }
void CAudioVolumeComponent::ps_onVolumeChanged(QList<qint32> volumes) void CAudioVolumeComponent::ps_onVolumesChanged(qint32 com1Volume, qint32 com2Volume)
{ {
Q_ASSERT(volumes.length() == 2); this->ui->hs_VolumeCom1->setValue(com1Volume);
if (volumes.length() != 2) return; this->ui->hs_VolumeCom2->setValue(com2Volume);
this->ui->hs_VolumeCom1->setValue(volumes.at(0)); this->ui->hs_VolumeCom1->setToolTip(QString::number(com1Volume));
this->ui->hs_VolumeCom2->setValue(volumes.at(1)); this->ui->hs_VolumeCom2->setToolTip(QString::number(com2Volume));
} }
void CAudioVolumeComponent::ps_onWindowsMixer() void CAudioVolumeComponent::ps_changeVolume()
{
qint32 v1 = this->ui->hs_VolumeCom1->value();
qint32 v2 = this->ui->hs_VolumeCom2->value();
this->ui->hs_VolumeCom1->setToolTip(QString::number(v1));
this->ui->hs_VolumeCom2->setToolTip(QString::number(v2));
this->getIContextAudio()->setVolumes(v1, v2);
}
void CAudioVolumeComponent::ps_onWindowsMixerRequested()
{ {
BlackMisc::Audio::startWindowsMixer(); BlackMisc::Audio::startWindowsMixer();
} }

View File

@@ -44,11 +44,14 @@ namespace BlackGui
//! Mute toggle //! Mute toggle
void ps_onMuteChanged(bool muted); void ps_onMuteChanged(bool muted);
//! Volumes changed //! Volumes changed (elsewhere)
void ps_onVolumeChanged(QList<qint32> volumes); void ps_onVolumesChanged(qint32 com1Volume, qint32 com2Volume);
//! Change values because of volume GUI controls
void ps_changeVolume();
//! Requested windows mixer //! Requested windows mixer
void ps_onWindowsMixer(); void ps_onWindowsMixerRequested();
private: private:
QScopedPointer<Ui::CAudioVolumeComponent> ui; QScopedPointer<Ui::CAudioVolumeComponent> ui;

View File

@@ -170,13 +170,9 @@ namespace BlackGui
} }
} }
void CInfoBarStatusComponent::ps_onVolumesChanged(QList<qint32> volumes) void CInfoBarStatusComponent::ps_onVolumesChanged(qint32 com1Volume, qint32 com2Volume)
{ {
Q_ASSERT(volumes.count() == 2); bool pseudoMute = (com1Volume < 1 && com2Volume < 1);
if (volumes.count() != 2) { return; }
qint32 v1 = volumes.at(0);
qint32 v2 = volumes.at(1);
bool pseudoMute = (v1 < 1 && v2 < 1);
this->ps_onMuteChanged(pseudoMute); this->ps_onMuteChanged(pseudoMute);
} }
@@ -184,5 +180,5 @@ namespace BlackGui
{ {
this->ui->led_Audio->setOn(!muted); this->ui->led_Audio->setOn(!muted);
} }
} } // namespace
} } // namespace

View File

@@ -63,7 +63,7 @@ namespace BlackGui
void ps_customAudioContextMenuRequested(const QPoint &position); void ps_customAudioContextMenuRequested(const QPoint &position);
//! Volumes changed 0..100 //! Volumes changed 0..100
void ps_onVolumesChanged(QList<qint32> volumes); void ps_onVolumesChanged(qint32 com1Volume, qint32 com2Volume);
//! Mute changed //! Mute changed
void ps_onMuteChanged(bool muted); void ps_onMuteChanged(bool muted);