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 }