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