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_symbolloader)
10# include <QtMultimedia/private/qpipewire_symbolloader_p.h>
13#include <QtDBus/qdbusinterface.h>
14#include <QtDBus/qdbusmessage.h>
16#include <QtCore/qcoreapplication.h>
17#include <QtCore/qmutex.h>
19#include <spa/utils/names.h>
37 std::weak_ptr<QPipeWireInstance> instance;
40Q_GLOBAL_STATIC(InstanceHolder, s_pipeWireInstance);
46 pw_init(
nullptr,
nullptr);
48 qCDebug(lcPipewire) <<
"PipeWire initialized: compiled against" << pw_get_headers_version()
49 <<
" running " << pw_get_library_version();
54 if (pw_check_library_version(0, 3, 49))
60 std::lock_guard guard{ s_pipeWireInstance->mutex };
61 std::shared_ptr<QPipeWireInstance> ret = s_pipeWireInstance->instance.lock();
63 ret = QPipeWireInstance::create();
65 s_pipeWireInstance->instance = ret;
72#if QT_CONFIG(pipewire_symbolloader)
73 return qPipewireIsLoaded();
79q23::expected<
void, std::error_code>
QPipeWireInstance::hasSPAFactory(
const char *factoryName)
81 std::array<spa_support, 32> support{};
82 uint32_t n_support = pw_get_support(support.data(), uint32_t(support.size()));
84 SpaHandleHandle handle{
85 pw_load_spa_handle(
nullptr, factoryName,
nullptr, n_support,
89 return q23::unexpected{ make_error_code() };
96 return m_eventLoop.isInThread();
101 return m_eventLoop.loop();
106 QDBusInterface properties(u"org.freedesktop.portal.Desktop"_s,
107 u"/org/freedesktop/portal/desktop"_s,
108 u"org.freedesktop.DBus.Properties"_s, QDBusConnection::sessionBus());
110 QDBusMessage reply = properties.call(u"Get"_s, interface, u"version"_s);
112 if (reply.type() != QDBusMessage::ReplyMessage || reply.arguments().size() != 1) {
113 qCDebug(lcPipewire) << interface <<
"not available:" << reply.errorName()
114 << reply.errorMessage();
119 const uint version = reply.arguments().at(0).toUInt();
120 qCDebug(lcPipewire) << interface <<
"version" << version;
126 if (!m_hasScreenCastPortal)
127 m_hasScreenCastPortal =
128 portalInterfaceVersion(u"org.freedesktop.portal.ScreenCast"_s).has_value();
129 return *m_hasScreenCastPortal;
134 auto connection = PwCoreConnectionHandle{
135 pw_context_connect(m_context.get(),
nullptr,
140 return q23::unexpected(make_error_code(errno));
146 auto connection = PwCoreConnectionHandle{
147 pw_context_connect_fd(m_context.get(), fd,
nullptr,
152 return q23::unexpected(make_error_code(errno));
158 auto instance = std::unique_ptr<QPipeWireInstance>(
new QPipeWireInstance);
159 if (!instance->m_eventLoop || !instance->m_context)
170 int status = m_eventLoop.start();
172 qFatal() <<
"Failed to start event loop" << make_error_code(-status).message();
174 m_context = runWithEventLoopLock([&] {
175 auto applicationName = qApp->applicationName().toUtf8();
176 PwPropertiesHandle props = makeProperties({
177 { PW_KEY_APP_NAME, applicationName.data() },
180 return PwContextHandle{
181 pw_context_new(m_eventLoop.loop(), props.release(), 0),
188 runWithEventLoopLock([&] { m_context = {}; });
bool isInPwThreadLoop() const
q23::expected< PwCoreConnectionHandle, std::error_code > connectToPortal(int fd)
q23::expected< PwCoreConnectionHandle, std::error_code > connectToDaemon()
pw_loop * eventLoop() const
bool hasScreenCastPortal()
static std::optional< uint > portalInterfaceVersion(const QString &interface)
Q_LOGGING_CATEGORY(lcPipewire, "qt.multimedia.pipewire")
Q_DECLARE_LOGGING_CATEGORY(lcPipewire)