Proper OSC remote control implementation, allowed on standalones

Signed-off-by: falkTX <falktx@falktx.com>
This commit is contained in:
falkTX 2023-07-27 14:01:02 +02:00
parent 0ad791dee0
commit 3d44fb9d79
No known key found for this signature in database
GPG key ID: CDBAA37ABC74FBA0
5 changed files with 192 additions and 34 deletions

View file

@ -63,7 +63,7 @@
# include <unistd.h>
#endif
#ifdef CARDINAL_INIT_OSC_THREAD
#ifdef HAVE_LIBLO
# include <lo/lo.h>
#endif
@ -231,7 +231,7 @@ void CardinalPluginContext::writeMidiMessage(const rack::midi::Message& message,
// -----------------------------------------------------------------------------------------------------------
#ifdef CARDINAL_INIT_OSC_THREAD
#ifdef HAVE_LIBLO
static void osc_error_handler(int num, const char* msg, const char* path)
{
d_stderr("Cardinal OSC Error: code: %i, msg: \"%s\", path: \"%s\")", num, msg, path);
@ -245,9 +245,9 @@ static int osc_fallback_handler(const char* const path, const char* const types,
static int osc_hello_handler(const char*, const char*, lo_arg**, int, const lo_message m, void* const self)
{
d_debug("osc_hello_handler()");
d_stdout("Hello received from OSC, saying hello back to them o/");
const lo_address source = lo_message_get_source(m);
const lo_server server = lo_server_thread_get_server(static_cast<Initializer*>(self)->oscServerThread);
const lo_server server = static_cast<Initializer*>(self)->oscServer;
lo_send_from(source, server, LO_TT_IMMEDIATE, "/resp", "ss", "hello", "ok");
return 0;
}
@ -287,7 +287,7 @@ static int osc_load_handler(const char*, const char* types, lo_arg** argv, int a
}
const lo_address source = lo_message_get_source(m);
const lo_server server = lo_server_thread_get_server(static_cast<Initializer*>(self)->oscServerThread);
const lo_server server = static_cast<Initializer*>(self)->oscServer;
lo_send_from(source, server, LO_TT_IMMEDIATE, "/resp", "ss", "load", ok ? "ok" : "fail");
return 0;
}
@ -344,6 +344,7 @@ static int osc_host_param_handler(const char*, const char* types, lo_arg** argv,
return 0;
}
# ifdef CARDINAL_INIT_OSC_THREAD
static int osc_screenshot_handler(const char*, const char* types, lo_arg** argv, int argc, const lo_message m, void* const self)
{
d_debug("osc_screenshot_handler()");
@ -368,10 +369,11 @@ static int osc_screenshot_handler(const char*, const char* types, lo_arg** argv,
}
const lo_address source = lo_message_get_source(m);
const lo_server server = lo_server_thread_get_server(static_cast<Initializer*>(self)->oscServerThread);
const lo_server server = static_cast<Initializer*>(self)->oscServer;
lo_send_from(source, server, LO_TT_IMMEDIATE, "/resp", "ss", "screenshot", ok ? "ok" : "fail");
return 0;
}
# endif
#endif
// -----------------------------------------------------------------------------------------------------------
@ -575,41 +577,32 @@ Initializer::Initializer(const CardinalBasePlugin* const plugin, const CardinalB
loadSettings(isRealInstance);
#ifdef CARDINAL_INIT_OSC_THREAD
#if defined(CARDINAL_INIT_OSC_THREAD)
INFO("Initializing OSC Remote control");
const char* port;
if (const char* const portEnv = std::getenv("CARDINAL_REMOTE_HOST_PORT"))
port = portEnv;
else
port = CARDINAL_DEFAULT_REMOTE_PORT;
oscServerThread = lo_server_thread_new_with_proto(port, LO_UDP, osc_error_handler);
DISTRHO_SAFE_ASSERT_RETURN(oscServerThread != nullptr,);
lo_server_thread_add_method(oscServerThread, "/hello", "", osc_hello_handler, this);
lo_server_thread_add_method(oscServerThread, "/host-param", "if", osc_host_param_handler, this);
lo_server_thread_add_method(oscServerThread, "/load", "b", osc_load_handler, this);
lo_server_thread_add_method(oscServerThread, "/param", "hif", osc_param_handler, this);
lo_server_thread_add_method(oscServerThread, "/screenshot", "b", osc_screenshot_handler, this);
lo_server_thread_add_method(oscServerThread, nullptr, nullptr, osc_fallback_handler, nullptr);
lo_server_thread_start(oscServerThread);
#else
startRemoteServer(port);
#elif defined(HAVE_LIBLO)
if (isStandalone()) {
INFO("OSC Remote control is available on request");
} else {
INFO("OSC Remote control is not available on plugin variants");
}
#else
INFO("OSC Remote control is not enabled in this build");
#endif
#endif
}
Initializer::~Initializer()
{
using namespace rack;
#ifdef CARDINAL_INIT_OSC_THREAD
if (oscServerThread != nullptr)
{
lo_server_thread_stop(oscServerThread);
lo_server_thread_del_method(oscServerThread, nullptr, nullptr);
lo_server_thread_free(oscServerThread);
oscServerThread = nullptr;
}
#endif
#ifdef HAVE_LIBLO
stopRemoteServer();
#endif
if (shouldSaveSettings)
{
@ -670,6 +663,81 @@ void Initializer::loadSettings(const bool isRealInstance)
switchDarkMode(settings::uiTheme == "dark");
}
#ifdef HAVE_LIBLO
bool Initializer::startRemoteServer(const char* const port)
{
#ifdef CARDINAL_INIT_OSC_THREAD
if (oscServerThread != nullptr)
return true;
if ((oscServerThread = lo_server_thread_new_with_proto(port, LO_UDP, osc_error_handler)) == nullptr)
return false;
oscServer = lo_server_thread_get_server(oscServerThread);
lo_server_thread_add_method(oscServerThread, "/hello", "", osc_hello_handler, this);
lo_server_thread_add_method(oscServerThread, "/host-param", "if", osc_host_param_handler, this);
lo_server_thread_add_method(oscServerThread, "/load", "b", osc_load_handler, this);
lo_server_thread_add_method(oscServerThread, "/param", "hif", osc_param_handler, this);
lo_server_thread_add_method(oscServerThread, "/screenshot", "b", osc_screenshot_handler, this);
lo_server_thread_add_method(oscServerThread, nullptr, nullptr, osc_fallback_handler, nullptr);
lo_server_thread_start(oscServerThread);
#else
if (oscServer != nullptr)
return true;
if ((oscServer = lo_server_new_with_proto(port, LO_UDP, osc_error_handler)) == nullptr)
return false;
lo_server_add_method(oscServer, "/hello", "", osc_hello_handler, this);
lo_server_add_method(oscServer, "/host-param", "if", osc_host_param_handler, this);
lo_server_add_method(oscServer, "/load", "b", osc_load_handler, this);
lo_server_add_method(oscServer, "/param", "hif", osc_param_handler, this);
lo_server_add_method(oscServer, nullptr, nullptr, osc_fallback_handler, nullptr);
#endif
return true;
}
void Initializer::stopRemoteServer()
{
DISTRHO_SAFE_ASSERT(remotePluginInstance == nullptr);
#ifdef CARDINAL_INIT_OSC_THREAD
if (oscServerThread != nullptr)
{
lo_server_thread_stop(oscServerThread);
lo_server_thread_del_method(oscServerThread, nullptr, nullptr);
lo_server_thread_free(oscServerThread);
oscServerThread = oscServer = nullptr;
}
#else
if (oscServer != nullptr)
{
lo_server_del_method(oscServer, nullptr, nullptr);
lo_server_free(oscServer);
oscServer = nullptr;
}
#endif
}
void Initializer::stepRemoteServer()
{
DISTRHO_SAFE_ASSERT_RETURN(oscServer != nullptr,);
DISTRHO_SAFE_ASSERT_RETURN(remotePluginInstance != nullptr,);
#ifndef CARDINAL_INIT_OSC_THREAD
for (;;)
{
try {
if (lo_server_recv_noblock(oscServer, 0) == 0)
break;
} DISTRHO_SAFE_EXCEPTION_CONTINUE("stepRemoteServer")
}
#endif
}
#endif // HAVE_LIBLO
// --------------------------------------------------------------------------------------------------------------------
END_NAMESPACE_DISTRHO