diff --git a/meson.build b/meson.build index 3107b85f..9570903f 100644 --- a/meson.build +++ b/meson.build @@ -20,7 +20,9 @@ endif # about the way these two components work together can be found in the readme # file. -boost_dep = dependency('boost', modules : ['filesystem']) +# Boost 1.72 has a known bug in Boost.Process that will cause compilation to +# fail, see https://github.com/boostorg/process/issues/116 +boost_dep = dependency('boost', version : '!=1.72', modules : ['filesystem']) bitsery_dep = subproject('bitsery').get_variable('bitsery_dep') threads_dep = dependency('threads') # The built in threads dependency does not know how to handle winegcc diff --git a/src/plugin/host-bridge.cpp b/src/plugin/host-bridge.cpp index 68dc88c9..7af5948b 100644 --- a/src/plugin/host-bridge.cpp +++ b/src/plugin/host-bridge.cpp @@ -16,6 +16,7 @@ #include "host-bridge.h" +#include #include #include #include @@ -80,12 +81,16 @@ HostBridge::HostBridge(audioMasterCallback host_callback) host_callback_function(host_callback), logger(Logger::create_from_environment( create_logger_prefix(socket_endpoint.path()))), + wine_stdout(io_context), + wine_stderr(io_context), vst_host(vst_host_path, // The Wine VST host needs to know which plugin to load // and which Unix domain socket to connect to vst_plugin_path, socket_endpoint.path(), - bp::env = set_wineprefix()), + bp::env = set_wineprefix(), + bp::std_out = wine_stdout, + bp::std_err = wine_stderr), process_buffer(std::make_unique()) { logger.log("Initializing yabridge using '" + vst_host_path.string() + "'"); logger.log("plugin: '" + vst_plugin_path.string() + "'"); @@ -119,6 +124,12 @@ HostBridge::HostBridge(audioMasterCallback host_callback) } }); + wine_io_handler = std::thread([&]() { io_context.run(); }); + + // Print the Wine host's STDOUT and STDERR streams to the log file + async_log_pipe_lines(wine_stdout, wine_stdout_buffer, "[Wine STDOUT] "); + async_log_pipe_lines(wine_stderr, wine_stderr_buffer, "[Wine STDERR] "); + // 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 // this during initialization. @@ -207,6 +218,19 @@ float HostBridge::get_parameter(AEffect* /*plugin*/, int32_t index) { return response.value.value(); } +void HostBridge::async_log_pipe_lines(bp::async_pipe& pipe, + boost::asio::streambuf& buffer, + std::string prefix) { + boost::asio::async_read_until( + pipe, buffer, '\n', [&, prefix](const auto&, size_t) { + std::string line; + std::getline(std::istream(&buffer), line); + logger.log(prefix + line); + + async_log_pipe_lines(pipe, buffer, prefix); + }); +} + /** * Create a logger prefix based on the unique socket path for easy * identification. The socket path contains both the plugin's name and a unique diff --git a/src/plugin/host-bridge.h b/src/plugin/host-bridge.h index 08648df7..6ade645d 100644 --- a/src/plugin/host-bridge.h +++ b/src/plugin/host-bridge.h @@ -20,6 +20,8 @@ #include #include +#include +#include #include #include @@ -86,6 +88,18 @@ class HostBridge { AEffect plugin; private: + /** + * Write output from an async pipe to the log on a line by line basis. + * Useful for logging the Wine process's STDOUT and STDERR streams. + * + * @param pipe The pipe to read from. + * @param buffer The stream buffer to write to. + * @param prefix Text to prepend to the line before writing to the log. + */ + void async_log_pipe_lines(boost::process::async_pipe& pipe, + boost::asio::streambuf& buffer, + std::string prefix = ""); + boost::asio::io_context io_context; boost::asio::local::stream_protocol::endpoint socket_endpoint; boost::asio::local::stream_protocol::acceptor socket_acceptor; @@ -117,12 +131,28 @@ class HostBridge { * The thread that handles host callbacks. */ std::thread host_callback_handler; + /** + * Runs the Boost.Asio `io_context` thread for logging the Wine process + * STDOUT and STDERR messages. + */ + std::thread wine_io_handler; /** * The callback function passed by the host to the VST plugin instance. */ audioMasterCallback host_callback_function; Logger logger; + + boost::asio::streambuf wine_stdout_buffer; + boost::asio::streambuf wine_stderr_buffer; + /** + * The STDOUT stream of the Wine process we can forward to the logger. + */ + boost::process::async_pipe wine_stdout; + /** + * The STDERR stream of the Wine process we can forward to the logger. + */ + boost::process::async_pipe wine_stderr; /** * The Wine process hosting the Windows VST plugin. */