File indexing completed on 2024-04-21 16:13:06
0001 /* 0002 SPDX-FileCopyrightText: 2020 Aleix Pol Gonzalez <aleixpol@kde.org> 0003 SPDX-FileContributor: Jan Grulich <jgrulich@redhat.com> 0004 0005 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0006 */ 0007 0008 #include "pipewirecore.h" 0009 #include "logging.h" 0010 #include <KLocalizedString> 0011 #include <QSocketNotifier> 0012 #include <QThread> 0013 #include <QThreadStorage> 0014 #include <spa/utils/result.h> 0015 #include <mutex> 0016 0017 pw_core_events PipeWireCore::s_pwCoreEvents = { 0018 .version = PW_VERSION_CORE_EVENTS, 0019 .info = &PipeWireCore::onCoreInfo, 0020 .done = nullptr, 0021 .ping = nullptr, 0022 .error = &PipeWireCore::onCoreError, 0023 .remove_id = nullptr, 0024 .bound_id = nullptr, 0025 .add_mem = nullptr, 0026 .remove_mem = nullptr, 0027 }; 0028 0029 PipeWireCore::PipeWireCore() 0030 { 0031 static std::once_flag pwInitOnce; 0032 std::call_once(pwInitOnce, [] { pw_init(nullptr, nullptr); }); 0033 } 0034 0035 void PipeWireCore::onCoreError(void *data, uint32_t id, int seq, int res, const char *message) 0036 { 0037 Q_UNUSED(seq) 0038 0039 qCWarning(PIPEWIRE_LOGGING) << "PipeWire remote error: " << res << message; 0040 if (id == PW_ID_CORE) { 0041 PipeWireCore *pw = static_cast<PipeWireCore *>(data); 0042 Q_EMIT pw->pipewireFailed(QString::fromUtf8(message)); 0043 } 0044 } 0045 0046 void PipeWireCore::onCoreInfo(void *data, const struct pw_core_info *info) 0047 { 0048 PipeWireCore *pw = static_cast<PipeWireCore *>(data); 0049 pw->m_serverVersion = QVersionNumber::fromString(QString::fromUtf8(info->version)); 0050 } 0051 0052 PipeWireCore::~PipeWireCore() 0053 { 0054 if (m_pwMainLoop) { 0055 pw_loop_leave(m_pwMainLoop); 0056 } 0057 0058 if (m_pwCore) { 0059 pw_core_disconnect(m_pwCore); 0060 } 0061 0062 if (m_pwContext) { 0063 pw_context_destroy(m_pwContext); 0064 } 0065 0066 if (m_pwMainLoop) { 0067 pw_loop_destroy(m_pwMainLoop); 0068 } 0069 } 0070 0071 bool PipeWireCore::init(int fd) 0072 { 0073 m_pwMainLoop = pw_loop_new(nullptr); 0074 pw_loop_enter(m_pwMainLoop); 0075 0076 QSocketNotifier *notifier = new QSocketNotifier(pw_loop_get_fd(m_pwMainLoop), QSocketNotifier::Read, this); 0077 connect(notifier, &QSocketNotifier::activated, this, [this] { 0078 int result = pw_loop_iterate(m_pwMainLoop, 0); 0079 if (result < 0) 0080 qCWarning(PIPEWIRE_LOGGING) << "pipewire_loop_iterate failed: " << spa_strerror(result); 0081 }); 0082 0083 m_pwContext = pw_context_new(m_pwMainLoop, nullptr, 0); 0084 if (!m_pwContext) { 0085 qCWarning(PIPEWIRE_LOGGING) << "Failed to create PipeWire context"; 0086 m_error = i18n("Failed to create PipeWire context"); 0087 return false; 0088 } 0089 0090 if (fd > 0) { 0091 m_pwCore = pw_context_connect_fd(m_pwContext, fd, nullptr, 0); 0092 } else { 0093 m_pwCore = pw_context_connect(m_pwContext, nullptr, 0); 0094 } 0095 if (!m_pwCore) { 0096 m_error = i18n("Failed to connect to PipeWire"); 0097 qCWarning(PIPEWIRE_LOGGING) << "error:" << m_error << fd; 0098 return false; 0099 } 0100 0101 if (pw_loop_iterate(m_pwMainLoop, 0) < 0) { 0102 qCWarning(PIPEWIRE_LOGGING) << "Failed to start main PipeWire loop"; 0103 m_error = i18n("Failed to start main PipeWire loop"); 0104 return false; 0105 } 0106 0107 pw_core_add_listener(m_pwCore, &m_coreListener, &s_pwCoreEvents, this); 0108 return true; 0109 } 0110 0111 QSharedPointer<PipeWireCore> PipeWireCore::fetch(int fd) 0112 { 0113 static QThreadStorage<QHash<int, QWeakPointer<PipeWireCore>>> global; 0114 QSharedPointer<PipeWireCore> ret = global.localData().value(fd).toStrongRef(); 0115 if (!ret) { 0116 ret.reset(new PipeWireCore); 0117 if (ret->init(fd)) { 0118 global.localData().insert(fd, ret); 0119 } 0120 } 0121 return ret; 0122 } 0123 0124 QString PipeWireCore::error() const 0125 { 0126 return m_error; 0127 }