From 583645bb46dc070ecfa76272e9b51b5cc7723562 Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Sun, 13 Dec 2020 21:31:59 +0100 Subject: [PATCH] Add a holder for component contexts and pointers When implementing the other component interfaces we want to be able to store the `FUnknownPtrs`. --- src/wine-host/bridges/vst3.cpp | 60 ++++++++++++++++++---------------- src/wine-host/bridges/vst3.h | 46 ++++++++++++++++---------- 2 files changed, 61 insertions(+), 45 deletions(-) diff --git a/src/wine-host/bridges/vst3.cpp b/src/wine-host/bridges/vst3.cpp index a5be655b..f37f6bd8 100644 --- a/src/wine-host/bridges/vst3.cpp +++ b/src/wine-host/bridges/vst3.cpp @@ -22,6 +22,12 @@ #include "vst3-impls/host-application.h" +ComponentInstance::ComponentInstance() {} + +ComponentInstance::ComponentInstance( + Steinberg::IPtr component) + : component(component) {} + Vst3Bridge::Vst3Bridge(MainContext& main_context, std::string plugin_dll_path, std::string endpoint_base_dir) @@ -44,6 +50,11 @@ Vst3Bridge::Vst3Bridge(MainContext& main_context, } void Vst3Bridge::run() { + // XXX: In theory all of thise should be safe assuming the host doesn't do + // anything weird. We're using mutexes when inserting and removing + // things, but for correctness we should have a multiple-readers + // single-writer style lock since concurrent reads and writes can also + // be unsafe. sockets.host_vst_control.receive_messages( std::nullopt, overload{ @@ -61,7 +72,8 @@ void Vst3Bridge::run() { component_instances[instance_id] = std::move(component); return YaComponent::ConstructArgs( - component_instances[instance_id], instance_id); + component_instances[instance_id].component, + instance_id); } else { // The actual result is lost here return UniversalTResult(Steinberg::kNotImplemented); @@ -69,15 +81,8 @@ void Vst3Bridge::run() { }, [&](const YaComponent::Destruct& request) -> YaComponent::Destruct::Response { - std::scoped_lock lock( - component_instances_mutex, - component_host_application_context_instance_mutex); + std::lock_guard lock(component_instances_mutex); component_instances.erase(request.instance_id); - if (component_host_application_context_instances.contains( - request.instance_id)) { - component_host_application_context_instances.erase( - request.instance_id); - } return Ack{}; }, @@ -88,40 +93,39 @@ void Vst3Bridge::run() { // be cleaned up again during `YaComponent::Destruct`. Steinberg::FUnknown* context = nullptr; if (request.host_application_context_args) { - // TODO: Is this safe? These Steinberg smart pointers are - // scary - component_host_application_context_instances - [request.instance_id] = - Steinberg::owned(new YaHostApplicationHostImpl( - *this, - std::move( - *request.host_application_context_args))); - context = component_host_application_context_instances - [request.instance_id]; + component_instances[request.instance_id] + .hsot_application_context = + Steinberg::owned(new YaHostApplicationHostImpl( + *this, + std::move(*request.host_application_context_args))); + context = component_instances[request.instance_id] + .hsot_application_context; } - return component_instances[request.instance_id]->initialize( - context); + return component_instances[request.instance_id] + .component->initialize(context); }, [&](const YaComponent::Terminate& request) -> YaComponent::Terminate::Response { - return component_instances[request.instance_id]->terminate(); + return component_instances[request.instance_id] + .component->terminate(); }, [&](const YaComponent::SetIoMode& request) -> YaComponent::SetIoMode::Response { - return component_instances[request.instance_id]->setIoMode( - request.mode); + return component_instances[request.instance_id] + .component->setIoMode(request.mode); }, [&](const YaComponent::GetBusCount& request) -> YaComponent::GetBusCount::Response { - return component_instances[request.instance_id]->getBusCount( - request.type, request.dir); + return component_instances[request.instance_id] + .component->getBusCount(request.type, request.dir); }, [&](YaComponent::GetBusInfo& request) -> YaComponent::GetBusInfo::Response { const tresult result = - component_instances[request.instance_id]->getBusInfo( - request.type, request.dir, request.index, request.bus); + component_instances[request.instance_id] + .component->getBusInfo(request.type, request.dir, + request.index, request.bus); return YaComponent::GetBusInfoResponse{ .result = result, .updated_bus = request.bus}; diff --git a/src/wine-host/bridges/vst3.h b/src/wine-host/bridges/vst3.h index b871155a..fc1e4106 100644 --- a/src/wine-host/bridges/vst3.h +++ b/src/wine-host/bridges/vst3.h @@ -24,6 +24,34 @@ #include "../../common/configuration.h" #include "common.h" +/** + * A holder for an `IComponent` instance created from the factory along with any + * host context proxy objects belonging to it, and several predefined + * `FUnknownPtrs` so we don't have to do these dynamic casts all the times.. + */ +struct ComponentInstance { + ComponentInstance(); + + ComponentInstance(Steinberg::IPtr component); + + /** + * If the host passes an `IHostApplication` during + * `IPluginBase::initialize()`, we'll store a proxy object here and then + * pass it to `component->initialize()`. + */ + Steinberg::IPtr hsot_application_context; + + /** + * The `IComponent` instance we created. + */ + Steinberg::IPtr component; + + // All smart pointers below are created from `component`. They will be null + // pointers if `component` did not implement the interface. + + // TODO: Implement things like `IConnectionPoint` and `IAudioProcessor` +}; + /** * This hosts a Windows VST3 plugin, forwards messages sent by the Linux VST * plugin and provides host callback function for the plugin to talk back. @@ -112,22 +140,6 @@ class Vst3Bridge : public HostBridge { // instances. The mutexes are used for operations that insert or remove // items, and not for regular access. - std::map> - component_instances; + std::map component_instances; std::mutex component_instances_mutex; - - /** - * If an `IHostApplication` was passed during - * `{IPluginBase,IComponent}::initialize()`, then we'll store a proxy object - * here. The instance ID is the same as the corresponding instance ID in - * `component_instances`. When an instance gets removed from - * `component_instances`, it should also be removed from here. - * - * XXX: If it turns out we need to keep track of more of these kinds of - * objects, then we should create a wrapper so that everything can stay - * in `component_instances` - */ - std::map> - component_host_application_context_instances; - std::mutex component_host_application_context_instance_mutex; };