diff --git a/include/libremidi/backends/linux/pipewire/context.hpp b/include/libremidi/backends/linux/pipewire/context.hpp index dfdeec63..51382683 100644 --- a/include/libremidi/backends/linux/pipewire/context.hpp +++ b/include/libremidi/backends/linux/pipewire/context.hpp @@ -1130,10 +1130,9 @@ class context : public std::enable_shared_from_this void fill_port_from_props(port_info& p, const spa_dict* props) noexcept { if (auto v = dict_get(props, "format.dsp"); !v.empty()) - { p.format = std::string{v}; - p.kind = classify_format_dsp(p.format); - } + if (auto k = classify_port_props(props); k != media_class::other) + p.kind = k; if (auto v = dict_get(props, PW_KEY_PORT_NAME); !v.empty()) p.port_name = std::string{v}; if (auto v = dict_get(props, PW_KEY_PORT_ALIAS); !v.empty()) diff --git a/include/libremidi/backends/linux/pipewire/types.hpp b/include/libremidi/backends/linux/pipewire/types.hpp index 07243cba..8eef2aa9 100644 --- a/include/libremidi/backends/linux/pipewire/types.hpp +++ b/include/libremidi/backends/linux/pipewire/types.hpp @@ -104,6 +104,13 @@ inline media_class classify_node_props(const spa_dict* props) noexcept return classify_media_class(dict_get(props, PW_KEY_MEDIA_CLASS)); } +inline media_class classify_port_props(const spa_dict* props) noexcept +{ + if (dict_get(props, "control.ump") == "true") + return media_class::ump; + return classify_format_dsp(dict_get(props, "format.dsp")); +} + struct port_info { std::uint32_t id{}; diff --git a/include/libremidi/backends/pipewire/helpers.hpp b/include/libremidi/backends/pipewire/helpers.hpp index 5225ae23..1765acd7 100644 --- a/include/libremidi/backends/pipewire/helpers.hpp +++ b/include/libremidi/backends/pipewire/helpers.hpp @@ -210,14 +210,22 @@ struct pipewire_helpers this->flt->update_params(this->port, params, 1); } + static bool port_matches( + const libremidi::pipewire::port_info& port, libremidi::pipewire::media_class kind) noexcept + { + if (kind == libremidi::pipewire::media_class::ump) + return port.kind == libremidi::pipewire::media_class::ump; + return libremidi::pipewire::is_midi_like(port.kind); + } + template - void add_callbacks(std::string format, const observer_configuration& conf) + void add_callbacks(libremidi::pipewire::media_class kind, const observer_configuration& conf) { assert(this->ctx); sub_added = this->ctx->on_port_added( - [this, format, &conf](const libremidi::pipewire::port_info& port) { - if (port.format.find(format) == std::string::npos) + [this, kind, &conf](const libremidi::pipewire::port_info& port) { + if (!port_matches(port, kind)) return; this->port_cache[port.id] = port; @@ -239,14 +247,14 @@ struct pipewire_helpers }); sub_removed = this->ctx->on_port_removed( - [this, format, &conf](std::uint32_t port_id) { + [this, kind, &conf](std::uint32_t port_id) { auto it = this->port_cache.find(port_id); if (it == this->port_cache.end()) return; const auto port = it->second; this->port_cache.erase(it); - if (port.format.find(format) == std::string::npos) + if (!port_matches(port, kind)) return; bool unfiltered = conf.track_any; unfiltered |= (port.physical && conf.track_hardware); @@ -420,7 +428,8 @@ struct pipewire_helpers // user-facing input port carries Direction=OUTPUT. template static auto get_ports( - std::string_view format, const observer_configuration& conf, const context_t& ctx) noexcept + libremidi::pipewire::media_class kind, const observer_configuration& conf, + const context_t& ctx) noexcept -> std::vector< std::conditional_t> { @@ -433,7 +442,7 @@ struct pipewire_helpers const auto& bucket = (Direction == SPA_DIRECTION_INPUT ? node.inputs : node.outputs); for (const auto& port : bucket) { - if (port.format.find(format) == std::string::npos) + if (!port_matches(port, kind)) continue; bool unfiltered = conf.track_any; unfiltered |= (port.physical && conf.track_hardware); diff --git a/include/libremidi/backends/pipewire/observer.hpp b/include/libremidi/backends/pipewire/observer.hpp index 285d954b..d773e94b 100644 --- a/include/libremidi/backends/pipewire/observer.hpp +++ b/include/libremidi/backends/pipewire/observer.hpp @@ -27,7 +27,8 @@ class observer_pipewire final // Hold thread_loop_lock so a port arriving between subscription // install and the snapshot walk doesn't fire twice. this->ctx->with_lock([this] { - this->add_callbacks("midi", configuration); + this->add_callbacks( + libremidi::pipewire::media_class::midi, configuration); if (configuration.notify_in_constructor) { @@ -49,7 +50,7 @@ class observer_pipewire final if (!this->ctx) return {}; return get_ports( - "midi", this->configuration, *this->ctx); + libremidi::pipewire::media_class::midi, this->configuration, *this->ctx); } std::vector get_output_ports() const noexcept override @@ -57,7 +58,7 @@ class observer_pipewire final if (!this->ctx) return {}; return get_ports( - "midi", this->configuration, *this->ctx); + libremidi::pipewire::media_class::midi, this->configuration, *this->ctx); } ~observer_pipewire() { destroy_context(); } diff --git a/include/libremidi/backends/pipewire_ump/observer.hpp b/include/libremidi/backends/pipewire_ump/observer.hpp index c21c21e9..6ce56644 100644 --- a/include/libremidi/backends/pipewire_ump/observer.hpp +++ b/include/libremidi/backends/pipewire_ump/observer.hpp @@ -27,7 +27,8 @@ class observer_pipewire final // Atomic subscribe + initial walk (see pipewire/observer.hpp). this->ctx->with_lock([this] { - this->add_callbacks("UMP", configuration); + this->add_callbacks( + libremidi::pipewire::media_class::ump, configuration); if (configuration.notify_in_constructor) { @@ -52,7 +53,7 @@ class observer_pipewire final if (!this->ctx) return {}; return get_ports( - "UMP", this->configuration, *this->ctx); + libremidi::pipewire::media_class::ump, this->configuration, *this->ctx); } std::vector get_output_ports() const noexcept override @@ -60,7 +61,7 @@ class observer_pipewire final if (!this->ctx) return {}; return get_ports( - "UMP", this->configuration, *this->ctx); + libremidi::pipewire::media_class::ump, this->configuration, *this->ctx); } ~observer_pipewire() { destroy_context(); }