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_cameracontextmanager.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 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_async_support_p.h>
7#include <QtMultimedia/private/qpipewire_instance_p.h>
8#include <QtCore/qapplicationstatic.h>
9#include <QtCore/qloggingcategory.h>
10
11#if QT_CONFIG(dbus)
12# include <QtMultimedia/private/qpipewire_cameraportalclient_p.h>
13# include <QtMultimedia/private/qpipewire_portal_p.h>
14# include <QtDBus/qdbusunixfiledescriptor.h>
15#endif
16
17#include <pipewire/pipewire.h>
18
19#if !PW_CHECK_VERSION(0, 3, 75)
20extern "C" {
21bool pw_check_library_version(int major, int minor, int micro);
22}
23#endif
24
25QT_BEGIN_NAMESPACE
26
27namespace QtPipeWire {
28
30Q_STATIC_LOGGING_CATEGORY(lcPipewireCameraRegistry, "qt.multimedia.pipewire.camera.registry")
31
35 },
38 }
39{
40 static const bool forcePortal =
41 qEnvironmentVariableIntValue("QT_PIPEWIRE_CAMERA_FORCE_PORTAL") != 0;
42
43 if (!forcePortal) {
46 return;
47 }
48
49#if QT_CONFIG(dbus)
51#else
53 << "Cannot fall back to the camera portal: built without D-Bus support";
54#endif
55}
56
58{
61 if (!connection) {
62 qCDebug(lcPipewireCameraRegistry) << "Failed to connect to pipewire instance directly:"
64 return false;
65 }
68 return true;
69 });
70}
71
72#if QT_CONFIG(dbus)
74{
75 using namespace std::chrono_literals;
76
77 if (!portalInterfaceVersion(QLatin1StringView("org.freedesktop.portal.Camera"))) {
78 qCWarning(lcPipewireCameraRegistry) << "No camera portal available either";
79 return false;
80 }
81
82 // brings up a dialog for the user to approve camera access
83 auto fd = requestCameraPortalFd(20s);
84 if (!fd) {
86 << "Failed to obtain a camera file descriptor from the portal:" << fd.error();
87 return false;
88 }
89
92 if (!connection) {
94 << "Failed to connect via the camera portal" << connection.error().message();
95 return false;
96 }
99 return true;
100 });
101}
102#endif
103
115
120
122{
124 return false;
125
126 if (!pw_check_library_version(0, 3, 44))
127 return false;
128
130 return self && self->isConnected();
131}
132
137
142
144{
145 return PwNodeHandle{
146 reinterpret_cast<pw_node *>(pw_registry_bind(m_registry.get(), id.value,
147 PW_TYPE_INTERFACE_Node, PW_VERSION_NODE,
148 sizeof(void *))),
149 };
150}
151
153{
154 using namespace std::chrono_literals;
156
158 if (syncOrErr == true)
159 return;
160 if (syncOrErr == false)
161 qWarning() << "pw_core_sync timed out";
162 else if (syncOrErr.error()) {
163 int err = syncOrErr.error();
164 qWarning() << "CoreEventSyncHelper::sync failed:" << make_error_code(err).message();
165 }
166}
167
169 const char *type, uint32_t version, const spa_dict *props)
170{
172
174 if (!objectType) {
175 qCritical() << "object type cannot be parsed:" << type;
176 return;
177 }
178
179 if (!props) {
180 qCritical() << "null property received";
181 return;
182 }
183
186}
187
189{
191
192 auto *self = reinterpret_cast<QCameraContextManager *>(data);
194}
195
198 const spa_dict &props)
199{
201}
202
204{
206}
207
209{
211 pw_core_get_registry(m_coreConnection.get(), PW_VERSION_REGISTRY,
212 /*user_data_size=*/sizeof(QCameraContextManager *)),
213 };
214 if (!m_registry) {
215 qFatal() << "Failed to create pipewire registry" << make_error_code().message();
216 return;
217 }
218
219 spa_zero(m_registryListener);
220
221 static constexpr struct pw_registry_events registry_events = {
225 };
226 int status =
228 if (status < 0)
229 qFatal() << "Failed to add listener" << make_error_code(-status).message();
230}
231
233{
234 if (!m_registry)
235 return;
236
240 });
241}
242
243} // namespace QtPipeWire
244
245QT_END_NAMESPACE