Skip to content

Commit

Permalink
PipeWire: Introduce EventManager
Browse files Browse the repository at this point in the history
  • Loading branch information
davidebeatrici committed Sep 28, 2024
1 parent e2f1b28 commit 6b1272c
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 72 deletions.
2 changes: 2 additions & 0 deletions src/backends/PipeWire/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ target_include_directories(be_pipewire

target_sources(be_pipewire
PRIVATE
"EventManager.cpp"
"EventManager.hpp"
"Library.cpp"
"Library.hpp"
"PipeWire.cpp"
Expand Down
72 changes: 72 additions & 0 deletions src/backends/PipeWire/EventManager.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright 2024 The Mumble Developers. All rights reserved.
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file at the root of the
// Mumble source tree or at <https://www.mumble.info/LICENSE>.

#include "EventManager.hpp"

#include "Library.hpp"

#include <pipewire/core.h>
#include <pipewire/node.h>

using namespace pipewire;

static constexpr auto NODE_TYPE_ID = "PipeWire:Interface:Node";

static constexpr pw_registry_events eventsRegistry = { PW_VERSION_REGISTRY_EVENTS,
[](void *userData, const uint32_t id,
const uint32_t /*permissions*/, const char *type,
const uint32_t /*version*/, const spa_dict * /*props*/) {
if (spa_streq(type, NODE_TYPE_ID)) {
auto &manager = *static_cast< EventManager * >(userData);

new NodeInfoData(manager, id);
}
},
[](void *userData, const uint32_t id) {
auto &manager = *static_cast< EventManager* >(userData);

manager.feedback().nodeRemoved(id);
} };

static constexpr pw_node_events eventsNode = { PW_VERSION_NODE_EVENTS,
[](void *userData, const pw_node_info *info) {
auto data = static_cast< NodeInfoData* >(userData);

data->manager().feedback().nodeAdded(info);

delete data;
},
nullptr };

EventManager::EventManager(pw_core *core, const Feedback &feedback)
: m_feedback(feedback), m_registry(pw_core_get_registry(core, PW_VERSION_REGISTRY, 0)) {
if (m_registry) {
pw_registry_add_listener(m_registry, &m_registryListener, &eventsRegistry, this);
}
}

EventManager::~EventManager() {
if (m_registry) {
spa_hook_remove(&m_registryListener);
lib().proxy_destroy(reinterpret_cast< pw_proxy * >(m_registry));
}
}

NodeInfoData::NodeInfoData(EventManager &manager, const uint32_t id)
: m_manager(manager),
m_proxy(static_cast< pw_proxy * >(pw_registry_bind(manager.registry(), id, NODE_TYPE_ID, PW_VERSION_NODE, 0))),
m_listener() {
if (m_proxy) {
lib().proxy_add_object_listener(m_proxy, &m_listener, &eventsNode, this);
}
}

NodeInfoData::~NodeInfoData() {
spa_hook_remove(&m_listener);

if (m_proxy) {
lib().proxy_destroy(m_proxy);
}
}
56 changes: 56 additions & 0 deletions src/backends/PipeWire/EventManager.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright 2024 The Mumble Developers. All rights reserved.
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file at the root of the
// Mumble source tree or at <https://www.mumble.info/LICENSE>.

#ifndef CROSSAUDIO_SRC_BACKENDS_PIPEWIRE_EVENTMANAGER_HPP
#define CROSSAUDIO_SRC_BACKENDS_PIPEWIRE_EVENTMANAGER_HPP

#include <cstdint>
#include <functional>

#include <spa/utils/hook.h>

struct pw_core;
struct pw_node_info;
struct pw_proxy;
struct pw_registry;

namespace pipewire {
class EventManager {
public:
struct Feedback {
std::function< void(const pw_node_info *info) > nodeAdded;
std::function< void(uint32_t id) > nodeRemoved;
};

EventManager(pw_core *core, const Feedback &feedback);
~EventManager();

constexpr auto &feedback() { return m_feedback; }
constexpr auto registry() { return m_registry; }

private:
EventManager(const EventManager &) = delete;
EventManager &operator=(const EventManager &) = delete;

Feedback m_feedback;
pw_registry *m_registry;
spa_hook m_registryListener;
};

class NodeInfoData {
public:
NodeInfoData(EventManager &manager, const uint32_t id);
~NodeInfoData();

constexpr auto &manager() { return m_manager; }

private:
EventManager &m_manager;
pw_proxy *m_proxy;
spa_hook m_listener;
};
} // namespace pipewire

#endif
57 changes: 8 additions & 49 deletions src/backends/PipeWire/PipeWire.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@

#include "PipeWire.hpp"

#include "EventManager.hpp"
#include "Library.hpp"

#include "Node.h"

#include "crossaudio/Macros.h"
Expand Down Expand Up @@ -177,31 +180,6 @@ constexpr BE_Impl PipeWire_Impl = {
};
// clang-format on

static constexpr auto NODE_TYPE_ID = "PipeWire:Interface:Node";

static constexpr pw_registry_events eventsRegistry = {
PW_VERSION_REGISTRY_EVENTS,
[](void *userData, const uint32_t id, const uint32_t /*permissions*/, const char *type, const uint32_t /*version*/,
const spa_dict * /*props*/) {
if (spa_streq(type, NODE_TYPE_ID)) {
auto &engine = *static_cast< Engine * >(userData);

new NodeInfoData(engine, id);
}
},
[](void *userData, const uint32_t id) { static_cast< Engine * >(userData)->removeNode(id); }
};

static constexpr pw_node_events eventsNode = { PW_VERSION_NODE_EVENTS,
[](void *userData, const pw_node_info *info) {
auto data = static_cast< NodeInfoData* >(userData);

data->engine().addNode(info);

delete data;
},
nullptr };

Engine::Engine() : m_threadLoop(nullptr), m_context(nullptr), m_core(nullptr) {
if ((m_threadLoop = lib().thread_loop_new(nullptr, nullptr))) {
m_context = lib().context_new(lib().thread_loop_get_loop(m_threadLoop), nullptr, 0);
Expand Down Expand Up @@ -234,6 +212,9 @@ void Engine::unlock() {
}

ErrorCode Engine::start() {
const EventManager::Feedback eventManagerFeedback{ .nodeAdded = [this](const pw_node_info *info) { addNode(info); },
.nodeRemoved = [this](const uint32_t id) { removeNode(id); } };

if (m_core) {
return CROSSAUDIO_EC_INIT;
}
Expand All @@ -242,8 +223,7 @@ ErrorCode Engine::start() {
return CROSSAUDIO_EC_CONNECT;
}

m_registry = pw_core_get_registry(m_core, PW_VERSION_REGISTRY, 0);
pw_registry_add_listener(m_registry, &m_registryListener, &eventsRegistry, this);
m_eventManager = std::make_unique< EventManager >(m_core, eventManagerFeedback);

if (lib().thread_loop_start(m_threadLoop) < 0) {
stop();
Expand All @@ -256,14 +236,10 @@ ErrorCode Engine::start() {
ErrorCode Engine::stop() {
lock();

spa_hook_remove(&m_registryListener);
m_eventManager.reset();

m_nodes.clear();

if (m_registry) {
lib().proxy_destroy(reinterpret_cast< pw_proxy * >(m_registry));
}

if (m_core) {
lib().core_disconnect(m_core);
m_core = nullptr;
Expand Down Expand Up @@ -472,23 +448,6 @@ ErrorCode Flux::nameSet(const char *name) {
return lib().stream_update_properties(m_stream, &dict) >= 1 ? CROSSAUDIO_EC_OK : CROSSAUDIO_EC_GENERIC;
}

NodeInfoData::NodeInfoData(Engine &engine, const uint32_t id)
: m_engine(engine),
m_proxy(static_cast< pw_proxy * >(pw_registry_bind(engine.m_registry, id, NODE_TYPE_ID, PW_VERSION_NODE, 0))),
m_listener() {
if (m_proxy) {
lib().proxy_add_object_listener(m_proxy, &m_listener, &eventsNode, this);
}
}

NodeInfoData::~NodeInfoData() {
spa_hook_remove(&m_listener);

if (m_proxy) {
lib().proxy_destroy(m_proxy);
}
}

static void processInput(void *userData) {
auto &flux = *static_cast< Flux * >(userData);

Expand Down
35 changes: 12 additions & 23 deletions src/backends/PipeWire/PipeWire.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
#ifndef CROSSAUDIO_SRC_BACKENDS_PIPEWIRE_PIPEWIRE_HPP
#define CROSSAUDIO_SRC_BACKENDS_PIPEWIRE_PIPEWIRE_HPP

#include "Library.hpp"

#include "Backend.h"

#include "crossaudio/Direction.h"
Expand All @@ -16,6 +14,7 @@
#include "crossaudio/Node.h"

#include <map>
#include <memory>
#include <string>

#include <spa/param/audio/raw.h>
Expand All @@ -27,10 +26,15 @@ using FluxFeedback = CrossAudio_FluxFeedback;
using Direction = CrossAudio_Direction;
using Nodes = CrossAudio_Nodes;

struct pw_context;
struct pw_core;
struct pw_node_info;
struct spa_audio_info_raw;
struct pw_stream;
struct pw_thread_loop;

namespace pipewire {
class EventManager;

class Engine {
public:
class Locker {
Expand Down Expand Up @@ -66,19 +70,19 @@ class Engine {
ErrorCode start();
ErrorCode stop();

void addNode(const pw_node_info *info);
void removeNode(const uint32_t id);

pw_thread_loop *m_threadLoop;
pw_context *m_context;
pw_core *m_core;
pw_registry *m_registry;
spa_hook m_registryListener;

std::unique_ptr< EventManager > m_eventManager;

private:
Engine(const Engine &) = delete;
Engine &operator=(const Engine &) = delete;

void addNode(const pw_node_info *info);
void removeNode(uint32_t id);

std::map< uint32_t, Node > m_nodes;
};

Expand Down Expand Up @@ -106,21 +110,6 @@ class Flux {
Flux(const Flux &) = delete;
Flux &operator=(const Flux &) = delete;
};

class NodeInfoData {
public:
NodeInfoData(Engine &engine, const uint32_t id);
~NodeInfoData();

constexpr explicit operator bool() { return m_proxy; }

constexpr Engine &engine() { return m_engine; }

private:
Engine &m_engine;
pw_proxy *m_proxy;
spa_hook m_listener;
};
} // namespace pipewire

// Backend API
Expand Down

0 comments on commit 6b1272c

Please sign in to comment.