From ca713ada4e0f2d32989ee7ff8548cd2fb21a4c78 Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Sun, 1 Mar 2020 00:18:00 +0100 Subject: [PATCH] Factor out sending and passing through events Since we can use this both for the dispatch function and for host callbacks. --- src/common/communication.h | 88 ++++++++++++++++++++++++++++++++++++++ src/plugin/bridge.cpp | 16 +------ src/wine-host/bridge.cpp | 35 +-------------- 3 files changed, 90 insertions(+), 49 deletions(-) diff --git a/src/common/communication.h b/src/common/communication.h index 092464e5..c51bf4c4 100644 --- a/src/common/communication.h +++ b/src/common/communication.h @@ -21,8 +21,10 @@ #include #include #include +#include #include +#include #include #include #include @@ -156,3 +158,89 @@ inline T read_object(Socket& socket) { return object; } + +/** + * Serialize and send an event over a socket. This is used for both the host -> + * plugin 'dispatch' events and the plugin -> host 'audioMaster' host callbacks + * since they follow the same format. See one of those functions for details on + * the parameters and return value of this function. + * + * @relates passthrough_event + */ +intptr_t send_event(boost::asio::local::stream_protocol::socket& socket, + int32_t opcode, + int32_t index, + intptr_t value, + void* data, + float option) { + auto payload = + data == nullptr + ? std::nullopt + : std::make_optional(std::string(static_cast(data))); + + const Event event{opcode, index, value, option, payload}; + write_object(socket, event); + + const auto response = read_object(socket); + if (response.data.has_value()) { + std::copy(response.data->begin(), response.data->end(), + static_cast(data)); + } + + return response.return_value; +} + +/** + * Receive an event from a socket and pass it through to some callback function. + * This is used for both the host -> plugin 'dispatch' events and the plugin -> + * host 'audioMaster' host callbacks. This callback function is either one of + * those functions. + * + * @param socket The socket to receive on and to send the response back to. + * @param plugin The `AEffect` instance that should be passed to the callback + * function. + * @param callback The function to call with the arguments received from the + * socket. + * + * @relates send_event + */ +template +void passthrough_event(boost::asio::local::stream_protocol::socket& socket, + AEffect* plugin, + F callback) { + // TODO: Reuse buffers + std::array buffer; + + auto event = read_object(socket); + + // The void pointer argument for the dispatch function is used for + // either: + // - Not at all, in which case it will be a null pointer + // - For passing strings as input to the event + // - For providing a buffer for the event to write results back into + char* payload = nullptr; + if (event.data.has_value()) { + // If the data parameter was an empty string, then we're going to + // pass a larger buffer to the dispatch function instead.. + if (!event.data->empty()) { + payload = const_cast(event.data->c_str()); + } else { + payload = buffer.data(); + } + } + + const intptr_t return_value = callback(plugin, event.opcode, event.option, + event.index, payload, event.option); + + // Only write back the value from `payload` if we were passed an empty + // buffer to write into + bool is_updated = event.data.has_value() && event.data->empty(); + + if (is_updated) { + EventResult response{return_value, payload}; + write_object(socket, response); + } else { + EventResult response{return_value, std::nullopt}; + write_object(socket, response); + } +} diff --git a/src/plugin/bridge.cpp b/src/plugin/bridge.cpp index e326311a..bf42911d 100644 --- a/src/plugin/bridge.cpp +++ b/src/plugin/bridge.cpp @@ -96,21 +96,7 @@ intptr_t Bridge::dispatch(AEffect* /*plugin*/, break; } - auto payload = - data == nullptr - ? std::nullopt - : std::make_optional(std::string(static_cast(data))); - - const Event event{opcode, index, value, option, payload}; - write_object(host_vst_dispatch, event); - - const auto response = read_object(host_vst_dispatch); - if (response.data.has_value()) { - std::copy(response.data->begin(), response.data->end(), - static_cast(data)); - } - - return response.return_value; + return send_event(host_vst_dispatch, opcode, index, value, data, option); } void Bridge::process(AEffect* /*plugin*/, diff --git a/src/wine-host/bridge.cpp b/src/wine-host/bridge.cpp index fbe711ba..a34d8400 100644 --- a/src/wine-host/bridge.cpp +++ b/src/wine-host/bridge.cpp @@ -85,41 +85,8 @@ Bridge::Bridge(std::string plugin_dll_path, std::string socket_endpoint_path) // sockets. Also extract this functionality somewhere since the host event // callback needs to do exactly the same thing. void Bridge::dispatch_loop() { - std::array buffer; while (true) { - auto event = read_object(host_vst_dispatch); - - // The void pointer argument for the dispatch function is used for - // either: - // - Not at all, in which case it will be a null pointer - // - For passing strings as input to the event - // - For providing a buffer for the event to write results back into - char* payload = nullptr; - if (event.data.has_value()) { - // If the data parameter was an empty string, then we're going to - // pass a larger buffer to the dispatch function instead.. - if (!event.data->empty()) { - payload = const_cast(event.data->c_str()); - } else { - payload = buffer.data(); - } - } - - const intptr_t return_value = - plugin->dispatcher(plugin, event.opcode, event.option, event.index, - payload, event.option); - - // Only write back the value from `payload` if we were passed an empty - // buffer to write into - bool is_updated = event.data.has_value() && event.data->empty(); - - if (is_updated) { - EventResult response{return_value, payload}; - write_object(host_vst_dispatch, response); - } else { - EventResult response{return_value, std::nullopt}; - write_object(host_vst_dispatch, response); - } + passthrough_event(host_vst_dispatch, plugin, plugin->dispatcher); } }