From a9bb60772d2f07419243465643df5c03f693c59e Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Fri, 9 Sep 2022 14:51:59 +0200 Subject: [PATCH] Add functions for registering CLAP plugin proxies --- src/plugin/bridges/clap.cpp | 29 ++++++ src/plugin/bridges/clap.h | 98 +++++++++---------- src/plugin/meson.build | 2 + src/wine-host/bridges/clap-impls/host-proxy.h | 2 +- src/wine-host/bridges/clap.cpp | 4 +- src/wine-host/bridges/clap.h | 2 +- 6 files changed, 79 insertions(+), 58 deletions(-) diff --git a/src/plugin/bridges/clap.cpp b/src/plugin/bridges/clap.cpp index 61b68b72..b0d95160 100644 --- a/src/plugin/bridges/clap.cpp +++ b/src/plugin/bridges/clap.cpp @@ -98,3 +98,32 @@ const void* ClapPluginBridge::get_factory(const char* factory_id) { return nullptr; } } + +std::pair> +ClapPluginBridge::get_proxy(size_t instance_id) noexcept { + std::shared_lock lock(plugin_proxies_mutex_); + + return std::pair>( + *plugin_proxies_.at(instance_id), std::move(lock)); +} + +void ClapPluginBridge::register_plugin_proxy( + std::unique_ptr plugin_proxy) { + std::unique_lock lock(plugin_proxies_mutex_); + + assert(plugin_proxy); + + plugin_proxies_.emplace(plugin_proxy->instance_id(), + std::move(plugin_proxy)); + + // For optimization reaons we use dedicated sockets for functions that will + // be run in the audio processing loop + sockets_.add_audio_thread_and_connect(plugin_proxy->instance_id()); +} + +void ClapPluginBridge::unregister_plugin_proxy(size_t instance_id) { + std::lock_guard lock(plugin_proxies_mutex_); + + plugin_proxies_.erase(instance_id); + sockets_.remove_audio_thread(instance_id); +} diff --git a/src/plugin/bridges/clap.h b/src/plugin/bridges/clap.h index 03e09c17..eade04e9 100644 --- a/src/plugin/bridges/clap.h +++ b/src/plugin/bridges/clap.h @@ -23,6 +23,7 @@ #include "../../common/logging/clap.h" #include "../../common/mutual-recursion.h" #include "clap-impls/plugin-factory-proxy.h" +#include "clap-impls/plugin-proxy.h" #include "common.h" /** @@ -69,45 +70,38 @@ class ClapPluginBridge : PluginBridge> { */ const void* get_factory(const char* factory_id); - // TODO: - // /** - // * Fetch the plugin proxy instance along with a lock valid for the - // * instance's lifetime. This is mostly just to save some boilerplate - // * everywhere. Use C++17's structured binding as syntactic sugar to not - // have - // * to deal with the lock handle. - // */ - // std::pair> - // get_proxy(size_t instance_id) noexcept; + /** + * Fetch the plugin proxy instance along with a lock valid for the + * instance's lifetime. This is mostly just to save some boilerplate + * everywhere. Use C++17's structured binding as syntactic sugar to not have + * to deal with the lock handle. + */ + std::pair> + get_proxy(size_t instance_id) noexcept; - // /** - // * Add a `ClapPluginProxyImpl` to the list of registered proxy objects so - // we - // * can handle host callbacks. This function is called in - // * `ClapPluginProxyImpl`'s constructor. If the plugin supports the - // * `IAudioProcessor` or `IComponent` interfaces, then we'll also connect - // to - // * a dedicated audio processing socket. - // * - // * @param proxy_object The proxy object so we can access its host context - // * and unique instance identifier. - // * - // * @see plugin_proxies_ - // */ - // void register_plugin_proxy(ClapPluginProxyImpl& proxy_object); + /** + * Add a `clap_plugin_proxy` to the list of registered plugin proxies so we + * can handle host callbacks. This function is called in + * `clap_plugin_factory_proxy::create()`. This function also connects the + * instance's audio thread socket. + * + * @param proxy_object The proxy object so we can access its host context + * and unique instance identifier. + * + * @see plugin_proxies_ + */ + void register_plugin_proxy(std::unique_ptr plugin_proxy); - // /** - // * Remove a previously registered `ClapPluginProxyImpl` from the list of - // * registered proxy objects. Called during the object's destructor after - // * asking the Wine plugin host to destroy the component on its side. - // * - // * @param proxy_object The proxy object so we can access its unique - // instance - // * identifier. - // * - // * @see plugin_proxies_ - // */ - // void unregister_plugin_proxy(ClapPluginProxyImpl& proxy_object); + /** + * Remove a previously registered `clap_plugin_proxy` from the list of + * registered plugin proxies. Called in `clap_plugin_proxy::destroy()`after + * asking the Wine plugin host to destroy the component on its side. + * + * @param instance_id The instance ID of the proxy that should be removed. + * + * @see plugin_proxies_ + */ + void unregister_plugin_proxy(size_t instance_id); /** * Send a control message to the Wine plugin host and return the response. @@ -212,28 +206,24 @@ class ClapPluginBridge : PluginBridge> { */ std::unique_ptr plugin_factory_; - // TODO: Implement - // /** - // * All CLAP plugin objects we created from this plugin. We keep track of - // * these in case the plugin does a host callback, so we can associate - // that - // * call with the exact host context object passed to it during a call to - // * `initialize()`. The IDs here are the same IDs as generated by the Wine - // * plugin host. An instance is added here through a call by - // * `register_plugin_proxy()` in `ClapPluginProxyImpl`'s constructor, and - // an - // * instance is then removed through a call to `unregister_plugin_proxy()` - // in - // * the destructor. - // */ - // std::unordered_map> - // plugin_proxies_; + /** + * Proxies for all CLAP plugin instances we created for this plugin library. + * These are all keyed by an ID created on the Wine side when initializing + * the plugin. That lets us send function calls from the host to the correct + * plugin instance, and callbacks from a plugin instance to the correct host + * instance. Instances are added here through a call by + * `register_plugin_proxy()` in `clap_plugin_factory_proxy::create()`, and + * they are removed again by a call to `unregister_plugin_proxy()` in + * `clap_plugin_proxy::destroy()`. + */ + std::unordered_map> + plugin_proxies_; /** * In theory all object handling is safe iff the host also doesn't do * anything weird even without locks, but we'll still prevent adding or * removing instances while accessing other instances at the same time - * anyways. See `ClapBridge::object_instances_mutex` for more details. + * anyways. See `ClapBridge::plugin_instances_mutex_` for more details. * * TODO: At some point replace this with a multiple reader single writer * lock based by a spinlock. Because this lock is rarely contested diff --git a/src/plugin/meson.build b/src/plugin/meson.build index bed9eaf3..7aba1004 100644 --- a/src/plugin/meson.build +++ b/src/plugin/meson.build @@ -77,9 +77,11 @@ if with_clap '../common/notifications.cpp', '../common/plugins.cpp', '../common/process.cpp', + '../common/serialization/clap/host.cpp', '../common/serialization/clap/plugin.cpp', '../common/utils.cpp', '../include/llvm/small-vector.cpp', + 'bridges/clap-impls/plugin-proxy.cpp', 'bridges/clap-impls/plugin-factory-proxy.cpp', 'bridges/clap.cpp', 'host-process.cpp', diff --git a/src/wine-host/bridges/clap-impls/host-proxy.h b/src/wine-host/bridges/clap-impls/host-proxy.h index 0bc3c5d5..dc9dd796 100644 --- a/src/wine-host/bridges/clap-impls/host-proxy.h +++ b/src/wine-host/bridges/clap-impls/host-proxy.h @@ -52,7 +52,7 @@ class clap_host_proxy { /** * The instance ID of the plugin instance this proxy belongs to. */ - inline size_t owner_isntance_id() const { return owner_instance_id_; } + inline size_t owner_instance_id() const { return owner_instance_id_; } static const void* CLAP_ABI host_get_extension(const struct clap_host* host, const char* extension_id); diff --git a/src/wine-host/bridges/clap.cpp b/src/wine-host/bridges/clap.cpp index f280cca3..47b1b985 100644 --- a/src/wine-host/bridges/clap.cpp +++ b/src/wine-host/bridges/clap.cpp @@ -406,7 +406,7 @@ void ClapBridge::register_plugin_instance( // This instance ID has already been generated because the host proxy has to // be created before the plugin instance - const size_t instance_id = host_proxy->owner_isntance_id(); + const size_t instance_id = host_proxy->owner_instance_id(); object_instances_.emplace( instance_id, ClapPluginInstance(plugin, std::move(host_proxy))); @@ -441,7 +441,7 @@ void ClapBridge::register_plugin_instance( socket_listening_latch.get_future().wait(); } -void ClapBridge::unregister_object_instance(size_t instance_id) { +void ClapBridge::unregister_plugin_instance(size_t instance_id) { sockets_.remove_audio_thread(instance_id); // Remove the instance from within the main IO context so diff --git a/src/wine-host/bridges/clap.h b/src/wine-host/bridges/clap.h index 1ffaf6c5..35279423 100644 --- a/src/wine-host/bridges/clap.h +++ b/src/wine-host/bridges/clap.h @@ -358,7 +358,7 @@ class ClapBridge : public HostBridge { * Remove an object from `object_instances_`. Will also tear down the * instance's audio thread. */ - void unregister_object_instance(size_t instance_id); + void unregister_plugin_instance(size_t instance_id); /** * The configuration for this instance of yabridge based on the path to the