MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
PipewireMidiBackend.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "InputBackend.hpp"
4
5#ifdef PIPEWIRE_BACKEND
6
7#include <alsa/asoundlib.h>
8#include <pipewire/pipewire.h>
9
10namespace MayaFlux::Core {
11
12/**
13 * @class PipewireMidiBackend
14 * @brief PipeWire-native MIDI input backend
15 *
16 * Enumerates Midi/Source nodes from the PipeWire registry and opens
17 * a pw_stream per port. All streams share a single pw_thread_loop,
18 * avoiding the overhead of one loop per port.
19 *
20 * Threading model:
21 * - One pw_thread_loop drives all MIDI port streams
22 * - The process callback fires on that loop's thread for each port
23 * - Callbacks push to InputManager's queue (thread-safe)
24 * - Registry enumeration and hotplug run on the same loop thread
25 * - m_devices_mutex guards m_enumerated_devices and m_open_devices
26 * across the loop thread and any external caller
27 */
28class MAYAFLUX_API PipewireMidiBackend : public IInputBackend {
29public:
30 struct Config {
31 std::vector<std::string> input_port_filters;
32 std::vector<std::string> output_port_filters;
33 bool auto_open_inputs { true };
34 bool auto_open_outputs { false };
35 bool enable_virtual_port { false };
36 std::string virtual_port_name { "MayaFlux" };
37 };
38
39 PipewireMidiBackend();
40 explicit PipewireMidiBackend(Config config);
41 ~PipewireMidiBackend() override;
42
43 PipewireMidiBackend(const PipewireMidiBackend&) = delete;
44 PipewireMidiBackend& operator=(const PipewireMidiBackend&) = delete;
45 PipewireMidiBackend(PipewireMidiBackend&&) = delete;
46 PipewireMidiBackend& operator=(PipewireMidiBackend&&) = delete;
47
48 void register_midi_port(uint32_t pw_id, const std::string& name, const std::string& object_path);
49
50 // ===================================================================================
51 // IInputBackend Implementation
52 // ===================================================================================
53
54 bool initialize() override;
55 void start() override;
56 void stop() override;
57 void shutdown() override;
58
59 [[nodiscard]] bool is_initialized() const override { return m_initialized.load(); }
60 [[nodiscard]] bool is_running() const override { return m_running.load(); }
61
62 [[nodiscard]] std::vector<InputDeviceInfo> get_devices() const override;
63 size_t refresh_devices() override;
64
65 bool open_device(uint32_t device_id) override;
66 void close_device(uint32_t device_id) override;
67 [[nodiscard]] bool is_device_open(uint32_t device_id) const override;
68 [[nodiscard]] std::vector<uint32_t> get_open_devices() const override;
69
70 void set_input_callback(InputCallback callback) override;
71 void set_device_callback(DeviceCallback callback) override;
72
73 [[nodiscard]] InputType get_type() const override { return InputType::MIDI; }
74 [[nodiscard]] std::string get_name() const override { return "MIDI (PipeWire)"; }
75 [[nodiscard]] std::string get_version() const override;
76
77private:
78 struct MIDIPortInfo : InputDeviceInfo {
79 uint32_t pw_global_id { 0 };
80 std::string object_path;
81 int alsa_client { -1 };
82 int alsa_port { -1 };
83 };
84
85 struct MIDIPortState {
86 MIDIPortInfo info;
87 uint32_t device_id { 0 };
88 std::atomic<bool> active { false };
89 std::function<void(const InputValue&)> input_callback;
90 snd_seq_t* seq_handle { nullptr };
91 int seq_port { -1 };
92 std::thread poll_thread;
93 };
94
95 // ===================================================================================
96 // Enumeration state (used during registry roundtrip and persistent hotplug)
97 // ===================================================================================
98
99 Config m_config;
100 std::atomic<bool> m_initialized { false };
101 std::atomic<bool> m_running { false };
102
103 pw_thread_loop* m_thread_loop { nullptr };
104 pw_context* m_context { nullptr };
105 pw_core* m_core { nullptr };
106
107 pw_registry* m_registry { nullptr };
108 spa_hook m_registry_listener {};
109 spa_hook m_core_listener {};
110
111 mutable std::mutex m_devices_mutex;
112 std::unordered_map<uint32_t, MIDIPortInfo> m_enumerated_devices;
113 std::unordered_map<uint32_t, std::shared_ptr<MIDIPortState>> m_open_devices;
114 uint32_t m_next_device_id { 1 };
115
116 InputCallback m_input_callback;
117 DeviceCallback m_device_callback;
118 mutable std::mutex m_callback_mutex;
119
120 // ===================================================================================
121 // Private helpers
122 // ===================================================================================
123
124 bool port_matches_filter(const std::string& port_name) const;
125 uint32_t find_or_assign_device_id(uint32_t pw_global_id);
126 void create_virtual_port_if_enabled();
127 void notify_device_change(const InputDeviceInfo& info, bool connected);
128
129 // ===================================================================================
130 // PipeWire callbacks (static, called on pw_thread_loop thread)
131 // ===================================================================================
132
133 static void on_registry_global(
134 void* userdata,
135 uint32_t id,
136 uint32_t permissions,
137 const char* type,
138 uint32_t version,
139 const struct spa_dict* props);
140
141 static void on_registry_global_remove(void* userdata, uint32_t id);
142
143 static void on_core_done(void* userdata, uint32_t id, int seq);
144};
145
146} // namespace MayaFlux::Core
147
148#endif // PIPEWIRE_BACKEND
void initialize()
Definition main.cpp:11
InputType
Input backend type enumeration.
std::function< void(const InputValue &)> InputCallback
Callback signature for input events.
std::function< void(const InputDeviceInfo &, bool connected)> DeviceCallback
Callback signature for device connection/disconnection events.
void shutdown()
Release stored references.
Definition Forma.cpp:168
void stop()
Stop all Portal::Graphics operations.
Definition Graphics.cpp:69
bool is_initialized()
Checks if the default engine has been initialized.
Definition Core.cpp:52