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_instance.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
6#include <QtMultimedia/private/qpipewire_propertydict_p.h>
7#include <QtMultimedia/private/qpipewire_support_p.h>
8#include <QtMultimedia/private/qtmultimediaglobal_p.h>
9#if QT_CONFIG(pipewire_screencapture)
10# include <QtMultimedia/private/qpipewire_portal_p.h>
11#endif
12#if QT_CONFIG(pipewire_symbolloader)
13# include <QtMultimedia/private/qpipewire_symbolloader_p.h>
14#endif
15
16#include <QtCore/qcoreapplication.h>
17#include <QtCore/qmutex.h>
18
19#include <spa/utils/names.h>
20
21#include <array>
22#include <mutex>
23
24QT_BEGIN_NAMESPACE
25
26namespace QtPipeWire {
27
28using namespace Qt::Literals;
29
30Q_LOGGING_CATEGORY(lcPipewire, "qt.multimedia.pipewire");
31
32namespace {
33
34struct InstanceHolder
35{
36 QMutex mutex;
37 std::weak_ptr<QPipeWireInstance> instance;
38};
39
40Q_GLOBAL_STATIC(InstanceHolder, s_pipeWireInstance);
41
42} // namespace
43
45{
46 pw_init(nullptr, nullptr);
47
48 qCDebug(lcPipewire) << "PipeWire initialized: compiled against" << pw_get_headers_version()
49 << " running " << pw_get_library_version();
50}
51
53{
54 if (pw_check_library_version(0, 3, 49))
55 pw_deinit();
56}
57
58std::shared_ptr<QPipeWireInstance> QPipeWireInstance::instance()
59{
60 std::lock_guard guard{ s_pipeWireInstance->mutex };
61 std::shared_ptr<QPipeWireInstance> ret = s_pipeWireInstance->instance.lock();
62 if (!ret) {
63 ret = QPipeWireInstance::create();
64 if (ret)
65 s_pipeWireInstance->instance = ret;
66 }
67 return ret;
68}
69
71{
72#if QT_CONFIG(pipewire_symbolloader)
73 return qPipewireIsLoaded();
74#else
75 return 1;
76#endif
77}
78
79q23::expected<void, std::error_code> QPipeWireInstance::hasSPAFactory(const char *factoryName)
80{
81 std::array<spa_support, 32> support{};
82 uint32_t n_support = pw_get_support(support.data(), uint32_t(support.size()));
83
84 SpaHandleHandle handle{
85 pw_load_spa_handle(/*lib=*/nullptr, factoryName, /*info=*/nullptr, n_support,
86 support.data()),
87 };
88 if (!handle)
89 return q23::unexpected{ make_error_code() };
90
91 return {};
92}
93
95{
96 return m_eventLoop.isInThread();
97}
98
100{
101 return m_eventLoop.loop();
102}
103
105{
106#if QT_CONFIG(pipewire_screencapture)
107 if (!m_hasScreenCastPortal)
108 m_hasScreenCastPortal =
109 portalInterfaceVersion("org.freedesktop.portal.ScreenCast"_L1).has_value();
110 return *m_hasScreenCastPortal;
111#else
112 return false;
113#endif
114}
115
117{
118 auto connection = PwCoreConnectionHandle{
119 pw_context_connect(m_context.get(), /*props=*/nullptr,
120 /*user_data_size=*/0),
121 };
122
123 if (!connection)
124 return q23::unexpected(make_error_code(errno));
125 return connection;
126}
127
129{
130 auto connection = PwCoreConnectionHandle{
131 pw_context_connect_fd(m_context.get(), fd, /*props=*/nullptr,
132 /*user_data_size=*/0),
133 };
134
135 if (!connection)
136 return q23::unexpected(make_error_code(errno));
137 return connection;
138}
139
140std::unique_ptr<QPipeWireInstance> QPipeWireInstance::create()
141{
142 auto instance = std::unique_ptr<QPipeWireInstance>(new QPipeWireInstance);
143 if (!instance->m_eventLoop || !instance->m_context)
144 return nullptr;
145
146 return instance;
147}
148
149QPipeWireInstance::QPipeWireInstance()
150{
151 if (!m_eventLoop)
152 return;
153
154 int status = m_eventLoop.start();
155 if (status < 0)
156 qFatal() << "Failed to start event loop" << make_error_code(-status).message();
157
158 m_context = runWithEventLoopLock([&] {
159 auto applicationName = qApp->applicationName().toUtf8();
160 PwPropertiesHandle props = makeProperties({
161 { PW_KEY_APP_NAME, applicationName.data() },
162 });
163
164 return PwContextHandle{
165 pw_context_new(m_eventLoop.loop(), props.release(), /*user_data_size=*/0),
166 };
167 });
168}
169
171{
172 runWithEventLoopLock([&] { m_context = {}; });
173 m_eventLoop.stop();
174}
175
176} // namespace QtPipeWire
177
178QT_END_NAMESPACE
q23::expected< PwCoreConnectionHandle, std::error_code > connectToPortal(int fd)
q23::expected< PwCoreConnectionHandle, std::error_code > connectToDaemon()
Q_LOGGING_CATEGORY(lcPipewire, "qt.multimedia.pipewire")
Q_DECLARE_LOGGING_CATEGORY(lcPipewire)