File indexing completed on 2024-07-21 05:00:39

0001 /*
0002     SPDX-FileCopyrightText: 2014-2015 Harald Sitter <sitter@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 
0007 #ifndef DEVICE_H
0008 #define DEVICE_H
0009 
0010 #include <QString>
0011 #include <QVariantMap>
0012 
0013 #include <pulse/volume.h>
0014 
0015 #include "port.h"
0016 #include "pulseobject.h"
0017 #include "volumeobject.h"
0018 
0019 namespace QPulseAudio
0020 {
0021 class Device : public VolumeObject
0022 {
0023     Q_OBJECT
0024     Q_PROPERTY(State state READ state NOTIFY stateChanged)
0025     Q_PROPERTY(QString name READ name NOTIFY nameChanged)
0026     Q_PROPERTY(QString description READ description NOTIFY descriptionChanged)
0027     Q_PROPERTY(QString formFactor READ formFactor NOTIFY formFactorChanged)
0028     Q_PROPERTY(quint32 cardIndex READ cardIndex NOTIFY cardIndexChanged)
0029     Q_PROPERTY(QList<QObject *> ports READ ports NOTIFY portsChanged)
0030     Q_PROPERTY(quint32 activePortIndex READ activePortIndex WRITE setActivePortIndex NOTIFY activePortIndexChanged)
0031     Q_PROPERTY(bool default READ isDefault WRITE setDefault NOTIFY defaultChanged)
0032     Q_PROPERTY(bool virtualDevice READ isVirtualDevice NOTIFY virtualDeviceChanged)
0033     Q_PROPERTY(QVariantMap pulseProperties READ pulseProperties NOTIFY pulsePropertiesChanged)
0034 public:
0035     enum State {
0036         InvalidState = 0,
0037         RunningState,
0038         IdleState,
0039         SuspendedState,
0040         UnknownState,
0041     };
0042     Q_ENUMS(State)
0043 
0044     ~Device() override = default;
0045 
0046     template<typename PAInfo>
0047     void updatePulseProperties(const PAInfo *info)
0048     {
0049         QVariantMap pulseProperties;
0050         void *state = nullptr;
0051         while (auto key = pa_proplist_iterate(info->proplist, &state)) {
0052             const auto value = pa_proplist_gets(info->proplist, key);
0053             pulseProperties.insert(key, QString::fromUtf8(value));
0054         }
0055         if (pulseProperties != m_pulseProperties) {
0056             m_pulseProperties = pulseProperties;
0057             Q_EMIT pulsePropertiesChanged();
0058         }
0059     }
0060 
0061     template<typename PAInfo>
0062     void updateDevice(const PAInfo *info)
0063     {
0064         updateVolumeObject(info);
0065 
0066         if (m_name != info->name) {
0067             m_name = info->name;
0068             Q_EMIT nameChanged();
0069         }
0070         if (m_description != info->description) {
0071             m_description = info->description;
0072             Q_EMIT descriptionChanged();
0073         }
0074         const char *form_factor = pa_proplist_gets(info->proplist, PA_PROP_DEVICE_FORM_FACTOR);
0075         if (form_factor) {
0076             QString formFactor = QString::fromUtf8(form_factor);
0077             if (m_formFactor != formFactor) {
0078                 m_formFactor = formFactor;
0079                 Q_EMIT formFactorChanged();
0080             }
0081         }
0082 
0083         updatePulseProperties(info);
0084 
0085         if (m_cardIndex != info->card) {
0086             m_cardIndex = info->card;
0087             Q_EMIT cardIndexChanged();
0088         }
0089 
0090         const quint32 oldActivePortIndex = m_activePortIndex;
0091         bool portsHaveChanged = false;
0092         int i = 0;
0093         for (auto **ports = info->ports; ports && *ports != nullptr; ++ports) {
0094             if (i < m_ports.count()) {
0095                 Port *port = static_cast<Port *>(m_ports.at(i));
0096                 portsHaveChanged |= port->setInfo(*ports);
0097             } else {
0098                 Port *port = new Port(this);
0099                 port->setInfo(*ports);
0100                 m_ports.append(port);
0101                 portsHaveChanged = true;
0102             }
0103             if (info->active_port == *ports) {
0104                 m_activePortIndex = i;
0105             }
0106             ++i;
0107         }
0108 
0109         while (m_ports.count() > i) {
0110             delete m_ports.takeLast();
0111             portsHaveChanged = true;
0112         }
0113 
0114         if (portsHaveChanged) {
0115             Q_EMIT portsChanged();
0116         }
0117         if (portsHaveChanged || m_activePortIndex != oldActivePortIndex) {
0118             Q_EMIT activePortIndexChanged();
0119         }
0120 
0121         State infoState = stateFromPaState(info->state);
0122         if (infoState != m_state) {
0123             m_state = infoState;
0124             Q_EMIT stateChanged();
0125         }
0126 
0127         const bool isVirtual = !(info->flags & 4); // PA_X_HARDWARE
0128         if (m_virtualDevice != isVirtual) {
0129             m_virtualDevice = isVirtual;
0130             Q_EMIT virtualDeviceChanged();
0131         }
0132     }
0133 
0134     State state() const;
0135     QString name() const;
0136     QString description() const;
0137     QString formFactor() const;
0138     quint32 cardIndex() const;
0139     QList<QObject *> ports() const;
0140     quint32 activePortIndex() const;
0141     virtual void setActivePortIndex(quint32 port_index) = 0;
0142     virtual bool isDefault() const = 0;
0143     virtual void setDefault(bool enable) = 0;
0144     bool isVirtualDevice() const;
0145     [[nodiscard]] QVariantMap pulseProperties() const;
0146 
0147     virtual Q_INVOKABLE void switchStreams() = 0;
0148 
0149 Q_SIGNALS:
0150     void stateChanged();
0151     void nameChanged();
0152     void descriptionChanged();
0153     void formFactorChanged();
0154     void cardIndexChanged();
0155     void portsChanged();
0156     void activePortIndexChanged();
0157     void defaultChanged();
0158     void virtualDeviceChanged();
0159     void pulsePropertiesChanged();
0160 
0161 protected:
0162     explicit Device(QObject *parent);
0163 
0164 private:
0165     State stateFromPaState(int value) const;
0166 
0167     QString m_name;
0168     QString m_description;
0169     QString m_formFactor;
0170     quint32 m_cardIndex = -1;
0171     QList<QObject *> m_ports;
0172     quint32 m_activePortIndex = -1;
0173     State m_state = UnknownState;
0174     bool m_virtualDevice = false;
0175     QVariantMap m_pulseProperties;
0176 };
0177 
0178 } // QPulseAudio
0179 
0180 #endif // DEVICE_H