Document the plugin factory approach

This commit is contained in:
Robbert van der Helm
2020-12-08 14:21:54 +01:00
parent ed743e6f22
commit f4a5aa91fb
3 changed files with 39 additions and 28 deletions
+31 -1
View File
@@ -50,7 +50,37 @@ instantiated and managed by the host. The model works as follows:
## Plugin Factory
TODO: Explain how we implement `createInstance()`, based on the todo comment there.
Creating a new instance of an interface using the plugin factory wroks as
follows:
1. The host calls `createInterface(cid, _iid, obj)` on an IPluginFactory
implementation exposed to the host as described above.
2. We check which interface we support matches the `_iid`. If we don't support
the interface, we'll log a message about it and return that we do not support
the itnerface.
3. If we determine that `_iid` matches `IFoo`, then we'll send a
`YaFoo::Create{cid}` to the Wine plugin host process.
4. The Wine plugin host will then call
`module->getFactory().createInstance<IFoo>(cid)` using the Windows VST3
plugin's plugin factory to ask it to create an instance of that interface. If
this operation fails and returns a null pointer, we'll send an `std::nullopt`
back to indicate that the instantiation was not successful and we relay this
on the plugin side.
5. Using the newly created instance (which will be returned by the factory as an
`IPtr<IFoo>`), we will instantiate a `YaFoo` object using `YaFooHostImpl`.
This will read all simple data members from the `IFoo` smart pointer just
like described in the above section. The `YaFoo` object will also gen a
unique identifier which we generate on the Wine side using an atomic
fetch-and-add on a counter. This way we can refer to this specific isntance
when doing callbacks.
6. Still on the Wine side of things, the `IPtr<IFoo>` will be moved to an
`std::map<size_t, IPtr<IFoo>>` with that unique identifier we generated
earlier as a key so we can refer to it later.
7. Finally on the plugin side we will create an `YaFooPluginImpl` object that
can send control messages to the Wine plugin host, and then we'll deserialize
the `YaFoo` object we receive into that.
8. A pointer to this `YaFooPluginImpl` then gets returned as the final step of
the initialization process.
## Safety notes
+7 -1
View File
@@ -41,6 +41,8 @@ class YaComponent : public Steinberg::Vst::IComponent {
* ...)`.
*/
struct Create {
// TODO: This should be `std::optional<YaComponent>`, and we need a way
// to deserialize that into an existing YaComponent.
using Response = YaComponent&;
Steinberg::TUID cid;
@@ -58,7 +60,11 @@ class YaComponent : public Steinberg::Vst::IComponent {
*/
explicit YaComponent(Steinberg::IPtr<Steinberg::Vst::IComponent> component);
virtual ~YaComponent();
/**
* @remark The plugin side implementation should send a control message to
* clean up the instance on the Wine side in its destructor.
*/
virtual ~YaComponent() = 0;
DECLARE_FUNKNOWN_METHODS
+1 -26
View File
@@ -25,32 +25,7 @@ tresult PLUGIN_API
YaPluginFactoryPluginImpl::createInstance(Steinberg::FIDString cid,
Steinberg::FIDString _iid,
void** obj) {
// TODO: This should:
// 1. Check which interface `_iid` belongs to. Let's call this
// interface `T`. If we do not (yet) support it, then we should log
// it and return `Steinberg::kNotImplemented`.
// 2. Send a control message to the Wine plugin host to instantiate a
// new object of type `T` with `cid` and `_iid` as parameters.
// 3. On the Wine side this calls `createIntance()` on the module's
// factory with thsoe same `cid` and `_iid` arguments.
// 4. It this was successful, we'll assign this object a unique number
// (by just doing a fetch-and-add on an atomic size_t) so we can
// refer to it and add it to an `std::map<size_t, IP tr<T>`, where
// `T` is the _original_ object (we don't have to and shouldn't
// wrap it).
// 5. We'll copy over any payload data into a `YaT` **which includes
// that unique identifier we generated** and send it back to the
// plugin.
// 6. On the plugin's side we'll create a new `YaTPluginImpl` inside
// of a VST smart pointer and deserialize the `YaT` we got sent
// into that. We then write that smart pointer into `obj`. We don't
// have to keep track of these objects on the plugin side and the
// reference counting pointers will cause everything to clean up
// after itself.
// 7. Since those `YaTPluginImpl` objects we'll return from
// `createInstance()` will have a reference to `Vst3PluginBridge`,
// they can also send control messages themselves.
// TODO: Implement as specified in `src/common/serialization/vst3/README.md`
if (Steinberg::FIDStringsEqual(_iid, Steinberg::Vst::IComponent::iid)) {
// TODO: Instantiate an IComponent as described above
return Steinberg::kNotImplemented;