File indexing completed on 2024-04-14 15:40:18

0001 /*
0002     SPDX-FileCopyrightText: 2016 David Edmundson <davidedmundson@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 
0007 #include "modulemanager.h"
0008 #include "module.h"
0009 #include "server.h"
0010 
0011 #include "gsettingsitem.h"
0012 #define PA_SETTINGS_PATH_MODULES "/org/freedesktop/pulseaudio/module-groups"
0013 
0014 #include <QTimer>
0015 #include <chrono>
0016 
0017 using namespace std::chrono_literals;
0018 
0019 namespace QPulseAudio
0020 {
0021 class ConfigModule : public GSettingsItem
0022 {
0023 public:
0024     ConfigModule(const QString &configName, const QString &moduleName, QObject *parent);
0025     bool isEnabled() const;
0026     void setEnabled(bool enabled, const QVariant &args = QVariant());
0027 
0028 private:
0029     QString m_moduleName;
0030 };
0031 
0032 ConfigModule::ConfigModule(const QString &configName, const QString &moduleName, QObject *parent)
0033     : GSettingsItem(QStringLiteral(PA_SETTINGS_PATH_MODULES "/") + configName + QStringLiteral("/"), parent)
0034     , m_moduleName(moduleName)
0035 {
0036 }
0037 
0038 bool ConfigModule::isEnabled() const
0039 {
0040     return value(QStringLiteral("enabled")).toBool();
0041 }
0042 
0043 void ConfigModule::setEnabled(bool enabled, const QVariant &args)
0044 {
0045     set(QStringLiteral("locked"), true);
0046 
0047     if (enabled) {
0048         set(QStringLiteral("name0"), m_moduleName);
0049         set(QStringLiteral("args0"), args);
0050         set(QStringLiteral("enabled"), true);
0051     } else {
0052         set(QStringLiteral("enabled"), false);
0053     }
0054     set(QStringLiteral("locked"), false);
0055 }
0056 
0057 ModuleManager::ModuleManager(QObject *parent)
0058     : QObject(parent)
0059 {
0060     m_combineSinks = new ConfigModule(QStringLiteral("combine"), QStringLiteral("module-combine-sink"), this);
0061     m_switchOnConnect = new ConfigModule(QStringLiteral("switch-on-connect"), QStringLiteral("module-switch-on-connect"), this);
0062     m_deviceManager = new ConfigModule(QStringLiteral("device-manager"), QStringLiteral("module-device-manager"), this);
0063 
0064     connect(m_combineSinks, &ConfigModule::subtreeChanged, this, &ModuleManager::combineSinksChanged);
0065     connect(m_switchOnConnect, &ConfigModule::subtreeChanged, this, &ModuleManager::switchOnConnectChanged);
0066     connect(m_deviceManager, &ConfigModule::subtreeChanged, this, &ModuleManager::switchOnConnectChanged);
0067 
0068     connect(Context::instance()->server(), &Server::updated, this, &ModuleManager::serverUpdated);
0069 
0070     auto *updateModulesTimer = new QTimer(this);
0071     updateModulesTimer->setInterval(500ms);
0072     updateModulesTimer->setSingleShot(true);
0073     connect(updateModulesTimer, &QTimer::timeout, this, &ModuleManager::updateLoadedModules);
0074     connect(&Context::instance()->modules(), &MapBaseQObject::added, updateModulesTimer, static_cast<void (QTimer::*)(void)>(&QTimer::start));
0075     connect(&Context::instance()->modules(), &MapBaseQObject::removed, updateModulesTimer, static_cast<void (QTimer::*)(void)>(&QTimer::start));
0076     updateLoadedModules();
0077 }
0078 
0079 ModuleManager::~ModuleManager() = default;
0080 ;
0081 
0082 bool ModuleManager::settingsSupported() const
0083 {
0084     // PipeWire does not (yet) have support for module-switch-on-connect and module-combine-sink
0085     // Also switching streams is the default there
0086     // TODO Check whether there is a PipeWire-specific way to do these
0087     return !Context::instance()->server()->isPipeWire();
0088 }
0089 
0090 bool ModuleManager::combineSinks() const
0091 {
0092     return m_combineSinks->isEnabled();
0093 }
0094 
0095 void ModuleManager::setCombineSinks(bool combineSinks)
0096 {
0097     m_combineSinks->setEnabled(combineSinks);
0098 }
0099 
0100 bool ModuleManager::switchOnConnect() const
0101 {
0102     // switch on connect and device-manager do the same task. Only one should be enabled
0103 
0104     // Note on the first run m_deviceManager will appear to be disabled even though it's actually running
0105     // because there is no gconf entry, however m_switchOnConnect will only exist if set by Plasma PA
0106     // hence only check this entry
0107     return m_switchOnConnect->isEnabled();
0108 }
0109 
0110 void ModuleManager::setSwitchOnConnect(bool switchOnConnect)
0111 {
0112     m_deviceManager->setEnabled(!switchOnConnect);
0113     m_switchOnConnect->setEnabled(switchOnConnect);
0114 }
0115 
0116 QStringList ModuleManager::loadedModules() const
0117 {
0118     return m_loadedModules;
0119 }
0120 
0121 void ModuleManager::updateLoadedModules()
0122 {
0123     m_loadedModules.clear();
0124     const auto modules = Context::instance()->modules().data();
0125     for (Module *module : modules) {
0126         m_loadedModules.append(module->name());
0127     }
0128     Q_EMIT loadedModulesChanged();
0129 }
0130 
0131 bool ModuleManager::configModuleLoaded() const
0132 {
0133     return m_loadedModules.contains(configModuleName());
0134 }
0135 
0136 QString ModuleManager::configModuleName() const
0137 {
0138     return QStringLiteral("module-gsettings");
0139 }
0140 }