File indexing completed on 2024-05-05 09:46:36
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_p.h" 0009 0010 #include <KLocalizedString> 0011 #include <QSocketNotifier> 0012 #include <QThread> 0013 #include <QThreadStorage> 0014 #include <mutex> 0015 #include <spa/utils/result.h> 0016 0017 #include "logging.h" 0018 0019 pw_core_events PipeWireCore::s_pwCoreEvents = { 0020 .version = PW_VERSION_CORE_EVENTS, 0021 .info = &PipeWireCore::onCoreInfo, 0022 .done = nullptr, 0023 .ping = nullptr, 0024 .error = &PipeWireCore::onCoreError, 0025 .remove_id = nullptr, 0026 .bound_id = nullptr, 0027 .add_mem = nullptr, 0028 .remove_mem = nullptr, 0029 }; 0030 0031 PipeWireCore::PipeWireCore() 0032 { 0033 static std::once_flag pwInitOnce; 0034 std::call_once(pwInitOnce, [] { pw_init(nullptr, nullptr); }); 0035 } 0036 0037 void PipeWireCore::onCoreError(void *data, uint32_t id, int seq, int res, const char *message) 0038 { 0039 Q_UNUSED(seq) 0040 0041 qCWarning(PIPEWIRE_LOGGING) << "PipeWire remote error: " << res << message; 0042 if (id == PW_ID_CORE) { 0043 PipeWireCore *pw = static_cast<PipeWireCore *>(data); 0044 Q_EMIT pw->pipewireFailed(QString::fromUtf8(message)); 0045 0046 if (res == -EPIPE) { 0047 // Broken pipe, need reconnecting 0048 if (pw->m_pwCore) { 0049 Q_EMIT pw->pipeBroken(); 0050 spa_hook_remove(&pw->m_coreListener); 0051 pw_core_disconnect(pw->m_pwCore); 0052 pw->init_core(); 0053 } 0054 } 0055 } 0056 } 0057 0058 void PipeWireCore::onCoreInfo(void *data, const struct pw_core_info *info) 0059 { 0060 PipeWireCore *pw = static_cast<PipeWireCore *>(data); 0061 pw->m_serverVersion = QVersionNumber::fromString(QString::fromUtf8(info->version)); 0062 } 0063 0064 PipeWireCore::~PipeWireCore() 0065 { 0066 if (m_pwMainLoop) { 0067 pw_loop_leave(m_pwMainLoop); 0068 } 0069 0070 if (m_pwCore) { 0071 pw_core_disconnect(m_pwCore); 0072 } 0073 0074 if (m_pwContext) { 0075 pw_context_destroy(m_pwContext); 0076 } 0077 0078 if (m_pwMainLoop) { 0079 pw_loop_destroy(m_pwMainLoop); 0080 } 0081 } 0082 0083 bool PipeWireCore::init(int fd) 0084 { 0085 m_pwMainLoop = pw_loop_new(nullptr); 0086 pw_loop_enter(m_pwMainLoop); 0087 0088 QSocketNotifier *notifier = new QSocketNotifier(pw_loop_get_fd(m_pwMainLoop), QSocketNotifier::Read, this); 0089 connect(notifier, &QSocketNotifier::activated, this, [this] { 0090 int result = pw_loop_iterate(m_pwMainLoop, 0); 0091 if (result < 0) 0092 qCWarning(PIPEWIRE_LOGGING) << "pipewire_loop_iterate failed: " << spa_strerror(result); 0093 }); 0094 0095 m_pwContext = pw_context_new(m_pwMainLoop, nullptr, 0); 0096 if (!m_pwContext) { 0097 qCWarning(PIPEWIRE_LOGGING) << "Failed to create PipeWire context"; 0098 m_error = i18n("Failed to create PipeWire context"); 0099 return false; 0100 } 0101 0102 m_fd = fd; 0103 0104 return init_core(); 0105 } 0106 0107 bool PipeWireCore::init_core() 0108 { 0109 if (m_fd > 0) { 0110 m_pwCore = pw_context_connect_fd(m_pwContext, m_fd, nullptr, 0); 0111 } else { 0112 m_pwCore = pw_context_connect(m_pwContext, nullptr, 0); 0113 } 0114 if (!m_pwCore) { 0115 m_error = i18n("Failed to connect to PipeWire"); 0116 qCWarning(PIPEWIRE_LOGGING) << "error:" << m_error << m_fd; 0117 return false; 0118 } 0119 0120 if (pw_loop_iterate(m_pwMainLoop, 0) < 0) { 0121 qCWarning(PIPEWIRE_LOGGING) << "Failed to start main PipeWire loop"; 0122 m_error = i18n("Failed to start main PipeWire loop"); 0123 return false; 0124 } 0125 0126 pw_core_add_listener(m_pwCore, &m_coreListener, &s_pwCoreEvents, this); 0127 return true; 0128 } 0129 0130 QSharedPointer<PipeWireCore> PipeWireCore::fetch(int fd) 0131 { 0132 static QThreadStorage<QHash<int, QWeakPointer<PipeWireCore>>> global; 0133 QSharedPointer<PipeWireCore> ret = global.localData().value(fd).toStrongRef(); 0134 if (!ret) { 0135 ret.reset(new PipeWireCore); 0136 if (ret->init(fd)) { 0137 global.localData().insert(fd, ret); 0138 } 0139 } 0140 return ret; 0141 } 0142 0143 QString PipeWireCore::error() const 0144 { 0145 return m_error; 0146 }