daemon: add a mode to execute lua scripts from the command line

This can be useful for quick testing of scripts, or to build small
utilities that do something in pipewire utilizing our lua API
This commit is contained in:
George Kiagiadakis
2021-02-04 16:44:56 +02:00
parent 02142b899b
commit e0f1c8710f
3 changed files with 83 additions and 13 deletions

View File

@@ -37,7 +37,7 @@ if SANDBOX_CONFIG["minimal_std"] then
else else
-- full list, used for scripts -- full list, used for scripts
([[ ([[
_VERSION assert error ipairs next pairs _VERSION assert error ipairs next pairs print
pcall select tonumber tostring type xpcall pcall select tonumber tostring type xpcall
table utf8 table utf8

View File

@@ -101,11 +101,37 @@ core_sync (lua_State *L)
return 0; return 0;
} }
static gboolean
core_disconnect (WpCore * core)
{
wp_core_disconnect (core);
return G_SOURCE_REMOVE;
}
static int
core_quit (lua_State *L)
{
WpCore * core = get_wp_core (L);
g_autoptr (WpProperties) p = wp_core_get_properties (core);
const gchar *interactive = wp_properties_get (p, "wireplumber.interactive");
if (!interactive || g_strcmp0 (interactive, "true") != 0) {
wp_warning ("script attempted to quit, but wireplumber "
"is not running in script interactive mode; ignoring");
return 0;
}
/* wp_core_disconnect() will immediately destroy the lua plugin
and the lua engine, so we cannot call it directly */
wp_core_idle_add (core, NULL, G_SOURCE_FUNC (core_disconnect), core, NULL);
return 0;
}
static const luaL_Reg core_funcs[] = { static const luaL_Reg core_funcs[] = {
{ "get_info", core_get_info }, { "get_info", core_get_info },
{ "idle_add", core_idle_add }, { "idle_add", core_idle_add },
{ "timeout_add", core_timeout_add }, { "timeout_add", core_timeout_add },
{ "sync", core_sync }, { "sync", core_sync },
{ "quit", core_quit },
{ NULL, NULL } { NULL, NULL }
}; };

View File

@@ -10,15 +10,6 @@
#include <glib-unix.h> #include <glib-unix.h>
#include <pipewire/keys.h> #include <pipewire/keys.h>
static gchar * config_file = NULL;
static GOptionEntry entries[] =
{
{ "config-file", 'c', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, &config_file,
"The configuration file to load components from", NULL },
{ NULL }
};
#define WP_DOMAIN_DAEMON (wp_domain_daemon_quark ()) #define WP_DOMAIN_DAEMON (wp_domain_daemon_quark ())
static G_DEFINE_QUARK (wireplumber-daemon, wp_domain_daemon); static G_DEFINE_QUARK (wireplumber-daemon, wp_domain_daemon);
@@ -30,6 +21,40 @@ enum WpExitCode
WP_CODE_INVALID_ARGUMENT, WP_CODE_INVALID_ARGUMENT,
}; };
static gchar * config_file = NULL;
static gchar * exec_script = NULL;
static GVariantBuilder exec_args_b =
G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_VARDICT);
static gboolean
parse_exec_script_arg (const gchar *option_name, const gchar *value,
gpointer data, GError **error)
{
g_auto(GStrv) tokens = g_strsplit (value, "=", 2);
if (!tokens[0] || *g_strstrip (tokens[0]) == '\0') {
g_set_error (error, WP_DOMAIN_DAEMON, WP_CODE_INVALID_ARGUMENT,
"invalid script argument '%s'; must be in key=value format", value);
return FALSE;
}
g_variant_builder_add (&exec_args_b, "{sv}", tokens[0], tokens[1] ?
g_variant_new_string (g_strstrip (tokens[1])) :
g_variant_new_boolean (TRUE));
return TRUE;
}
static GOptionEntry entries[] =
{
{ "config-file", 'c', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, &config_file,
"The configuration file to load components from", NULL },
{ "execute", 'e', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, &exec_script,
"Runs WirePlumber in interactive script execution mode, "
"executing the given script", NULL },
{ G_OPTION_REMAINING, 0, G_OPTION_FLAG_NONE, G_OPTION_ARG_CALLBACK,
parse_exec_script_arg, NULL, NULL },
{ NULL }
};
/*** WpInitTransition ***/ /*** WpInitTransition ***/
struct _WpInitTransition struct _WpInitTransition
@@ -42,6 +67,7 @@ struct _WpInitTransition
enum { enum {
STEP_LOAD_MODULE = WP_TRANSITION_STEP_CUSTOM_START, STEP_LOAD_MODULE = WP_TRANSITION_STEP_CUSTOM_START,
STEP_LOAD_CONFIG, STEP_LOAD_CONFIG,
STEP_LOAD_SCRIPT,
STEP_CONNECT, STEP_CONNECT,
STEP_ACTIVATE_PLUGINS, STEP_ACTIVATE_PLUGINS,
STEP_ACTIVATE_SCRIPTS, STEP_ACTIVATE_SCRIPTS,
@@ -61,9 +87,16 @@ wp_init_transition_get_next_step (WpTransition * transition, guint step)
{ {
switch (step) { switch (step) {
case WP_TRANSITION_STEP_NONE: return STEP_LOAD_MODULE; case WP_TRANSITION_STEP_NONE: return STEP_LOAD_MODULE;
case STEP_LOAD_MODULE: return STEP_LOAD_CONFIG;
case STEP_LOAD_CONFIG: return STEP_CONNECT;
case STEP_CONNECT: return STEP_ACTIVATE_PLUGINS; case STEP_CONNECT: return STEP_ACTIVATE_PLUGINS;
case STEP_ACTIVATE_SCRIPTS: return WP_TRANSITION_STEP_NONE;
case STEP_LOAD_MODULE:
return exec_script ? STEP_LOAD_SCRIPT : STEP_LOAD_CONFIG;
case STEP_LOAD_CONFIG:
case STEP_LOAD_SCRIPT:
return STEP_CONNECT;
case STEP_ACTIVATE_PLUGINS: { case STEP_ACTIVATE_PLUGINS: {
WpInitTransition *self = WP_INIT_TRANSITION (transition); WpInitTransition *self = WP_INIT_TRANSITION (transition);
if (self->pending_plugins == 0) if (self->pending_plugins == 0)
@@ -71,7 +104,7 @@ wp_init_transition_get_next_step (WpTransition * transition, guint step)
else else
return STEP_ACTIVATE_PLUGINS; return STEP_ACTIVATE_PLUGINS;
} }
case STEP_ACTIVATE_SCRIPTS: return WP_TRANSITION_STEP_NONE;
default: default:
g_return_val_if_reached (WP_TRANSITION_STEP_ERROR); g_return_val_if_reached (WP_TRANSITION_STEP_ERROR);
} }
@@ -127,6 +160,16 @@ wp_init_transition_execute_step (WpTransition * transition, guint step)
break; break;
} }
case STEP_LOAD_SCRIPT: {
GVariant *args = g_variant_builder_end (&exec_args_b);
if (!wp_core_load_component (core, exec_script, "script/lua", args, &error)) {
wp_transition_return_error (transition, error);
return;
}
wp_transition_advance (transition);
break;
}
case STEP_CONNECT: case STEP_CONNECT:
g_signal_connect_object (core, "connected", g_signal_connect_object (core, "connected",
G_CALLBACK (wp_transition_advance), transition, G_CONNECT_SWAPPED); G_CALLBACK (wp_transition_advance), transition, G_CONNECT_SWAPPED);
@@ -281,6 +324,7 @@ main (gint argc, gchar **argv)
d.loop = g_main_loop_new (NULL, FALSE); d.loop = g_main_loop_new (NULL, FALSE);
d.core = wp_core_new (NULL, wp_properties_new ( d.core = wp_core_new (NULL, wp_properties_new (
PW_KEY_APP_NAME, "WirePlumber", PW_KEY_APP_NAME, "WirePlumber",
"wireplumber.interactive", exec_script ? "true" : "false",
NULL)); NULL));
g_signal_connect (d.core, "disconnected", G_CALLBACK (on_disconnected), &d); g_signal_connect (d.core, "disconnected", G_CALLBACK (on_disconnected), &d);