Add functions for registering CLAP plugin proxies

This commit is contained in:
Robbert van der Helm
2022-09-09 14:51:59 +02:00
parent bacda47671
commit a9bb60772d
6 changed files with 79 additions and 58 deletions
+29
View File
@@ -98,3 +98,32 @@ const void* ClapPluginBridge::get_factory(const char* factory_id) {
return nullptr;
}
}
std::pair<clap_plugin_proxy&, std::shared_lock<std::shared_mutex>>
ClapPluginBridge::get_proxy(size_t instance_id) noexcept {
std::shared_lock lock(plugin_proxies_mutex_);
return std::pair<clap_plugin_proxy&, std::shared_lock<std::shared_mutex>>(
*plugin_proxies_.at(instance_id), std::move(lock));
}
void ClapPluginBridge::register_plugin_proxy(
std::unique_ptr<clap_plugin_proxy> 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);
}
+44 -54
View File
@@ -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<ClapSockets<std::jthread>> {
*/
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<ClapPluginProxyImpl&, std::shared_lock<std::shared_mutex>>
// 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<clap_plugin_proxy&, std::shared_lock<std::shared_mutex>>
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<clap_plugin_proxy> 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<ClapSockets<std::jthread>> {
*/
std::unique_ptr<clap_plugin_factory_proxy> 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<size_t, std::reference_wrapper<ClapPluginProxyImpl>>
// 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<size_t, std::unique_ptr<clap_plugin_proxy>>
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
+2
View File
@@ -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',
@@ -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);
+2 -2
View File
@@ -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
+1 -1
View File
@@ -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