7#include <alsa/asoundlib.h>
8#include <pipewire/pipewire.h>
28class MAYAFLUX_API PipewireMidiBackend :
public IInputBackend {
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" };
39 PipewireMidiBackend();
40 explicit PipewireMidiBackend(Config config);
41 ~PipewireMidiBackend()
override;
43 PipewireMidiBackend(
const PipewireMidiBackend&) =
delete;
44 PipewireMidiBackend& operator=(
const PipewireMidiBackend&) =
delete;
45 PipewireMidiBackend(PipewireMidiBackend&&) =
delete;
46 PipewireMidiBackend& operator=(PipewireMidiBackend&&) =
delete;
48 void register_midi_port(uint32_t pw_id,
const std::string& name,
const std::string& object_path);
55 void start()
override;
59 [[nodiscard]]
bool is_initialized()
const override {
return m_initialized.load(); }
60 [[nodiscard]]
bool is_running()
const override {
return m_running.load(); }
62 [[nodiscard]] std::vector<InputDeviceInfo> get_devices()
const override;
63 size_t refresh_devices()
override;
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;
70 void set_input_callback(InputCallback callback)
override;
71 void set_device_callback(DeviceCallback callback)
override;
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;
78 struct MIDIPortInfo : InputDeviceInfo {
79 uint32_t pw_global_id { 0 };
80 std::string object_path;
81 int alsa_client { -1 };
85 struct MIDIPortState {
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 };
92 std::thread poll_thread;
100 std::atomic<bool> m_initialized {
false };
101 std::atomic<bool> m_running {
false };
103 pw_thread_loop* m_thread_loop {
nullptr };
104 pw_context* m_context {
nullptr };
105 pw_core* m_core {
nullptr };
107 pw_registry* m_registry {
nullptr };
108 spa_hook m_registry_listener {};
109 spa_hook m_core_listener {};
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 };
118 mutable std::mutex m_callback_mutex;
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);
133 static void on_registry_global(
136 uint32_t permissions,
139 const struct spa_dict* props);
141 static void on_registry_global_remove(
void* userdata, uint32_t
id);
143 static void on_core_done(
void* userdata, uint32_t
id,
int seq);
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 stop()
Stop all Portal::Graphics operations.
bool is_initialized()
Checks if the default engine has been initialized.