6#include <QtMultimedia/private/qpipewire_portal_p.h>
7#include <QtCore/qeventloop.h>
8#include <QtCore/qloggingcategory.h>
9#include <QtCore/qscopeguard.h>
10#include <QtCore/qtimer.h>
11#include <QtCore/qthread.h>
12#include <QtCore/quuid.h>
13#include <QtDBus/qdbusconnection.h>
14#include <QtDBus/qdbusinterface.h>
15#include <QtDBus/qdbusreply.h>
16#include <QtDBus/qdbusunixfiledescriptor.h>
30class CameraPortalWorker :
public QObject
35 q23::expected<QDBusUnixFileDescriptor, QString> run(std::chrono::milliseconds timeout)
37 const QString connectionName = u"qt_pipewire_camera_portal_%1"_s.arg(
38 QUuid::createUuid().toString(QUuid::WithoutBraces));
40 QDBusConnection::connectToBus(QDBusConnection::SessionBus, connectionName);
41 auto disconnectFromBus = qScopeGuard([&] {
42 QDBusConnection::disconnectFromBus(connectionName);
44 if (!bus.isConnected())
45 return q23::unexpected(u"could not open a private session bus connection"_s);
47 const QString token = allocatePortalRequestToken();
48 const QString requestPath = portalRequestPath(bus, token);
50 if (!bus.connect(u"org.freedesktop.portal.Desktop"_s, requestPath,
51 u"org.freedesktop.portal.Request"_s, u"Response"_s,
this,
52 SLOT(onResponse(uint, QVariantMap)))) {
53 return q23::unexpected(u"could not subscribe to the portal Request response"_s);
55 auto disconnectBus = qScopeGuard([&] {
56 bus.disconnect(u"org.freedesktop.portal.Desktop"_s, requestPath,
57 u"org.freedesktop.portal.Request"_s, u"Response"_s,
this,
58 SLOT(onResponse(uint, QVariantMap)));
61 QDBusInterface cameraInterface(u"org.freedesktop.portal.Desktop"_s,
62 u"/org/freedesktop/portal/desktop"_s,
63 u"org.freedesktop.portal.Camera"_s, bus);
64 QDBusReply<QDBusObjectPath> accessReply =
65 cameraInterface.call(u"AccessCamera"_s,
67 { u"handle_token"_s, token },
69 if (!accessReply.isValid()) {
70 return q23::unexpected(u"AccessCamera failed: "_s + accessReply.error().message());
75 QTimer::singleShot(timeout, &loop, &QEventLoop::quit);
80 return q23::unexpected(u"timed out waiting for the camera access request"_s);
82 return q23::unexpected(
83 u"camera access request was not granted (response=%1)"_s.arg(m_response));
85 QDBusReply<QDBusUnixFileDescriptor> fdReply =
86 cameraInterface.call(u"OpenPipeWireRemote"_s, QVariantMap{});
87 if (!fdReply.isValid())
88 return q23::unexpected(u"OpenPipeWireRemote failed: "_s + fdReply.error().message());
90 return fdReply.value();
94 void onResponse(uint response,
const QVariantMap &)
96 m_response = response;
103 QEventLoop *m_loop =
nullptr;
105 bool m_gotResponse =
false;
118 auto worker =
std::make_unique<CameraPortalWorker>();
119 worker->moveToThread(&thread);
121 q23::expected<QDBusUnixFileDescriptor, QString> result =
122 q23::unexpected(u"the camera portal worker did not run"_s);
123 QMetaObject::invokeMethod(worker.get(), [&] {
124 result = worker->run(timeout);
125 }, Qt::BlockingQueuedConnection);
131 qCDebug(lcCameraPortal) <<
"requestCameraPortalFd failed:" << result.error();
140#include "qpipewire_cameraportalclient.moc"
Q_STATIC_LOGGING_CATEGORY(lcPipewireAudioSink, "qt.multimedia.pipewire.audiosink")
q23::expected< QDBusUnixFileDescriptor, QString > requestCameraPortalFd(std::chrono::milliseconds timeout)