From c77cb002f3001430fde83d857f24511414f8bd24 Mon Sep 17 00:00:00 2001 From: Jonas Kvinge Date: Fri, 21 Sep 2018 23:29:00 +0200 Subject: [PATCH] Add support for both ALSA hw and plughw --- src/engine/alsadevicefinder.cpp | 5 +- src/engine/enginebase.h | 1 + src/engine/enginetype.cpp | 34 ++--- src/engine/gstengine.cpp | 4 + src/engine/gstengine.h | 1 + src/engine/phononengine.cpp | 4 + src/engine/phononengine.h | 1 + src/engine/vlcengine.cpp | 4 + src/engine/vlcengine.h | 1 + src/engine/xineengine.cpp | 4 + src/engine/xineengine.h | 1 + src/settings/backendsettingspage.cpp | 140 ++++++++++++++++-- src/settings/backendsettingspage.h | 9 ++ src/settings/backendsettingspage.ui | 214 ++++++++++++++++++--------- 14 files changed, 323 insertions(+), 100 deletions(-) diff --git a/src/engine/alsadevicefinder.cpp b/src/engine/alsadevicefinder.cpp index 20fd4aed..1bbfb598 100644 --- a/src/engine/alsadevicefinder.cpp +++ b/src/engine/alsadevicefinder.cpp @@ -99,10 +99,13 @@ QList AlsaDeviceFinder::ListDevices() { Device device; device.description = QString("%1 %2").arg(snd_ctl_card_info_get_name(cardinfo)).arg(snd_pcm_info_get_name(pcminfo)); - device.value = QString("hw:%1,%2").arg(card).arg(dev); device.iconname = GuessIconName(device.description); device.card = card; device.device = dev; + + device.value = QString("hw:%1,%2").arg(card).arg(dev); + ret.append(device); + device.value = QString("plughw:%1,%2").arg(card).arg(dev); ret.append(device); } diff --git a/src/engine/enginebase.h b/src/engine/enginebase.h index 2ec95823..d933352d 100644 --- a/src/engine/enginebase.h +++ b/src/engine/enginebase.h @@ -93,6 +93,7 @@ public: virtual bool ValidOutput(const QString &output) = 0; virtual QString DefaultOutput() = 0; virtual bool CustomDeviceSupport(const QString &output) = 0; + virtual bool ALSADeviceSupport(const QString &output) = 0; // Plays a media stream represented with the URL 'u' from the given 'beginning' to the given 'end' (usually from 0 to a song's length). // Both markers should be passed in nanoseconds. 'end' can be negative, indicating that the real length of 'u' stream is unknown. diff --git a/src/engine/enginetype.cpp b/src/engine/enginetype.cpp index f9bb218f..04b412d5 100644 --- a/src/engine/enginetype.cpp +++ b/src/engine/enginetype.cpp @@ -27,37 +27,33 @@ namespace Engine { Engine::EngineType EngineTypeFromName(QString enginename) { - QString lower = enginename.toLower(); - - if (lower == "xine") return Engine::Xine; - else if (lower == "gstreamer") return Engine::GStreamer; - else if (lower == "phonon") return Engine::Phonon; - else if (lower == "vlc") return Engine::VLC; - else return Engine::None; - + if (lower == "xine") return Engine::Xine; + else if (lower == "gstreamer") return Engine::GStreamer; + else if (lower == "phonon") return Engine::Phonon; + else if (lower == "vlc") return Engine::VLC; + else return Engine::None; } QString EngineName(Engine::EngineType enginetype) { switch (enginetype) { - case Engine::Xine: return QObject::tr("xine"); - case Engine::GStreamer: return QObject::tr("gstreamer"); - case Engine::Phonon: return QObject::tr("phonon"); - case Engine::VLC: return QObject::tr("vlc"); + case Engine::Xine: return QString("xine"); + case Engine::GStreamer: return QString("gstreamer"); + case Engine::Phonon: return QString("phonon"); + case Engine::VLC: return QString("vlc"); case Engine::None: - default: return QObject::tr("None"); - + default: return QString("None"); } } QString EngineDescription(Engine::EngineType enginetype) { switch (enginetype) { - case Engine::Xine: return QObject::tr("Xine"); - case Engine::GStreamer: return QObject::tr("GStreamer"); - case Engine::Phonon: return QObject::tr("Phonon"); - case Engine::VLC: return QObject::tr("VLC"); + case Engine::Xine: return QString("Xine"); + case Engine::GStreamer: return QString("GStreamer"); + case Engine::Phonon: return QString("Phonon"); + case Engine::VLC: return QString("VLC"); case Engine::None: - default: return QObject::tr("None"); + default: return QString("None"); } } diff --git a/src/engine/gstengine.cpp b/src/engine/gstengine.cpp index 27e053b7..3dbb0513 100644 --- a/src/engine/gstengine.cpp +++ b/src/engine/gstengine.cpp @@ -402,6 +402,10 @@ bool GstEngine::CustomDeviceSupport(const QString &output) { return (output == kALSASink || output == kOpenALSASink || output == kOSSSink || output == kOSS4Sink || output == kPulseSink || output == kA2DPSink || output == kAVDTPSink); } +bool GstEngine::ALSADeviceSupport(const QString &output) { + return (output == kALSASink); +} + void GstEngine::ReloadSettings() { Engine::Base::ReloadSettings(); diff --git a/src/engine/gstengine.h b/src/engine/gstengine.h index d52c056d..f55575ae 100644 --- a/src/engine/gstengine.h +++ b/src/engine/gstengine.h @@ -87,6 +87,7 @@ class GstEngine : public Engine::Base, public GstBufferConsumer { bool ValidOutput(const QString &output); QString DefaultOutput() { return kAutoSink; } bool CustomDeviceSupport(const QString &output); + bool ALSADeviceSupport(const QString &output); void EnsureInitialised() { initialising_.waitForFinished(); } void InitialiseGStreamer(); diff --git a/src/engine/phononengine.cpp b/src/engine/phononengine.cpp index 1ab772eb..4a2a34f9 100644 --- a/src/engine/phononengine.cpp +++ b/src/engine/phononengine.cpp @@ -189,3 +189,7 @@ bool PhononEngine::ValidOutput(const QString &output) { bool PhononEngine::CustomDeviceSupport(const QString &output) { return false; } + +bool PhononEngine::ALSADeviceSupport(const QString &output) { + return false; +} diff --git a/src/engine/phononengine.h b/src/engine/phononengine.h index 2a392e75..84608c5d 100644 --- a/src/engine/phononengine.h +++ b/src/engine/phononengine.h @@ -66,6 +66,7 @@ class PhononEngine : public Engine::Base { QString DefaultOutput() { return ""; } bool ValidOutput(const QString &output); bool CustomDeviceSupport(const QString &output); + bool ALSADeviceSupport(const QString &output); protected: void SetVolumeSW( uint percent ); diff --git a/src/engine/vlcengine.cpp b/src/engine/vlcengine.cpp index 3a32f216..653d4424 100644 --- a/src/engine/vlcengine.cpp +++ b/src/engine/vlcengine.cpp @@ -238,6 +238,10 @@ bool VLCEngine::CustomDeviceSupport(const QString &output) { return (output == "auto" ? false : true); } +bool VLCEngine::ALSADeviceSupport(const QString &output) { + return (output == "alsa"); +} + uint VLCEngine::position() const { if (!Initialised()) return (0); diff --git a/src/engine/vlcengine.h b/src/engine/vlcengine.h index 90ae8994..512deb20 100644 --- a/src/engine/vlcengine.h +++ b/src/engine/vlcengine.h @@ -64,6 +64,7 @@ class VLCEngine : public Engine::Base { bool ValidOutput(const QString &output); QString DefaultOutput() { return ""; } bool CustomDeviceSupport(const QString &output); + bool ALSADeviceSupport(const QString &output); private: libvlc_instance_t *instance_; diff --git a/src/engine/xineengine.cpp b/src/engine/xineengine.cpp index a9f57a92..46e5e214 100644 --- a/src/engine/xineengine.cpp +++ b/src/engine/xineengine.cpp @@ -345,6 +345,10 @@ bool XineEngine::CustomDeviceSupport(const QString &output) { return (output == "alsa" || output == "oss" || output == "jack" || output == "pulseaudio"); } +bool XineEngine::ALSADeviceSupport(const QString &output) { + return (output == "alsa"); +} + void XineEngine::ReloadSettings() { Engine::Base::ReloadSettings(); diff --git a/src/engine/xineengine.h b/src/engine/xineengine.h index 1d707e71..e645c521 100644 --- a/src/engine/xineengine.h +++ b/src/engine/xineengine.h @@ -87,6 +87,7 @@ class XineEngine : public Engine::Base { bool ValidOutput(const QString &output); QString DefaultOutput() { return "auto"; } bool CustomDeviceSupport(const QString &output); + bool ALSADeviceSupport(const QString &output); void ReloadSettings(); diff --git a/src/settings/backendsettingspage.cpp b/src/settings/backendsettingspage.cpp index e52b9293..9f0918b7 100644 --- a/src/settings/backendsettingspage.cpp +++ b/src/settings/backendsettingspage.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include "backendsettingspage.h" @@ -112,6 +113,19 @@ void BackendSettingsPage::Load() { ui_->stickslider_replaygainpreamp->setValue(s_.value("rgpreamp", 0.0).toDouble() * 10 + 150); ui_->checkbox_replaygaincompression->setChecked(s_.value("rgcompression", true).toBool()); + int alsaplug_int = alsa_plugin(s_.value("alsaplugin", 0).toInt()); + if (alsa_plugin(alsaplug_int)) { + alsa_plugin alsaplugin = alsa_plugin(alsaplug_int); + switch (alsaplugin) { + case alsa_plugin::alsa_hw: + ui_->radiobutton_alsa_hw->setChecked(true); + break; + case alsa_plugin::alsa_plughw: + ui_->radiobutton_alsa_plughw->setChecked(true); + break; + } + } + if (!EngineInitialised()) return; if (engine()->state() == Engine::Empty) { @@ -139,6 +153,8 @@ void BackendSettingsPage::ConnectSignals() { connect(ui_->lineedit_device, SIGNAL(textChanged(const QString &)), SLOT(DeviceStringChanged())); connect(ui_->slider_bufferminfill, SIGNAL(valueChanged(int)), SLOT(BufferMinFillChanged(int))); connect(ui_->stickslider_replaygainpreamp, SIGNAL(valueChanged(int)), SLOT(RgPreampChanged(int))); + connect(ui_->radiobutton_alsa_hw, SIGNAL(clicked(bool)), SLOT(radiobutton_alsa_hw_clicked(bool))); + connect(ui_->radiobutton_alsa_plughw, SIGNAL(clicked(bool)), SLOT(radiobutton_alsa_plughw_clicked(bool))); } @@ -271,6 +287,27 @@ void BackendSettingsPage::Load_Device(QString output, QVariant device) { ui_->lineedit_device->setEnabled(false); } + if (engine()->ALSADeviceSupport(output)) { + ui_->radiobutton_alsa_hw->setEnabled(true); + ui_->radiobutton_alsa_plughw->setEnabled(true); + if (device.toString().contains(QRegExp("^plughw:.*"))) { + ui_->radiobutton_alsa_hw->setChecked(false); + ui_->radiobutton_alsa_plughw->setChecked(true); + SwitchALSADevices(alsa_plugin::alsa_plughw); + } + else { + ui_->radiobutton_alsa_plughw->setChecked(false); + ui_->radiobutton_alsa_hw->setChecked(true); + SwitchALSADevices(alsa_plugin::alsa_hw); + } + } + else { + ui_->radiobutton_alsa_hw->setEnabled(false); + ui_->radiobutton_alsa_hw->setChecked(false); + ui_->radiobutton_alsa_plughw->setEnabled(false); + ui_->radiobutton_alsa_plughw->setChecked(false); + } + bool found(false); for (int i = 0; i < ui_->combobox_device->count(); ++i) { QVariant d = ui_->combobox_device->itemData(i).value(); @@ -285,17 +322,12 @@ void BackendSettingsPage::Load_Device(QString output, QVariant device) { if (engine()->CustomDeviceSupport(output) && device.type() == QVariant::String && !device.toString().isEmpty()) { ui_->lineedit_device->setText(device.toString()); if (!found) { - bool have_custom(false); - int index_custom = 0; for (int i = 0; i < ui_->combobox_device->count(); ++i) { if (ui_->combobox_device->itemText(i) == "Custom") { - have_custom = true; - index_custom = i; if (ui_->combobox_device->currentText() != "Custom") ui_->combobox_device->setCurrentIndex(i); break; } } - if (have_custom) ui_->combobox_device->setItemData(index_custom, QVariant(device.toString())); } } @@ -315,7 +347,9 @@ void BackendSettingsPage::Save() { EngineBase::OutputDetails output = ui_->combobox_output->itemData(ui_->combobox_output->currentIndex()).value(); output_name = output.name; } + if (ui_->combobox_device->currentText().isEmpty()) device_value = QVariant(); + else if (ui_->combobox_device->currentText() == "Custom") device_value = ui_->lineedit_device->text(); else device_value = ui_->combobox_device->itemData(ui_->combobox_device->currentIndex()).value(); s_.setValue("engine", EngineName(enginetype)); @@ -330,6 +364,10 @@ void BackendSettingsPage::Save() { s_.setValue("rgpreamp", float(ui_->stickslider_replaygainpreamp->value()) / 10 - 15); s_.setValue("rgcompression", ui_->checkbox_replaygaincompression->isChecked()); + if (ui_->radiobutton_alsa_hw->isChecked()) s_.setValue("alsaplugin", static_cast(alsa_plugin::alsa_hw)); + else if (ui_->radiobutton_alsa_plughw->isChecked()) s_.setValue("alsaplugin", static_cast(alsa_plugin::alsa_plughw)); + else s_.remove("alsaplugin"); + // If engine has not been changed, but output or device has been changed, // then set_output_changed(true) to reinitialize engine when dialog closes. if (enginetype == enginetype_current_ && (output_name != output_current_ || device_value != device_current_)) dialog()->set_output_changed(true); @@ -347,7 +385,7 @@ void BackendSettingsPage::Cancel() { void BackendSettingsPage::EngineChanged(int index) { if (!configloaded_ || !EngineInitialised()) return; - + QVariant v = ui_->combobox_engine->itemData(index); Engine::EngineType enginetype = v.value(); @@ -386,12 +424,7 @@ void BackendSettingsPage::DeviceSelectionChanged(int index) { if (engine()->CustomDeviceSupport(output.name)) { ui_->lineedit_device->setEnabled(true); - if (ui_->combobox_device->currentText() == "Custom") { - ui_->combobox_device->setItemData(index, QVariant(ui_->lineedit_device->text())); - } - else { - if (device.type() == QVariant::String) ui_->lineedit_device->setText(device.toString()); - } + if (ui_->combobox_device->currentText() != "Custom" && device.type() == QVariant::String) ui_->lineedit_device->setText(device.toString()); } else { ui_->lineedit_device->setEnabled(false); @@ -409,10 +442,22 @@ void BackendSettingsPage::DeviceStringChanged() { EngineBase::OutputDetails output = ui_->combobox_output->itemData(ui_->combobox_output->currentIndex()).value(); bool found(false); + if (engine()->ALSADeviceSupport(output.name)) { + if (ui_->lineedit_device->text().contains(QRegExp("^hw:.*")) && !ui_->radiobutton_alsa_hw->isChecked()) { + ui_->radiobutton_alsa_hw->setChecked(true); + SwitchALSADevices(alsa_plugin::alsa_hw); + } + else if (ui_->lineedit_device->text().contains(QRegExp("^plughw:.*")) && !ui_->radiobutton_alsa_plughw->isChecked()) { + ui_->radiobutton_alsa_plughw->setChecked(true); + SwitchALSADevices(alsa_plugin::alsa_plughw); + } + } + for (int i = 0; i < ui_->combobox_device->count(); ++i) { QVariant device = ui_->combobox_device->itemData(i).value(); if (device.type() != QVariant::String) continue; if (device.toString().isEmpty()) continue; + if (ui_->combobox_device->itemText(i) == "Custom") continue; if (device.toString() == ui_->lineedit_device->text()) { if (ui_->combobox_device->currentIndex() != i) ui_->combobox_device->setCurrentIndex(i); found = true; @@ -430,7 +475,6 @@ void BackendSettingsPage::DeviceStringChanged() { } } if (ui_->combobox_device->currentText() == "Custom") { - ui_->combobox_device->setItemData(ui_->combobox_device->currentIndex(), QVariant(ui_->lineedit_device->text())); if ((ui_->lineedit_device->text().isEmpty()) && (ui_->combobox_device->count() > 0) && (ui_->combobox_device->currentIndex() != 0)) ui_->combobox_device->setCurrentIndex(0); } } @@ -502,3 +546,73 @@ void BackendSettingsPage::XineWarning() { xinewarning_ = true; } + +void BackendSettingsPage::SwitchALSADevices(alsa_plugin alsaplugin) { + + // All ALSA devices are listed twice, one for "hw" and one for "plughw" + // Only show one of them by making the other ones invisible based on the alsa plugin radiobuttons + for (int i = 0; i < ui_->combobox_device->count(); ++i) { + QListView *view = qobject_cast(ui_->combobox_device->view()); + if (!view) continue; + if (alsaplugin == alsa_plugin::alsa_hw && ui_->combobox_device->itemData(i).toString().contains(QRegExp("^plughw:.*"))) { + view->setRowHidden(i, true); + } + else if (alsaplugin == alsa_plugin::alsa_plughw && ui_->combobox_device->itemData(i).toString().contains(QRegExp("^hw:.*"))) { + view->setRowHidden(i, true); + } + else { + view->setRowHidden(i, false); + } + } + +} + +void BackendSettingsPage::radiobutton_alsa_hw_clicked(bool checked) { + + if (!configloaded_ || !EngineInitialised()) return; + + EngineBase::OutputDetails output = ui_->combobox_output->itemData(ui_->combobox_output->currentIndex()).value(); + if (!engine()->ALSADeviceSupport(output.name)) return; + + if (ui_->lineedit_device->text().contains(QRegExp("^plughw:.*"))) { + SwitchALSADevices(alsa_plugin::alsa_hw); + QString device_new = ui_->lineedit_device->text().replace(QRegExp("^plughw:"), "hw:"); + bool found(false); + for (int i = 0; i < ui_->combobox_device->count(); ++i) { + QVariant device = ui_->combobox_device->itemData(i).value(); + if (device.type() != QVariant::String) continue; + if (device.toString().isEmpty()) continue; + if (device.toString() == device_new) { + if (ui_->combobox_device->currentIndex() != i) ui_->combobox_device->setCurrentIndex(i); + found = true; + } + } + if (!found) ui_->lineedit_device->setText(device_new); + } + +} + +void BackendSettingsPage::radiobutton_alsa_plughw_clicked(bool checked) { + + if (!configloaded_ || !EngineInitialised()) return; + + EngineBase::OutputDetails output = ui_->combobox_output->itemData(ui_->combobox_output->currentIndex()).value(); + if (!engine()->ALSADeviceSupport(output.name)) return; + + if (ui_->lineedit_device->text().contains(QRegExp("^hw:.*"))) { + SwitchALSADevices(alsa_plugin::alsa_plughw); + QString device_new = ui_->lineedit_device->text().replace(QRegExp("^hw:"), "plughw:"); + bool found(false); + for (int i = 0; i < ui_->combobox_device->count(); ++i) { + QVariant device = ui_->combobox_device->itemData(i).value(); + if (device.type() != QVariant::String) continue; + if (device.toString().isEmpty()) continue; + if (device.toString() == device_new) { + if (ui_->combobox_device->currentIndex() != i) ui_->combobox_device->setCurrentIndex(i); + found = true; + } + } + if (!found) ui_->lineedit_device->setText(device_new); + } + +} diff --git a/src/settings/backendsettingspage.h b/src/settings/backendsettingspage.h index a1ed797f..09b07fb5 100644 --- a/src/settings/backendsettingspage.h +++ b/src/settings/backendsettingspage.h @@ -63,8 +63,16 @@ public: void DeviceStringChanged(); void RgPreampChanged(int value); void BufferMinFillChanged(int value); + void radiobutton_alsa_hw_clicked(bool checked); + void radiobutton_alsa_plughw_clicked(bool checked); private: + + enum alsa_plugin { + alsa_hw = 1, + alsa_plughw = 2 + }; + Ui_BackendSettingsPage *ui_; void ConnectSignals(); @@ -78,6 +86,7 @@ private: void ShowWarning(QString text); void ResetWarning(); void XineWarning(); + void SwitchALSADevices(alsa_plugin alsaplugin); QSettings s_; bool configloaded_; diff --git a/src/settings/backendsettingspage.ui b/src/settings/backendsettingspage.ui index 8375c6ba..fb4d0891 100644 --- a/src/settings/backendsettingspage.ui +++ b/src/settings/backendsettingspage.ui @@ -7,7 +7,7 @@ 0 0 596 - 638 + 720 @@ -19,67 +19,84 @@ Audio output - - - QFormLayout::AllNonFixedFieldsGrow - - - - - - 60 - 0 - - - - Engine - - + + + + + + + + 90 + 0 + + + + Engine + + + + + + + false + + + + + + + Qt::Horizontal + + + + - - + + + + + + + 90 + 0 + + + + Output + + + + + + + false + + + + + + + Qt::Horizontal + + + + - - - - true - - - - 60 - 0 - - - - Output - - - - - - - false - - - - - - - true - - - - 60 - 0 - - - - Device - - - - - + + + + + + + 90 + 0 + + + + Device + + + @@ -92,6 +109,12 @@ false + + + 90 + 0 + + 160 @@ -118,6 +141,69 @@ + + + + Qt::Horizontal + + + + + + + + + + + + 90 + 0 + + + + ALSA plugin + + + + + + + false + + + + 0 + 20 + + + + hw + + + + + + + false + + + + 0 + 20 + + + + plughw + + + + + + + Qt::Horizontal + + + @@ -155,7 +241,7 @@ - Minimum buffer fill + &Minimum buffer fill @@ -370,12 +456,6 @@ Qt::Vertical - - - 0 - 0 - -