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 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 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 sockets rather than shared memory to avoid having to do manual
synchronization and because it makes it easy to handle different kinds of synchronization and because they have very low overhead. Since the Wine VST
events asynchronously. Since the Wine VST host can't access the Linux VST host can't access the Linux VST host's memory we would have to copy audio
host's memory we would have to copy audio buffers in either case. buffers in either case.
4. The plugin launches the Wine VST host in the detected wine prefix, passing 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 the name of the `.dll` file it should be loading and the path to the Unix
domain socket that was just created. domain socket that was just created.
+9 -13
View File
@@ -95,10 +95,15 @@ HostBridge::HostBridge(audioMasterCallback host_callback)
plugin.getParameter = getParameter_proxy; plugin.getParameter = getParameter_proxy;
plugin.processReplacing = process_replacing_proxy; plugin.processReplacing = process_replacing_proxy;
// TODO: Replace manual thread creation with an async_read loop // For our communication we use simple threads and blocking operations
// Start accepting host callbacks after we've set up our sockets and basic // instead of asynchronous IO since communication has to be handled in
// `AEffect` struct. // lockstep anyway
removeme = std::thread([&]() { return host_callback_loop(); }); 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 // 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 // done after we started accepting host callbacks as the plugin might do
@@ -261,15 +266,6 @@ fs::path generate_endpoint_name() {
return candidate_endpoint; 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. * 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 * 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/io_context.hpp>
#include <boost/asio/local/stream_protocol.hpp> #include <boost/asio/local/stream_protocol.hpp>
#include <boost/process/child.hpp> #include <boost/process/child.hpp>
// TODO: Remove
#include <thread> #include <thread>
/** /**
@@ -67,9 +66,6 @@ class HostBridge {
void set_parameter(AEffect* plugin, int32_t index, float value); void set_parameter(AEffect* plugin, int32_t index, float value);
float get_parameter(AEffect* plugin, int32_t index); 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 * 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 * 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; 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. * The callback function passed by the host to the VST plugin instance.
*/ */
audioMasterCallback host_callback_function; audioMasterCallback host_callback_function;
// TODO: Remove
std::thread removeme;
/** /**
* The Wine process hosting the Windows VST plugin. * 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 // We only needed this little hack during initialization
current_bridge_isntance = nullptr; current_bridge_isntance = nullptr;
plugin->ptr1 = this; 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 void PluginBridge::wait() {
// sockets. Also extract this functionality somewhere since the host event dispatch_handler.join();
// callback needs to do exactly the same thing.
void PluginBridge::dispatch_loop() {
while (true) {
passthrough_event(host_vst_dispatch, plugin, plugin->dispatcher);
}
} }
intptr_t PluginBridge::host_callback(AEffect* /*plugin*/, intptr_t PluginBridge::host_callback(AEffect* /*plugin*/,
+14 -5
View File
@@ -24,6 +24,8 @@
#include <vestige/aeffect.h> #include <vestige/aeffect.h>
#include <windows.h> #include <windows.h>
#include <thread>
/** /**
* This handles the communication between the Linux native VST plugin and the * 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 * 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); 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); 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: private:
/** /**
* The shared library handle of the VST plugin. I sadly could not get * 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. * pass the Wine plugin's information to the host.
*/ */
boost::asio::local::stream_protocol::socket vst_host_aeffect; 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]); const std::string socket_endpoint_path(argv[2]);
try { try {
PluginBridge Pluginbridge(plugin_dll_path, socket_endpoint_path); PluginBridge bridge(plugin_dll_path, socket_endpoint_path);
// TODO: Remove debug // Block the main thread until the plugin shuts down
Pluginbridge.dispatch_loop(); bridge.wait();
} catch (const std::runtime_error& error) { } catch (const std::runtime_error& error) {
std::cerr << "Error while initializing plugin:" << std::endl; std::cerr << "Error while initializing plugin:" << std::endl;
std::cerr << error.what() << std::endl; std::cerr << error.what() << std::endl;