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_async_support.cpp
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
5
7
9
10namespace QtPipeWire {
11
12// SpaListenerBase
13
15
17 : m_sequenceNumber(s_sequenceNumberAllocator.fetch_add(1, std::memory_order_relaxed))
18{
19}
20
21void SpaListenerBase::removeHooks()
22{
23 spa_hook_remove(&m_listenerHook);
24}
25
26///////////////////////////////////////////////////////////////////////////////////////////////////
27
28// NodeEventListener
29
30NodeEventListener::NodeEventListener(PwNodeHandle node, NodeHandler handler)
32{
33 static constexpr struct pw_node_events nodeEvents{
34 .version = PW_VERSION_NODE_EVENTS,
35 .info = NodeEventListener::onInfo,
36 .param = NodeEventListener::onParam,
37 };
38
39 int status = pw_node_add_listener(m_node.get(), &m_listenerHook, &nodeEvents, this);
40 if (status < 0)
41 qFatal() << "Failed to add listener: " << make_error_code(-status).message();
42}
43
44NodeEventListener::~NodeEventListener()
45{
46 removeHooks();
47 QAudioContextManager::withEventLoopLock([&] {
48 m_node = {};
49 });
50}
51
52void NodeEventListener::enumParams(spa_param_type type)
53{
54 int status = pw_node_enum_params(m_node.get(), m_sequenceNumber, type, 0, 0, nullptr);
55 if (status < 0)
56 qCritical() << "pw_node_enum_params failed:" << make_error_code(-status).message();
57}
58
59void NodeEventListener::onInfo(void *data, const pw_node_info *info)
60{
61 NodeEventListener *self = reinterpret_cast<NodeEventListener *>(data);
62 if (self->m_handler.infoHandler)
63 self->m_handler.infoHandler(info);
64}
65
66void NodeEventListener::onParam(void *data, int seq, uint32_t id, uint32_t index, uint32_t next,
67 const spa_pod *param)
68{
69 NodeEventListener *self = reinterpret_cast<NodeEventListener *>(data);
70 if (self->m_handler.paramHandler)
71 self->m_handler.paramHandler(seq, id, index, next, param);
72}
73
74///////////////////////////////////////////////////////////////////////////////////////////////////
75
76// CoreEventListener
77
79{
80 coreEvents.version = PW_VERSION_CORE_EVENTS;
81}
82
84{
85 removeHooks();
86}
87
88///////////////////////////////////////////////////////////////////////////////////////////////////
89
90// CoreEventDoneListener
91
93{
94 coreEvents.done = [](void *self, uint32_t id, int seq) {
96 CoreEventDoneListener *listener = reinterpret_cast<CoreEventDoneListener *>(self);
97 if (id == PW_ID_CORE && listener->m_seqnum == seq) {
98 listener->m_seqnum = -1;
99 if (listener->m_handler)
100 listener->m_handler();
101 }
102 };
103}
104
105q23::expected<void, int> CoreEventDoneListener::asyncWait(pw_core *coreConnection,
106 std::function<void()> handler)
107{
108 m_handler = std::move(handler);
109
110 return QAudioContextManager::withEventLoopLock([&]() -> q23::expected<void, int> {
111 int status = pw_core_add_listener(coreConnection, &m_listenerHook, &coreEvents, this);
112 if (status < 0) {
113 qFatal() << "pw_core_add_listener failed" << make_error_code(-status).message();
114 return q23::unexpected(status);
115 }
116
117 Q_ASSERT(m_seqnum == -1);
118 status = pw_core_sync(coreConnection, PW_ID_CORE, 0);
119 if (status < 0)
120 return q23::unexpected(status);
121 m_seqnum = status;
122 return {};
123 });
124}
125
126///////////////////////////////////////////////////////////////////////////////////////////////////
127
129
130q23::expected<bool, int> CoreEventSyncHelper::sync(pw_core *coreConnection,
131 std::optional<std::chrono::nanoseconds> timeout)
132{
133 auto voidOrError = CoreEventDoneListener::asyncWait(coreConnection, [&] {
134 m_semaphore.release();
135 });
136 if (voidOrError) {
137 if (timeout)
138 return m_semaphore.try_acquire_for(*timeout);
139
140 m_semaphore.acquire();
141 return true;
142 }
143 return voidOrError.error();
144}
145
146} // namespace QtPipeWire
147
148QT_END_NAMESPACE
static std::atomic_int s_sequenceNumberAllocator
std::error_code make_error_code(int errnoValue=errno)
q23::expected< void, int > asyncWait(pw_core *coreConnection, std::function< void()> handler)
q23::expected< bool, int > sync(pw_core *coreConnection, std::optional< std::chrono::nanoseconds > timeout={})
NodeEventListener(PwNodeHandle, NodeHandler)