Implement the CLAP log extension

This commit is contained in:
Robbert van der Helm
2022-10-09 00:21:29 +02:00
parent 2766f2ab09
commit 6cb12aad73
10 changed files with 114 additions and 22 deletions
+1
View File
@@ -199,6 +199,7 @@ void serialize(S& s, ClapMainThreadCallbackRequest& payload) {
*/
using ClapAudioThreadCallbackRequest =
std::variant<WantsConfiguration,
clap::ext::log::host::Log,
clap::ext::params::host::RequestFlush,
clap::ext::tail::host::Changed>;
+19 -19
View File
@@ -15,25 +15,25 @@ Yabridge currently tracks CLAP 1.1.1. The implementation status for CLAP's core
| `clap.plugin-factory` | :heavy_check_mark: |
| `clap.plugin-invalidation-factory/draft0` | :x: Not supported yet |
| extension | status |
| ------------------------- | ---------------------------------------------------- |
| `clap.audio-ports` | :heavy_check_mark: |
| `clap.audio-ports-config` | :x: Not supported yet |
| `clap.event-registry` | :x: Not needed for any of the supported extensions |
| `clap.gui` | :heavy_check_mark: Currently only does embedded GUIs |
| `clap.latency` | :heavy_check_mark: |
| `clap.log` | :x: Not supported yet |
| `clap.note-name` | :x: Not supported yet |
| `clap.note-ports` | :heavy_check_mark: |
| `clap.params` | :heavy_check_mark: |
| `clap.posix-fd-support` | :x: Not supported yet |
| `clap.render` | :x: Not supported yet |
| `clap.state` | :heavy_check_mark: |
| `clap.tail` | :heavy_check_mark: |
| `clap.thread-check` | :heavy_check_mark: |
| `clap.thread-pool` | :x: Not supported yet |
| `clap.timer-support` | :x: Not supported yet |
| `clap.voice-info` | :x: Not supported yet |
| extension | status |
| ------------------------- | ------------------------------------------------------------ |
| `clap.audio-ports` | :heavy_check_mark: |
| `clap.audio-ports-config` | :x: Not supported yet |
| `clap.event-registry` | :x: Not needed for any of the supported extensions |
| `clap.gui` | :heavy_check_mark: Currently only does embedded GUIs |
| `clap.latency` | :heavy_check_mark: |
| `clap.log` | :heavy_check_mark: Always supported with or without bridging |
| `clap.note-name` | :x: Not supported yet |
| `clap.note-ports` | :heavy_check_mark: |
| `clap.params` | :heavy_check_mark: |
| `clap.posix-fd-support` | :x: Not supported yet |
| `clap.render` | :x: Not supported yet |
| `clap.state` | :heavy_check_mark: |
| `clap.tail` | :heavy_check_mark: |
| `clap.thread-check` | :heavy_check_mark: No bridging involved |
| `clap.thread-pool` | :x: Not supported yet |
| `clap.timer-support` | :x: Not supported yet |
| `clap.voice-info` | :x: Not supported yet |
| draft extension | status |
| -------------------------------- | --------------------- |
+1 -1
View File
@@ -45,7 +45,7 @@ struct Log {
void serialize(S& s) {
s.value8b(owner_instance_id);
s.value4b(severity);
s.text(msg, 1 << 16);
s.text1b(msg, 1 << 16);
}
};
+3 -1
View File
@@ -19,6 +19,7 @@
#include <clap/ext/audio-ports.h>
#include <clap/ext/gui.h>
#include <clap/ext/latency.h>
#include <clap/ext/log.h>
#include <clap/ext/note-ports.h>
#include <clap/ext/params.h>
#include <clap/ext/state.h>
@@ -34,11 +35,12 @@ Host::Host(const clap_host_t& original)
url(original.url ? std::optional(original.url) : std::nullopt),
version((assert(original.version), original.version)) {}
std::array<std::pair<bool, const char*>, 7> SupportedHostExtensions::list()
std::array<std::pair<bool, const char*>, 8> SupportedHostExtensions::list()
const noexcept {
return {std::pair(supports_audio_ports, CLAP_EXT_AUDIO_PORTS),
std::pair(supports_gui, CLAP_EXT_GUI),
std::pair(supports_latency, CLAP_EXT_LATENCY),
std::pair(supports_log, CLAP_EXT_LOG),
std::pair(supports_note_ports, CLAP_EXT_NOTE_PORTS),
std::pair(supports_params, CLAP_EXT_PARAMS),
std::pair(supports_state, CLAP_EXT_STATE),
+3 -1
View File
@@ -84,6 +84,7 @@ struct SupportedHostExtensions {
bool supports_audio_ports = false;
bool supports_gui = false;
bool supports_latency = false;
bool supports_log = false;
bool supports_note_ports = false;
bool supports_params = false;
bool supports_state = false;
@@ -93,13 +94,14 @@ struct SupportedHostExtensions {
* Get a list of `<bool, extension_name>` tuples for the supported
* extensions. Used during logging.
*/
std::array<std::pair<bool, const char*>, 7> list() const noexcept;
std::array<std::pair<bool, const char*>, 8> list() const noexcept;
template <typename S>
void serialize(S& s) {
s.value1b(supports_audio_ports);
s.value1b(supports_gui);
s.value1b(supports_latency);
s.value1b(supports_log);
s.value1b(supports_note_ports);
s.value1b(supports_params);
s.value1b(supports_state);
@@ -25,6 +25,8 @@ ClapHostExtensions::ClapHostExtensions(const clap_host& host) noexcept
host.get_extension(&host, CLAP_EXT_GUI))),
latency(static_cast<const clap_host_latency_t*>(
host.get_extension(&host, CLAP_EXT_LATENCY))),
log(static_cast<const clap_host_log_t*>(
host.get_extension(&host, CLAP_EXT_LOG))),
note_ports(static_cast<const clap_host_note_ports_t*>(
host.get_extension(&host, CLAP_EXT_NOTE_PORTS))),
params(static_cast<const clap_host_params_t*>(
@@ -42,6 +44,7 @@ clap::host::SupportedHostExtensions ClapHostExtensions::supported()
.supports_audio_ports = audio_ports != nullptr,
.supports_gui = gui != nullptr,
.supports_latency = latency != nullptr,
.supports_log = log != nullptr,
.supports_note_ports = note_ports != nullptr,
.supports_params = params != nullptr,
.supports_state = state != nullptr,
@@ -23,6 +23,7 @@
#include <clap/ext/audio-ports.h>
#include <clap/ext/gui.h>
#include <clap/ext/latency.h>
#include <clap/ext/log.h>
#include <clap/ext/note-ports.h>
#include <clap/ext/params.h>
#include <clap/ext/state.h>
@@ -65,6 +66,7 @@ struct ClapHostExtensions {
const clap_host_audio_ports_t* audio_ports = nullptr;
const clap_host_gui_t* gui = nullptr;
const clap_host_latency_t* latency = nullptr;
const clap_host_log_t* log = nullptr;
const clap_host_note_ports_t* note_ports = nullptr;
const clap_host_params_t* params = nullptr;
const clap_host_state_t* state = nullptr;
+11
View File
@@ -346,6 +346,17 @@ void ClapPluginBridge::register_plugin_proxy(
// hell. I haven't been able to figure out why.
return {};
},
[&](const clap::ext::log::host::Log& request)
-> clap::ext::log::host::Log::Response {
const auto& [plugin_proxy, _] =
get_proxy(request.owner_instance_id);
plugin_proxy.host_extensions_.log->log(plugin_proxy.host_,
request.severity,
request.msg.c_str());
return Ack{};
},
[&](const clap::ext::params::host::RequestFlush& request)
-> clap::ext::params::host::RequestFlush::Response {
const auto& [plugin_proxy, _] =
@@ -63,6 +63,9 @@ clap_host_proxy::clap_host_proxy(ClapBridge& bridge,
ext_latency_vtable(clap_host_latency_t{
.changed = ext_latency_changed,
}),
ext_log_vtable(clap_host_log_t{
.log = ext_log_log,
}),
ext_note_ports_vtable(clap_host_note_ports_t{
.supported_dialects = ext_note_ports_supported_dialects,
.rescan = ext_note_ports_rescan,
@@ -99,6 +102,11 @@ clap_host_proxy::host_get_extension(const struct clap_host* host,
} else if (self->supported_extensions_.supports_latency &&
strcmp(extension_id, CLAP_EXT_LATENCY) == 0) {
extension_ptr = &self->ext_latency_vtable;
} else if (strcmp(extension_id, CLAP_EXT_LOG) == 0) {
// This extension is always supported. We'll bridge it if the host also
// supports it, or we'll print the message if it doesn't. That allows us
// to filter misbehavior messages.
extension_ptr = &self->ext_log_vtable;
} else if (self->supported_extensions_.supports_note_ports &&
strcmp(extension_id, CLAP_EXT_NOTE_PORTS) == 0) {
extension_ptr = &self->ext_note_ports_vtable;
@@ -265,6 +273,59 @@ void CLAP_ABI clap_host_proxy::ext_latency_changed(const clap_host_t* host) {
self->owner_instance_id()});
}
void CLAP_ABI clap_host_proxy::ext_log_log(const clap_host_t* host,
clap_log_severity severity,
const char* msg) {
assert(host && host->host_data && msg);
auto self = static_cast<const clap_host_proxy*>(host->host_data);
// We'll always support this extension, even if the host doesn't. That
// allows us to filter misbehavior messages from the CLAP helper.
if ((severity == CLAP_LOG_HOST_MISBEHAVING ||
severity == CLAP_LOG_PLUGIN_MISBEHAVING) &&
self->bridge_.logger_.verbosity() < Logger::Verbosity::all_events) {
return;
}
// We'll bridge this if possible, otherwise we'll just print the message to
// the logger (through STDERR)
if (self->supported_extensions_.supports_log) {
self->bridge_.send_audio_thread_message(clap::ext::log::host::Log{
.owner_instance_id = self->owner_instance_id(),
.severity = severity,
.msg = msg});
} else {
switch (severity) {
case CLAP_LOG_DEBUG:
std::cerr << "[DEBUG] ";
break;
case CLAP_LOG_INFO:
std::cerr << "[INFO] ";
break;
case CLAP_LOG_WARNING:
std::cerr << "[WARNING] ";
break;
case CLAP_LOG_ERROR:
std::cerr << "[ERROR] ";
break;
case CLAP_LOG_FATAL:
std::cerr << "[FATAL] ";
break;
case CLAP_LOG_HOST_MISBEHAVING:
std::cerr << "[HOST_MISBEHAVING] ";
break;
case CLAP_LOG_PLUGIN_MISBEHAVING:
std::cerr << "[PLUGIN_MISBEHAVING] ";
break;
default:
std::cerr << "[unknown log level " << severity << "] ";
break;
}
std::cerr << msg << std::endl;
}
}
uint32_t CLAP_ABI
clap_host_proxy::ext_note_ports_supported_dialects(const clap_host_t* host) {
assert(host && host->host_data);
@@ -21,6 +21,7 @@
#include <clap/ext/audio-ports.h>
#include <clap/ext/gui.h>
#include <clap/ext/latency.h>
#include <clap/ext/log.h>
#include <clap/ext/note-ports.h>
#include <clap/ext/params.h>
#include <clap/ext/state.h>
@@ -95,6 +96,10 @@ class clap_host_proxy {
static void CLAP_ABI ext_latency_changed(const clap_host_t* host);
static void CLAP_ABI ext_log_log(const clap_host_t* host,
clap_log_severity severity,
const char* msg);
static uint32_t CLAP_ABI
ext_note_ports_supported_dialects(const clap_host_t* host);
static void CLAP_ABI ext_note_ports_rescan(const clap_host_t* host,
@@ -134,10 +139,15 @@ class clap_host_proxy {
const clap_host_audio_ports_t ext_audio_ports_vtable;
const clap_host_gui_t ext_gui_vtable;
const clap_host_latency_t ext_latency_vtable;
// This is also always available regardless of the proxied host. That way we
// can filter out plugin/host misbehavior messages on lower yabridge
// verbosity levels.
const clap_host_log_t ext_log_vtable;
const clap_host_note_ports_t ext_note_ports_vtable;
const clap_host_params_t ext_params_vtable;
const clap_host_state_t ext_state_vtable;
const clap_host_tail_t ext_tail_vtable;
// This is always available regardless of the proxied host
const clap_host_thread_check_t ext_thread_check_vtable;
/**