Use a thread for dispatch events

This commit is contained in:
Robbert van der Helm
2020-03-05 16:29:59 +01:00
parent 6c4dca151b
commit 814a3b40b5
6 changed files with 45 additions and 37 deletions
+3 -3
View File
@@ -84,9 +84,9 @@ follows:
3. The plugin then sets up a Unix domain socket endpoint to communicate with the
Wine VST host somewhere in a temporary directory. I chose to use Unix domain
sockets rather than shared memory to avoid having to do manual
synchronization and because it makes it easy to handle different kinds of
events asynchronously. Since the Wine VST host can't access the Linux VST
host's memory we would have to copy audio buffers in either case.
synchronization and because they have very low overhead. Since the Wine VST
host can't access the Linux VST host's memory we would have to copy audio
buffers in either case.
4. The plugin launches the Wine VST host in the detected wine prefix, passing
the name of the `.dll` file it should be loading and the path to the Unix
domain socket that was just created.
+9 -13
View File
@@ -95,10 +95,15 @@ HostBridge::HostBridge(audioMasterCallback host_callback)
plugin.getParameter = getParameter_proxy;
plugin.processReplacing = process_replacing_proxy;
// TODO: Replace manual thread creation with an async_read loop
// Start accepting host callbacks after we've set up our sockets and basic
// `AEffect` struct.
removeme = std::thread([&]() { return host_callback_loop(); });
// For our communication we use simple threads and blocking operations
// instead of asynchronous IO since communication has to be handled in
// lockstep anyway
host_callback_handler = std::thread([&]() {
while (true) {
passthrough_event(vst_host_callback, &plugin,
host_callback_function);
}
});
// Read the plugin's information from the Wine process. This can only be
// done after we started accepting host callbacks as the plugin might do
@@ -261,15 +266,6 @@ fs::path generate_endpoint_name() {
return candidate_endpoint;
}
// TODO: Replace blocking loop with async readers or threads for all of the
// sockets. Also extract this functionality somewhere since the host event
// callback needs to do exactly the same thing.
void HostBridge::host_callback_loop() {
while (true) {
passthrough_event(vst_host_callback, &plugin, host_callback_function);
}
}
/**
* Locate the wineprefix and set the `WINEPREFIX` environment variable if found.
* This way it's also possible to run .dll files outside of a wineprefix using
+5 -6
View File
@@ -21,7 +21,6 @@
#include <boost/asio/io_context.hpp>
#include <boost/asio/local/stream_protocol.hpp>
#include <boost/process/child.hpp>
// TODO: Remove
#include <thread>
/**
@@ -67,9 +66,6 @@ class HostBridge {
void set_parameter(AEffect* plugin, int32_t index, float value);
float get_parameter(AEffect* plugin, int32_t index);
// TODO: Remove debug loop
void host_callback_loop();
/**
* This AEffect struct will be populated using the data passed by the Wine
* VST host during initialization and then passed as a pointer to the Linux
@@ -96,12 +92,15 @@ class HostBridge {
*/
boost::asio::local::stream_protocol::socket vst_host_aeffect;
/**
* The thread that handles host callbacks.
*/
std::thread host_callback_handler;
/**
* The callback function passed by the host to the VST plugin instance.
*/
audioMasterCallback host_callback_function;
// TODO: Remove
std::thread removeme;
/**
* The Wine process hosting the Windows VST plugin.
*/
+11 -7
View File
@@ -108,15 +108,19 @@ PluginBridge::PluginBridge(std::string plugin_dll_path,
// We only needed this little hack during initialization
current_bridge_isntance = nullptr;
plugin->ptr1 = this;
// For our communication we use simple threads and blocking operations
// instead of asynchronous IO since communication has to be handled in
// lockstep anyway
dispatch_handler = std::thread([&]() {
while (true) {
passthrough_event(host_vst_dispatch, plugin, plugin->dispatcher);
}
});
}
// TODO: Replace blocking loop with async readers or threads for all of the
// sockets. Also extract this functionality somewhere since the host event
// callback needs to do exactly the same thing.
void PluginBridge::dispatch_loop() {
while (true) {
passthrough_event(host_vst_dispatch, plugin, plugin->dispatcher);
}
void PluginBridge::wait() {
dispatch_handler.join();
}
intptr_t PluginBridge::host_callback(AEffect* /*plugin*/,
+14 -5
View File
@@ -24,6 +24,8 @@
#include <vestige/aeffect.h>
#include <windows.h>
#include <thread>
/**
* This handles the communication between the Linux native VST plugin and the
* Wine VST host. The functions below should be used as callback functions in an
@@ -45,13 +47,13 @@ class PluginBridge {
*/
PluginBridge(std::string plugin_dll_path, std::string socket_endpoint_path);
/**
* Block the main thread until the plugin shuts down.
*/
void wait();
intptr_t host_callback(AEffect*, int32_t, int32_t, intptr_t, void*, float);
// TODO: Remove debug loop
void dispatch_loop();
// TODO: Set up all callback handlers
private:
/**
* The shared library handle of the VST plugin. I sadly could not get
@@ -82,4 +84,11 @@ class PluginBridge {
* pass the Wine plugin's information to the host.
*/
boost::asio::local::stream_protocol::socket vst_host_aeffect;
/**
* The thread that handles dispatch events from the host.
*/
std::thread dispatch_handler;
// TODO: Set up all other callback handlers
};
+3 -3
View File
@@ -33,10 +33,10 @@ int main(int argc, char* argv[]) {
const std::string socket_endpoint_path(argv[2]);
try {
PluginBridge Pluginbridge(plugin_dll_path, socket_endpoint_path);
PluginBridge bridge(plugin_dll_path, socket_endpoint_path);
// TODO: Remove debug
Pluginbridge.dispatch_loop();
// Block the main thread until the plugin shuts down
bridge.wait();
} catch (const std::runtime_error& error) {
std::cerr << "Error while initializing plugin:" << std::endl;
std::cerr << error.what() << std::endl;