Replace msgpack with bitsery

This commit is contained in:
Robbert van der Helm
2020-02-26 22:17:05 +01:00
parent 5b07941986
commit cd5b294952
5 changed files with 77 additions and 32 deletions
+6 -6
View File
@@ -13,7 +13,6 @@ There are a few things that should be done before making this public, including:
rewrite some parts of it to make it clearer. rewrite some parts of it to make it clearer.
- Document what this has been tested on and what does or does not work. - Document what this has been tested on and what does or does not work.
- Document wine32 support. - Document wine32 support.
- Swap out msgpack for bitsery and update the architecture section.
- Forward audio events. - Forward audio events.
- Forward host callback calls back to the native VST host. - Forward host callback calls back to the native VST host.
- Forward the values from the Windows VST plugin's `AEffect` struct. - Forward the values from the Windows VST plugin's `AEffect` struct.
@@ -31,7 +30,10 @@ the following dependencies:
- gcc (tested using GCC 9.2) - gcc (tested using GCC 9.2)
- A Wine installation with `wiengcc` and the development headers. - A Wine installation with `wiengcc` and the development headers.
- Boost - Boost
- [msgpack-c](git@github.com:msgpack/msgpack-c.git)
The following dependencies are included as a Meson wrap:
- bitsery
The project can then be compiled as follows: The project can then be compiled as follows:
@@ -104,15 +106,13 @@ follows:
- Calls from the native VST host to the plugin's `process()` and - Calls from the native VST host to the plugin's `process()` and
`processReplacing()` functions. Both functions get forwarded to the Windows `processReplacing()` functions. Both functions get forwarded to the Windows
VST plugin through the Wine VST host using a single socket. VST plugin through the Wine VST host using a single socket.
- TODO: This is missing updates to the AEffect struct.
The first step when passing through any of these function calls over a socket The first step when passing through any of these function calls over a socket
is to serialize the function's parameters as binary data. Both request and is to serialize the function's parameters as binary data. Both request and
the corresponding response objects for all of these function calls can be the corresponding response objects for all of these function calls can be
found in `src/common/communication.h`, along with functions to read and write found in `src/common/communication.h`, along with functions to read and write
these objects over streams and sockets. Right now we're using `msgpack`, but these objects over streams and sockets. The actual binary serialization is
this should be switched out for [bitsery](https://github.com/fraillt/bitsery) handled using [bitsery](https://github.com/fraillt/bitsery).
for lower overhead serialization.
6. The Wine VST host loads the Windows VST plugin and starts forwarding messages 6. The Wine VST host loads the Windows VST plugin and starts forwarding messages
over the sockets described above. over the sockets described above.
+2 -3
View File
@@ -22,7 +22,6 @@ endif
boost_dep = dependency('boost', modules : ['filesystem']) boost_dep = dependency('boost', modules : ['filesystem'])
bitsery_dep = subproject('bitsery').get_variable('bitsery_dep') bitsery_dep = subproject('bitsery').get_variable('bitsery_dep')
msgpack_dep = dependency('msgpack')
threads_dep = dependency('threads') threads_dep = dependency('threads')
# The built in threads dependency does not know how to handle winegcc # The built in threads dependency does not know how to handle winegcc
wine_threads_dep = declare_dependency(link_args : '-lpthread') wine_threads_dep = declare_dependency(link_args : '-lpthread')
@@ -37,7 +36,7 @@ shared_library(
], ],
native : true, native : true,
include_directories : include_dir, include_directories : include_dir,
dependencies : [boost_dep, bitsery_dep, msgpack_dep, threads_dep], dependencies : [boost_dep, bitsery_dep, threads_dep],
link_args : ['-ldl'] link_args : ['-ldl']
) )
@@ -48,6 +47,6 @@ executable(
], ],
native : false, native : false,
include_directories : include_dir, include_directories : include_dir,
dependencies : [boost_dep, bitsery_dep, msgpack_dep, wine_threads_dep], dependencies : [boost_dep, bitsery_dep, wine_threads_dep],
link_args : [] link_args : []
) )
+66 -20
View File
@@ -16,10 +16,15 @@
#pragma once #pragma once
#include <bitsery/adapter/buffer.h>
#include <bitsery/bitsery.h>
#include <bitsery/ext/std_optional.h>
#include <bitsery/traits/array.h>
#include <bitsery/traits/string.h>
#include <boost/asio/buffer.hpp> #include <boost/asio/buffer.hpp>
#include <cinttypes> #include <cinttypes>
#include <iostream> #include <iostream>
#include <msgpack.hpp>
#include <optional> #include <optional>
/** /**
@@ -29,6 +34,25 @@
*/ */
constexpr size_t max_string_length = 128; constexpr size_t max_string_length = 128;
/**
* The buffer size in bytes used for all buffers for sending and recieving
* messages.
*
* TODO: This should probably depend on the type. 512 bytes is way too much for
* events, and probably not enough for sending audio.
*/
constexpr size_t buffer_size = 512;
// Types used for serialization and deserialization with bitsery.
template <std::size_t N>
using Buffer = std::array<u_int8_t, N>;
template <std::size_t N>
using OutputAdapter = bitsery::OutputBufferAdapter<Buffer<N>>;
template <std::size_t N>
using InputAdapter = bitsery::InputBufferAdapter<Buffer<N>>;
/** /**
* An event as dispatched by the VST host. These events will get forwarded to * An event as dispatched by the VST host. These events will get forwarded to
* the VST host process running under Wine. The fields here mirror those * the VST host process running under Wine. The fields here mirror those
@@ -49,7 +73,18 @@ struct Event {
*/ */
std::optional<std::string> data; std::optional<std::string> data;
MSGPACK_DEFINE(opcode, index, value, option, data) template <typename S>
void serialize(S& s) {
s.value4b(opcode);
s.value4b(index);
// Hard coding pointer sizes to 8 bytes should be fine, right? Even if
// we're hosting a 32 bit plugin the native VST plugin will still use 64
// bit large pointers.
s.value8b(value);
s.value4b(option);
s.ext(data, bitsery::ext::StdOptional(),
[](S& s, auto& v) { s.text1b(v, max_string_length); });
}
}; };
/** /**
@@ -68,15 +103,18 @@ struct EventResult {
// TODO: Add missing return value fields; // TODO: Add missing return value fields;
MSGPACK_DEFINE(return_value, data) template <typename S>
void serialize(S& s) {
s.value8b(return_value);
s.ext(data, bitsery::ext::StdOptional(),
[](S& s, auto& v) { s.text1b(v, max_string_length); });
}
}; };
/** /**
* Serialize an object and write it to a stream. This function prefixes the * Serialize an object using bitsery and write it to a socket.
* output with the length of the serialized object in bytes since msgpack
* doesn't handle this on its own.
* *
* @param stream An ostream that can be written to. * @param socket The Boost.Asio socket to write to.
* @param object The object to write to the stream. * @param object The object to write to the stream.
* *
* @relates read_object * @relates read_object
@@ -84,29 +122,37 @@ struct EventResult {
template <typename T, typename Socket> template <typename T, typename Socket>
inline void write_object(Socket& socket, const T& object) { inline void write_object(Socket& socket, const T& object) {
// TODO: Reuse buffers // TODO: Reuse buffers
// TODO: Use boost's buffers directly after switching to bitsery Buffer<buffer_size> buffer;
msgpack::sbuffer buffer; auto length =
msgpack::pack(buffer, object); bitsery::quickSerialization<OutputAdapter<buffer_size>>(buffer, object);
socket.send(boost::asio::buffer(buffer.data(), buffer.size())); socket.send(boost::asio::buffer(buffer, length));
} }
/** /**
* Deserialize an object by reading it from a stream. This should be used * Deserialize an object by reading it from a socket. This should be used
* together with `write_object`. This will block until the object is * together with `write_object`. This will block until the object is available.
available.
* *
* @param stream The stream to read from. * @param socket The Boost.Asio socket to read from.
* @throw msgpack::type_error If the conversion to an object was not successful. * @throw std::runtime_error If the conversion to an object was not successful.
* *
* @relates write_object * @relates write_object
*/ */
template <typename T, typename Socket> template <typename T, typename Socket>
inline T read_object(Socket& socket) { inline T read_object(Socket& socket) {
// TODO: Reuse buffers, also this is way too large right now // TODO: Reuse buffers
// TODO: Use boost's buffers directly after switching to bitsery Buffer<buffer_size> buffer;
char buffer[4096];
auto message_length = socket.receive(boost::asio::buffer(buffer)); auto message_length = socket.receive(boost::asio::buffer(buffer));
return msgpack::unpack(buffer, message_length).get().convert(); T object;
auto [_, success] =
bitsery::quickDeserialization<InputAdapter<buffer_size>>(
{buffer.begin(), message_length}, object);
if (!success) {
throw std::runtime_error("Deserialization failure in call:" +
std::string(__PRETTY_FUNCTION__));
}
return object;
} }
-1
View File
@@ -22,7 +22,6 @@
#include <boost/process/io.hpp> #include <boost/process/io.hpp>
#include <boost/process/search_path.hpp> #include <boost/process/search_path.hpp>
#include <iostream> #include <iostream>
#include <msgpack.hpp>
#include <random> #include <random>
#include "../common/communication.h" #include "../common/communication.h"
+3 -2
View File
@@ -16,7 +16,7 @@
#pragma once #pragma once
// Libraries like Boost and msgpack think we're compiling on Windows or using a // Libraries like Boost and bitsery think we're compiling on Windows or using a
// MSVC toolchain. This will cause them to make assumptions about the way // MSVC toolchain. This will cause them to make assumptions about the way
// certain types are defined, which headers are available and which features to // certain types are defined, which headers are available and which features to
// disable (i.e. POSIX specific features). The only way around this I could // disable (i.e. POSIX specific features). The only way around this I could
@@ -34,10 +34,11 @@
#undef __WIN32__ #undef __WIN32__
#undef _WIN64 #undef _WIN64
#include <bitsery/bitsery.h>
#include <boost/algorithm/string/predicate.hpp> #include <boost/algorithm/string/predicate.hpp>
#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 <msgpack.hpp>
#pragma pop_macro("WIN32") #pragma pop_macro("WIN32")
#pragma pop_macro("_WIN32") #pragma pop_macro("_WIN32")