Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qpipewire_audiodevicemonitor_p.h
Go to the documentation of this file.
1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QPIPEWIRE_AUDIODEVICEMONITOR_P_H
5#define QPIPEWIRE_AUDIODEVICEMONITOR_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <QtMultimedia/private/qpipewire_async_support_p.h>
19#include <QtMultimedia/private/qpipewire_propertydict_p.h>
20#include <QtMultimedia/private/qpipewire_registry_support_p.h>
21#include <QtMultimedia/private/qpipewire_spa_pod_support_p.h>
22#include <QtMultimedia/qaudiodevice.h>
23#include <QtCore/qchronotimer.h>
24#include <QtCore/qfuture.h>
25#include <QtCore/qreadwritelock.h>
26
27#include <list>
28#include <vector>
29
30#include <pipewire/pipewire.h>
31
32QT_BEGIN_NAMESPACE
33
34namespace QtPipeWire {
35
37{
39public:
41 ObjectSerial serial() const;
42
45
46private:
47 const ObjectSerial m_observedSerial;
48};
49
51
52// TODO: can we make use of COW here?
54{
56
57 enum class Direction : uint8_t
58 {
59 sink,
60 source,
61 };
62
63public:
66
67 void objectAdded(ObjectId, uint32_t permissions, PipewireRegistryType, uint32_t version,
68 const spa_dict &props);
70
72 {
73 };
77
78 std::optional<ObjectSerial> findSinkNodeSerial(std::string_view nodeName) const;
79 std::optional<ObjectSerial> findSourceNodeSerial(std::string_view nodeName) const;
80
81 // ObjectId/ObjectSerial mapping
84
86 void unregisterObserver(const SharedObjectRemoveObserver &);
87
88 // Obtaining device lists
94 DeviceLists getDeviceLists(bool verifyThreading = true);
95
99
100private:
101 struct DeviceRecord
102 {
103 ObjectSerial serial;
104 PwPropertyDict properties;
105 };
106
107 struct PendingNodeRecord
108 {
109 PendingNodeRecord(ObjectId, ObjectSerial serial, std::optional<ObjectSerial> deviceSerial,
110 PwPropertyDict properties);
111
112 ObjectSerial serial;
113 std::optional<ObjectSerial> deviceSerial; // may be nullopt for virtual nodes
114 PwPropertyDict properties;
115 std::unique_ptr<NodeEventListener> enumFormatListener;
116 std::unique_ptr<CoreEventDoneListener> enumFormatDoneListener;
117 QFuture<std::vector<SpaObjectAudioFormat>> formatFuture;
118
119 // owned by he instance, updated in the formatFuture's continuation (we capture a weak reference in the
120 // continuation to avoid lifetime issues
121 const std::shared_ptr<std::optional<std::vector<SpaObjectAudioFormat>>> formatResults;
122 };
123
124 struct NodeRecord
125 {
126 ObjectSerial serial;
127 std::optional<ObjectSerial> deviceSerial; // may be nullopt for virtual nodes
128 PwPropertyDict properties;
129 SpaObjectAudioFormat format;
130 };
131
132 // discovered, but format not resolved
133 struct PendingRecords
134 {
135 std::list<PendingNodeRecord> m_sources;
136 std::list<PendingNodeRecord> m_sinks;
137 std::vector<ObjectSerial> m_removals;
138
139 std::optional<std::variant<QByteArray, NoDefaultDeviceType>> m_defaultSource;
140 std::optional<std::variant<QByteArray, NoDefaultDeviceType>> m_defaultSink;
141
142 void removeRecordsForObject(ObjectSerial);
143 };
144 QMutex m_pendingRecordsMutex;
145 PendingRecords m_pendingRecords QT_MM_GUARDED_BY(m_pendingRecordsMutex);
146
147 // discovered, format resolved. living on application thread
148 mutable QReadWriteLock m_mutex;
149 std::map<ObjectSerial, DeviceRecord> m_devices QT_MM_GUARDED_BY(m_mutex);
150 std::vector<NodeRecord> m_sources QT_MM_GUARDED_BY(m_mutex);
151 std::vector<NodeRecord> m_sinks QT_MM_GUARDED_BY(m_mutex);
152 std::optional<QByteArray> m_defaultSourceName;
153 std::optional<QByteArray> m_defaultSinkName;
154
155 QThread m_compressionTimerThread{ this };
156 QChronoTimer m_compressionTimer;
157 void startCompressionTimer();
158
159 // Device list updates
160 void audioDevicesChanged(bool verifyThreading = true);
161 void updateSources(std::list<PendingNodeRecord> addedNodes,
162 QSpan<const ObjectSerial> removedObjects);
163 void updateSinks(std::list<PendingNodeRecord> addedNodes,
164 QSpan<const ObjectSerial> removedObjects);
165 template <Direction>
166 void updateSourcesOrSinks(std::list<PendingNodeRecord>, QSpan<const ObjectSerial>);
167
168 QList<QAudioDevice> m_sourceDeviceList;
169 QList<QAudioDevice> m_sinkDeviceList;
170
171 std::optional<ObjectSerial> findDeviceSerial(std::string_view deviceName) const;
172
173 template <Direction>
174 std::optional<ObjectSerial> findNodeSerialForNodeName(std::string_view nodeName) const;
175
176 // ObjectId/ObjectSerial mapping
177 // CHECK: can we completely rely on only accessing ObjectId under the pipewire event loop lock?
178 mutable QReadWriteLock m_objectDictMutex;
179 std::map<ObjectId, ObjectSerial> m_objectSerialDict QT_MM_GUARDED_BY(m_objectDictMutex);
180 std::map<ObjectSerial, ObjectId> m_serialObjectDict QT_MM_GUARDED_BY(m_objectDictMutex);
181
182 std::vector<SharedObjectRemoveObserver>
183 m_objectRemoveObserver QT_MM_GUARDED_BY(m_objectDictMutex);
184};
185
186} // namespace QtPipeWire
187
188QT_END_NAMESPACE
189
190#endif // QPIPEWIRE_AUDIODEVICEMONITOR_P_H
void audioSourcesChanged(QList< QAudioDevice >)
std::optional< ObjectSerial > findObjectSerial(ObjectId) const
void unregisterObserver(const SharedObjectRemoveObserver &)
std::optional< ObjectSerial > findSourceNodeSerial(std::string_view nodeName) const
void setDefaultAudioSink(std::variant< QByteArray, NoDefaultDeviceType >)
DeviceLists getDeviceLists(bool verifyThreading=true)
void setDefaultAudioSource(std::variant< QByteArray, NoDefaultDeviceType >)
std::optional< ObjectSerial > findSinkNodeSerial(std::string_view nodeName) const
static constexpr NoDefaultDeviceType NoDefaultDevice
void objectAdded(ObjectId, uint32_t permissions, PipewireRegistryType, uint32_t version, const spa_dict &props)
std::optional< ObjectId > findObjectId(ObjectSerial) const
bool registerObserver(SharedObjectRemoveObserver)
Q_STATIC_LOGGING_CATEGORY(lcPipewireAudioSink, "qt.multimedia.pipewire.audiosink")
StrongIdType< uint64_t, ObjectSerialTag > ObjectSerial