From 8f23c45c28bcb7d3c83b8b7f04a841aa33fb628a Mon Sep 17 00:00:00 2001 From: Pau Aliagas Date: Thu, 22 Oct 2026 21:27:31 +0200 Subject: [PATCH 1/3] lv2_worker defaults to auto: the adapter row first, mod-host for what it refuses (#101) --- README.md | 2 +- include/plugin-hostd/protocol.h | 2 +- protocol/plugin-hostd.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e778f95..fb2a810 100644 --- a/README.md +++ b/README.md @@ -100,7 +100,7 @@ The settings live in a file, `-c`, `$PLUGIN_HOSTD_CONF` or |---|---|---| | `mod_host` | `mod-host` | worker for lv2 (a name on PATH or a path) | | `clap_host` | `omx-clap-host` | worker for clap | -| `lv2_worker` | `mod-host` | who runs an LV2 plugin: mod-host (the mod_host program), omx-clap-host (the clap_host program, through its LV2 adapter, a plugin it cannot run refused with a code) or auto (the adapter first, mod-host for what it refuses, each such plugin in a worker of its own unless its add names a placement); lv2_worker_set overrides it for one plugin | +| `lv2_worker` | `auto` | who runs an LV2 plugin: mod-host (the mod_host program), omx-clap-host (the clap_host program, through its LV2 adapter, a plugin it cannot run refused with a code) or auto (the adapter first, mod-host for what it refuses, each such plugin in a worker of its own unless its add names a placement); lv2_worker_set overrides it for one plugin | | `lv2_path` | `$LV2_PATH`, else `/usr/lib64/lv2:/usr/lib/lv2:/usr/local/lib/lv2` | where bundles are searched | | `state_root` | `$XDG_RUNTIME_DIR`, else `/tmp` | the daemon's checkpoints and worker logs | | `pin_mode` | `first-use` | strict or first-use, while require_pins is 1: first-use records the pin of a plugin on its first add, strict admits only a plugin a controller, a pin_file or pins_dir pinned | diff --git a/include/plugin-hostd/protocol.h b/include/plugin-hostd/protocol.h index 65900ae..3845f25 100644 --- a/include/plugin-hostd/protocol.h +++ b/include/plugin-hostd/protocol.h @@ -887,7 +887,7 @@ static inline int phd_is_note_verb(const char *verb) #define PHD_DEFAULT_MOD_HOST "mod-host" #define PHD_DEFAULT_CLAP_HOST "omx-clap-host" -#define PHD_DEFAULT_LV2_WORKER PHD_LV2_WORKER_MOD_HOST +#define PHD_DEFAULT_LV2_WORKER PHD_LV2_WORKER_AUTO #define PHD_DEFAULT_LV2_PATH "/usr/lib64/lv2:/usr/lib/lv2:/usr/local/lib/lv2" #define PHD_DEFAULT_STATE_ROOT "/tmp" #define PHD_DEFAULT_READY_TIMEOUT_MS 5000 diff --git a/protocol/plugin-hostd.json b/protocol/plugin-hostd.json index b8f458d..36f9b4c 100644 --- a/protocol/plugin-hostd.json +++ b/protocol/plugin-hostd.json @@ -205,7 +205,7 @@ "config": [ {"key": "mod_host", "type": "string", "default": "mod-host", "env": "", "meaning": "worker for lv2 (a name on PATH or a path)"}, {"key": "clap_host", "type": "string", "default": "omx-clap-host", "env": "", "meaning": "worker for clap"}, - {"key": "lv2_worker", "type": "string", "default": "mod-host", "env": "", "meaning": "who runs an LV2 plugin: mod-host (the mod_host program), omx-clap-host (the clap_host program, through its LV2 adapter, a plugin it cannot run refused with a code) or auto (the adapter first, mod-host for what it refuses, each such plugin in a worker of its own unless its add names a placement); lv2_worker_set overrides it for one plugin"}, + {"key": "lv2_worker", "type": "string", "default": "auto", "env": "", "meaning": "who runs an LV2 plugin: mod-host (the mod_host program), omx-clap-host (the clap_host program, through its LV2 adapter, a plugin it cannot run refused with a code) or auto (the adapter first, mod-host for what it refuses, each such plugin in a worker of its own unless its add names a placement); lv2_worker_set overrides it for one plugin"}, {"key": "lv2_path", "type": "string", "default": "/usr/lib64/lv2:/usr/lib/lv2:/usr/local/lib/lv2", "env": "LV2_PATH", "meaning": "where bundles are searched"}, {"key": "state_root", "type": "string", "default": "/tmp", "env": "XDG_RUNTIME_DIR", "meaning": "the daemon's checkpoints and worker logs"}, {"key": "pin_mode", "type": "string", "default": "first-use", "env": "", "meaning": "strict or first-use, while require_pins is 1: first-use records the pin of a plugin on its first add, strict admits only a plugin a controller, a pin_file or pins_dir pinned"}, From 00722b483c0e7b7515a27a92f505e2bb6bc9f6dc Mon Sep 17 00:00:00 2001 From: Pau Aliagas Date: Thu, 22 Oct 2026 21:27:31 +0200 Subject: [PATCH 2/3] tests: the lv2_worker default is auto, the mod-host row is named where it is meant (#101) --- tests/daemon_test.py | 35 ++++++++++++++++++++++++++++++++--- tests/harness.py | 3 +++ 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/tests/daemon_test.py b/tests/daemon_test.py index 68d6801..caf7f52 100644 --- a/tests/daemon_test.py +++ b/tests/daemon_test.py @@ -2073,12 +2073,12 @@ def adds_of(log, pid): @test -def lv2_worker_defaults_to_mod_host_on_the_lv2_row(): - d, programs, log = lv2_run() +def lv2_worker_mod_host_runs_an_lv2_plugin_on_the_lv2_row(): + d, programs, log = lv2_run(lv2_worker="mod-host") try: d.expect("add lv2:urn:test:a 0", "resp 0") _, w = d.holder(0) - check(w["fmt"] == "lv2", "the default row is lv2: %s" % w) + check(w["fmt"] == "lv2", "the mod-host row is lv2: %s" % w) check(programs.of(w["pid"])[0] == "mod-host", "mod-host runs it, not %s" % programs.of(w["pid"])[0]) check(adds_of(log, w["pid"]) == ["add urn:test:a 0"], "mod-host is given the bare uri: %s" % adds_of(log, w["pid"])) finally: @@ -2086,6 +2086,35 @@ def lv2_worker_defaults_to_mod_host_on_the_lv2_row(): programs.close() +@test +def lv2_worker_defaults_to_auto_the_adapter_row_first(): + # None leaves lv2_worker out of the settings file: the daemon's own default holds + d, programs, log = lv2_run(lv2_worker=None) + try: + d.expect("add lv2:urn:test:a 0", "resp 0") + _, w = d.holder(0) + check(w["fmt"] == "lv2-clap", "the default sends an LV2 plugin to the adapter row first: %s" % w) + check(programs.of(w["pid"])[0] == "omx-clap-host", "omx-clap-host runs it, not %s" % programs.of(w["pid"])[0]) + check(adds_of(log, w["pid"]) == ["add lv2:urn:test:a 0"], "the adapter's worker is given the lv2: uri: %s" % adds_of(log, w["pid"])) + finally: + d.close() + programs.close() + + +@test +def lv2_worker_default_without_the_adapter_worker_installed_is_the_lv2_row(): + # auto with no clap_host program on the system: the add is the lv2 row's, mod-host runs it, nothing is refused + d, programs, log = lv2_run(lv2_worker=None, clap_host=os.path.join(tempfile.gettempdir(), "no-such-omx-clap-host")) + try: + d.expect("add lv2:urn:test:a 0", "resp 0") + _, w = d.holder(0) + check(w["fmt"] == "lv2", "no adapter worker installed: the lv2 row: %s" % w) + check(programs.of(w["pid"])[0] == "mod-host", "mod-host runs it, not %s" % programs.of(w["pid"])[0]) + finally: + d.close() + programs.close() + + @test def lv2_worker_omx_clap_host_runs_the_plugin_in_the_clap_program_on_the_adapter_row(): d, programs, log = lv2_run(lv2_worker="omx-clap-host") diff --git a/tests/harness.py b/tests/harness.py index 02b2e88..a25586e 100644 --- a/tests/harness.py +++ b/tests/harness.py @@ -78,6 +78,9 @@ def __init__(self, exe, worker, clap_worker=None, conf=None, env=None, feedback= # the tests of placement, replay and attribution add plugins no one pinned; the pin tests turn it back on, # and a None leaves a setting out of the file, so the daemon's own default holds "require_pins": 0, + # the daemon's own default is auto (the adapter first); the tests of the mod-host row name that row, and the + # tests of the default pass None to leave the setting out of the file + "lv2_worker": "mod-host", # no package's pins: the system's pins_dir is not the test's "pins_dir": "", } From 5f39345e862fa16a8c3e01caa7a11d0c3d4eaa7b Mon Sep 17 00:00:00 2001 From: Pau Aliagas Date: Thu, 22 Oct 2026 21:27:31 +0200 Subject: [PATCH 3/3] README: who runs an LV2 plugin by default (#101) --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index fb2a810..545f810 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Raspberry Pi, and cannot let one bad plugin stop the show. - A crash stays small: the plugin's worker is respawned with its settings put back. - Nothing to change in your controller: it speaks mod-host's socket protocol, same ports, same replies. -- LV2 (through mod-host) and CLAP (through omx-clap-host) side by side. +- LV2 through omx-clap-host's adapter, with mod-host for the plugins the adapter refuses, and CLAP through omx-clap-host, side by side. - Audio never passes through the daemon; every worker is a JACK client, as in mod-host. - A plugin that keeps crashing is singled out and given up on without touching its neighbours. @@ -541,9 +541,9 @@ with a capability missing and says which. a test registers a third format in the Who runs an LV2 plugin ---------------------- -`lv2_worker` chooses the program that runs LV2 plugins: `mod-host` (the default, the `mod_host` program), `omx-clap-host` -(the `clap_host` program, through its LV2 adapter) or `auto` (the adapter first, mod-host for a plugin the adapter -refuses). `lv2_worker_set ` overrides it for one plugin from then on, and `-` takes +`lv2_worker` chooses the program that runs LV2 plugins: `auto` (the default: the adapter first, mod-host for a plugin the +adapter refuses, and for every add while omx-clap-host is not installed), `omx-clap-host` (the `clap_host` program, through +its LV2 adapter, a plugin it cannot run refused with a code) or `mod-host` (the `mod_host` program). `lv2_worker_set ` overrides it for one plugin from then on, and `-` takes the override back. The two programs are two rows of the table, `lv2` and `lv2-clap`, so `policy_set`, `worker_env` and `worker_list` name them like any format. The adapter row differs from the mod-host row in these ways, each held by a test: