mirror of
https://github.com/robbert-vdh/yabridge.git
synced 2026-05-10 04:30:12 +02:00
Handle dispatch() directly during event handling
When the message loop is active and we get an incoming dispatch() event, we'll just handle it directly. In practice this would only be needed when the event is a response to an `audioMaster()` call made during the event loop, but we can't know that. This allows the `getProgram()` during `audioMasterUpdateDisplay()` in REAPER and Renoise to work correctly. Hopefully this doesn't cause random rare breakage.
This commit is contained in:
@@ -29,11 +29,6 @@ namespace fs = boost::filesystem;
|
||||
|
||||
using namespace std::literals::chrono_literals;
|
||||
|
||||
/**
|
||||
* The delay between calls to the event loop at a more than cinematic 30 fps.
|
||||
*/
|
||||
constexpr std::chrono::duration event_loop_interval = 1000ms / 30;
|
||||
|
||||
/**
|
||||
* Listen on the specified endpoint if no process is already listening there,
|
||||
* otherwise throw. This is needed to handle these three situations:
|
||||
@@ -94,10 +89,9 @@ GroupBridge::GroupBridge(boost::filesystem::path group_socket_path)
|
||||
stdout_redirect(stdio_context, STDOUT_FILENO),
|
||||
stderr_redirect(stdio_context, STDERR_FILENO),
|
||||
group_socket_endpoint(group_socket_path.string()),
|
||||
group_socket_acceptor(
|
||||
create_acceptor_if_inactive(plugin_context, group_socket_endpoint)),
|
||||
events_timer(plugin_context),
|
||||
shutdown_timer(plugin_context) {
|
||||
group_socket_acceptor(create_acceptor_if_inactive(plugin_context.context,
|
||||
group_socket_endpoint)),
|
||||
shutdown_timer(plugin_context.context) {
|
||||
// Write this process's original STDOUT and STDERR streams to the logger
|
||||
// TODO: This works for output generated by plugins, but not for debug
|
||||
// messages generated by wineserver. Is it possible to catch those?
|
||||
@@ -131,7 +125,7 @@ void GroupBridge::handle_plugin_dispatch(size_t plugin_id) {
|
||||
// potentially corrupt our heap. This way we can also properly join the
|
||||
// thread again. If no active plugins remain, then we'll terminate the
|
||||
// process.
|
||||
boost::asio::post(plugin_context, [this, plugin_id]() {
|
||||
boost::asio::post(plugin_context.context, [this, plugin_id]() {
|
||||
std::lock_guard lock(active_plugins_mutex);
|
||||
|
||||
// The join is implicit because we're using std::jthread
|
||||
@@ -240,16 +234,7 @@ void GroupBridge::accept_requests() {
|
||||
}
|
||||
|
||||
void GroupBridge::async_handle_events() {
|
||||
// Try to keep a steady framerate, but add in delays to let other events get
|
||||
// handled if the GUI message handling somehow takes very long.
|
||||
events_timer.expires_at(
|
||||
std::max(events_timer.expiry() + event_loop_interval,
|
||||
std::chrono::steady_clock::now() + 5ms));
|
||||
events_timer.async_wait([&](const boost::system::error_code& error) {
|
||||
if (error.failed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
plugin_context.async_handle_events([&]() {
|
||||
{
|
||||
// Always handle X11 events
|
||||
std::lock_guard lock(active_plugins_mutex);
|
||||
@@ -279,8 +264,6 @@ void GroupBridge::async_handle_events() {
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
|
||||
async_handle_events();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -217,7 +217,7 @@ class GroupBridge {
|
||||
* operations that may involve the Win32 mesasge loop (e.g. initialization
|
||||
* and most `AEffect::dispatcher()` calls) should be run on.
|
||||
*/
|
||||
boost::asio::io_context plugin_context;
|
||||
PluginContext plugin_context;
|
||||
/**
|
||||
* A seperate IO context that handles the STDIO redirect through
|
||||
* `StdIoCapture`. This is seperated the `plugin_context` above so that
|
||||
@@ -279,14 +279,6 @@ class GroupBridge {
|
||||
*/
|
||||
std::mutex active_plugins_mutex;
|
||||
|
||||
/**
|
||||
* A timer used to repeatedly handle the Win32 message loop and the X11
|
||||
* events.
|
||||
*
|
||||
8 @see async_handle_events
|
||||
*/
|
||||
boost::asio::steady_timer events_timer;
|
||||
|
||||
/**
|
||||
* A timer to defer shutting down the process, allowing for fast plugin
|
||||
* scanning without having to start a new group host process for each
|
||||
|
||||
@@ -64,13 +64,13 @@ Vst2Bridge& get_bridge_instance(const AEffect* plugin) {
|
||||
return *static_cast<Vst2Bridge*>(plugin->ptr1);
|
||||
}
|
||||
|
||||
Vst2Bridge::Vst2Bridge(boost::asio::io_context& main_context,
|
||||
Vst2Bridge::Vst2Bridge(PluginContext& main_context,
|
||||
std::string plugin_dll_path,
|
||||
std::string endpoint_base_dir)
|
||||
: vst_plugin_path(plugin_dll_path),
|
||||
io_context(main_context),
|
||||
plugin_context(main_context),
|
||||
plugin_handle(LoadLibrary(plugin_dll_path.c_str()), FreeLibrary),
|
||||
sockets(io_context, endpoint_base_dir, false) {
|
||||
sockets(plugin_context.context, endpoint_base_dir, false) {
|
||||
// Got to love these C APIs
|
||||
if (!plugin_handle) {
|
||||
throw std::runtime_error("Could not load the Windows .dll file at '" +
|
||||
@@ -158,13 +158,14 @@ void Vst2Bridge::handle_dispatch() {
|
||||
// `plugin->dispatcher()` (or `dispatch_wrapper()`)
|
||||
// directly, we'll run the function within the IO context so
|
||||
// all events will be executed on the same thread as the one
|
||||
// that runs the Win32 message loop. We'll assume every
|
||||
// event that comes in while the main thread is already
|
||||
// handling an event in the IO context can safely be handled
|
||||
// on an off thread.
|
||||
if (on_main_thread) {
|
||||
// that runs the Win32 message loop. In some scenarios we'll
|
||||
// receive incoming calls from multiple threads or we'll
|
||||
// receive calls while we're currently stuck in the Win32
|
||||
// message loop. In those cases we'll assume that these
|
||||
// events can be safely handled directlyfrom another thread.
|
||||
if (on_main_thread && !plugin_context.event_loop_active) {
|
||||
std::promise<intptr_t> dispatch_result;
|
||||
boost::asio::dispatch(io_context, [&]() {
|
||||
boost::asio::dispatch(plugin_context.context, [&]() {
|
||||
const intptr_t result = dispatch_wrapper(
|
||||
plugin, opcode, index, value, data, option);
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ class Vst2Bridge {
|
||||
* @throw std::runtime_error Thrown when the VST plugin could not be loaded,
|
||||
* or if communication could not be set up.
|
||||
*/
|
||||
Vst2Bridge(boost::asio::io_context& main_context,
|
||||
Vst2Bridge(PluginContext& main_context,
|
||||
std::string plugin_dll_path,
|
||||
std::string endpoint_base_dir);
|
||||
|
||||
@@ -172,7 +172,7 @@ class Vst2Bridge {
|
||||
* message handling can be performed from a single thread, even when hosting
|
||||
* multiple plugins.
|
||||
*/
|
||||
boost::asio::io_context& io_context;
|
||||
PluginContext& plugin_context;
|
||||
|
||||
/**
|
||||
* The configuration for this instance of yabridge based on the `.so` file
|
||||
|
||||
Reference in New Issue
Block a user