File indexing completed on 2024-05-26 05:31:25
0001 /* 0002 SPDX-FileCopyrightText: 2023 Fushan Wen <qydwhotmail@gmail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #pragma once 0008 0009 #include <QAbstractListModel> 0010 #include <QQmlParserStatus> 0011 #include <QSharedPointer> 0012 #include <QTimer> 0013 #include <qqmlregistration.h> 0014 0015 #include <pipewire/pipewire.h> 0016 0017 class PipeWireCore; 0018 0019 namespace MediaRole 0020 { 0021 Q_NAMESPACE 0022 QML_ELEMENT 0023 // Match PW_KEY_MEDIA_ROLE 0024 enum Role : int { 0025 Unknown = -1, 0026 Movie, 0027 Music, 0028 Camera, 0029 Screen, 0030 Communication, 0031 Game, 0032 Notification, 0033 DSP, 0034 Production, 0035 Accessibility, 0036 Test, 0037 Last = Test, 0038 }; 0039 Q_ENUM_NS(Role) 0040 } 0041 0042 namespace NodeState 0043 { 0044 Q_NAMESPACE 0045 QML_ELEMENT 0046 // Match enum pw_node_state 0047 enum State : int { 0048 Error = -1, /**< error state */ 0049 Creating = 0, /**< the node is being created */ 0050 Suspended = 1, /**< the node is suspended, the device might be closed */ 0051 Idle = 2, /**< the node is running but there is no active port */ 0052 Running = 3, /**< the node is running */ 0053 }; 0054 Q_ENUM_NS(State) 0055 } 0056 0057 class MediaMonitor : public QAbstractListModel, public QQmlParserStatus 0058 { 0059 Q_OBJECT 0060 Q_INTERFACES(QQmlParserStatus) 0061 QML_ELEMENT 0062 0063 /** 0064 * Role for media streams. Only media streams with their @p PW_KEY_MEDIA_ROLE matching @p role will be monitored. 0065 * @default MediaRole::Unknown 0066 */ 0067 Q_PROPERTY(MediaRole::Role role READ role WRITE setRole NOTIFY roleChanged) 0068 0069 /** 0070 * Whether this monitor is able to detect apps using Pipewire for media access 0071 */ 0072 Q_PROPERTY(bool detectionAvailable READ detectionAvailable NOTIFY detectionAvailableChanged) 0073 0074 /** 0075 * Total count of media streams with the given role on the system 0076 */ 0077 Q_PROPERTY(int count READ rowCount NOTIFY countChanged) 0078 0079 /** 0080 * The number of media streams that are currently used by applications 0081 */ 0082 Q_PROPERTY(int runningCount READ runningCount NOTIFY runningCountChanged) 0083 0084 /** 0085 * The number of media streams that are in idle state. 0086 */ 0087 Q_PROPERTY(int idleCount READ idleCount NOTIFY idleCountChanged) 0088 0089 public: 0090 enum Role { 0091 StateRole = Qt::UserRole + 1, 0092 ObjectSerialRole, 0093 }; 0094 Q_ENUM(Role); 0095 0096 explicit MediaMonitor(QObject *parent = nullptr); 0097 ~MediaMonitor() override; 0098 0099 QVariant data(const QModelIndex &index, int role) const override; 0100 int rowCount(const QModelIndex &parent = QModelIndex()) const override; 0101 QHash<int, QByteArray> roleNames() const override; 0102 0103 MediaRole::Role role() const; 0104 void setRole(MediaRole::Role newRole); 0105 0106 bool detectionAvailable() const; 0107 int runningCount() const; 0108 int idleCount() const; 0109 0110 Q_SIGNALS: 0111 void roleChanged(); 0112 void detectionAvailableChanged(); 0113 void countChanged(); 0114 void runningCountChanged(); 0115 void idleCountChanged(); 0116 0117 private Q_SLOTS: 0118 void connectToCore(); 0119 void onPipeBroken(); 0120 0121 private: 0122 struct ProxyDeleter { 0123 void operator()(pw_proxy *proxy) const 0124 { 0125 MediaMonitor::onProxyDestroy(pw_proxy_get_user_data(proxy)); 0126 pw_proxy_destroy(proxy); 0127 } 0128 }; 0129 0130 static void onRegistryEventGlobal(void *data, uint32_t id, uint32_t permissions, const char *type, uint32_t version, const spa_dict *props); 0131 static void onRegistryEventGlobalRemove(void *data, uint32_t id); 0132 static void onProxyDestroy(void *data); 0133 static void onNodeEventInfo(void *data, const pw_node_info *info); 0134 0135 static void readProps(const spa_dict *props, pw_proxy *proxy, bool emitSignal); 0136 0137 void classBegin() override; 0138 void componentComplete() override; 0139 0140 void disconnectFromCore(); 0141 void reconnectOnIdle(); 0142 void updateState(); 0143 0144 static pw_registry_events s_pwRegistryEvents; 0145 static pw_proxy_events s_pwProxyEvents; 0146 static pw_node_events s_pwNodeEvents; 0147 0148 bool m_componentReady = false; 0149 MediaRole::Role m_role = MediaRole::Unknown; 0150 bool m_detectionAvailable = false; 0151 int m_runningCount = 0; 0152 int m_idleCount = 0; 0153 0154 QSharedPointer<PipeWireCore> m_pwCore; 0155 pw_registry *m_registry = nullptr; 0156 spa_hook m_registryListener; 0157 std::vector<std::unique_ptr<pw_proxy, ProxyDeleter>> m_nodeList; 0158 QTimer m_reconnectTimer; 0159 0160 bool m_inDestructor = false; 0161 };