
- support loading modules dependent on wireplumber settings in JSON config. - load the settings module before parsing wireplumber.components, so that dependencies can be fetched during parsing. - access lua scripts are switched to JSON based config and lua configs are removed.
248 lines
7.1 KiB
C
248 lines
7.1 KiB
C
/* WirePlumber
|
|
*
|
|
* Copyright © 2020 Collabora Ltd.
|
|
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
*/
|
|
|
|
#include <wp/wp.h>
|
|
#include <wplua/wplua.h>
|
|
#include <pipewire/keys.h>
|
|
|
|
#include "script.h"
|
|
|
|
void wp_lua_scripting_api_init (lua_State *L);
|
|
gboolean wp_lua_scripting_load_configuration (const gchar * conf_file,
|
|
WpCore * core, GError ** error);
|
|
|
|
struct _WpLuaScriptingPlugin
|
|
{
|
|
WpComponentLoader parent;
|
|
|
|
GPtrArray *scripts; /* element-type: WpPlugin* */
|
|
lua_State *L;
|
|
};
|
|
|
|
static int
|
|
wp_lua_scripting_package_loader (lua_State *L)
|
|
{
|
|
luaL_checktype (L, 2, LUA_TFUNCTION);
|
|
wplua_push_sandbox (L);
|
|
lua_pushvalue (L, 2);
|
|
lua_call (L, 1, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
wp_lua_scripting_package_searcher (lua_State *L)
|
|
{
|
|
const gchar *name = luaL_checkstring (L, 1);
|
|
g_autoptr (GError) error = NULL;
|
|
g_autofree gchar *filename = g_strdup_printf ("%s.lua", name);
|
|
g_autofree gchar *script = wp_find_file (
|
|
WP_LOOKUP_DIR_ENV_DATA |
|
|
WP_LOOKUP_DIR_XDG_CONFIG_HOME |
|
|
WP_LOOKUP_DIR_ETC |
|
|
WP_LOOKUP_DIR_PREFIX_SHARE,
|
|
filename, "scripts/lib");
|
|
|
|
if (!script) {
|
|
lua_pushliteral (L, "script not found");
|
|
return 1;
|
|
}
|
|
|
|
/* 1. loader (function) */
|
|
lua_pushcfunction (L, wp_lua_scripting_package_loader);
|
|
|
|
/* 2. loader data (param to 1) */
|
|
wp_debug ("Executing script %s", script);
|
|
if (!wplua_load_path (L, script, &error)) {
|
|
lua_pop (L, 1);
|
|
lua_pushstring (L, error->message);
|
|
return 1;
|
|
}
|
|
|
|
/* 3. script path */
|
|
lua_pushstring (L, script);
|
|
return 3;
|
|
}
|
|
|
|
static void
|
|
wp_lua_scripting_enable_package_searcher (lua_State *L)
|
|
{
|
|
/* table.insert(package.searchers, 2, wp_lua_scripting_package_searcher) */
|
|
lua_getglobal (L, "table");
|
|
lua_getfield (L, -1, "insert");
|
|
lua_remove (L, -2);
|
|
lua_getglobal (L, "package");
|
|
lua_getfield (L, -1, "searchers");
|
|
lua_remove (L, -2);
|
|
lua_pushinteger (L, 2);
|
|
lua_pushcfunction (L, wp_lua_scripting_package_searcher);
|
|
lua_call (L, 3, 0);
|
|
}
|
|
|
|
G_DECLARE_FINAL_TYPE (WpLuaScriptingPlugin, wp_lua_scripting_plugin,
|
|
WP, LUA_SCRIPTING_PLUGIN, WpComponentLoader)
|
|
G_DEFINE_TYPE (WpLuaScriptingPlugin, wp_lua_scripting_plugin,
|
|
WP_TYPE_COMPONENT_LOADER)
|
|
|
|
static void
|
|
wp_lua_scripting_plugin_init (WpLuaScriptingPlugin * self)
|
|
{
|
|
self->scripts = g_ptr_array_new_with_free_func (g_object_unref);
|
|
}
|
|
|
|
static void
|
|
wp_lua_scripting_plugin_finalize (GObject * object)
|
|
{
|
|
WpLuaScriptingPlugin * self = WP_LUA_SCRIPTING_PLUGIN (object);
|
|
|
|
g_clear_pointer (&self->scripts, g_ptr_array_unref);
|
|
|
|
G_OBJECT_CLASS (wp_lua_scripting_plugin_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
wp_lua_scripting_plugin_enable (WpPlugin * plugin, WpTransition * transition)
|
|
{
|
|
WpLuaScriptingPlugin * self = WP_LUA_SCRIPTING_PLUGIN (plugin);
|
|
g_autoptr (WpCore) core = wp_object_get_core (WP_OBJECT (plugin));
|
|
WpCore *export_core;
|
|
|
|
/* init lua engine */
|
|
self->L = wplua_new ();
|
|
|
|
lua_pushliteral (self->L, "wireplumber_core");
|
|
lua_pushlightuserdata (self->L, core);
|
|
lua_settable (self->L, LUA_REGISTRYINDEX);
|
|
|
|
/* initialize secondary connection to pipewire */
|
|
export_core = g_object_get_data (G_OBJECT (core), "wireplumber.export-core");
|
|
if (export_core) {
|
|
lua_pushliteral (self->L, "wireplumber_export_core");
|
|
wplua_pushobject (self->L, g_object_ref (export_core));
|
|
lua_settable (self->L, LUA_REGISTRYINDEX);
|
|
}
|
|
|
|
wp_lua_scripting_api_init (self->L);
|
|
wp_lua_scripting_enable_package_searcher (self->L);
|
|
wplua_enable_sandbox (self->L, WP_LUA_SANDBOX_ISOLATE_ENV);
|
|
|
|
/* register scripts that were queued in for loading */
|
|
for (guint i = 0; i < self->scripts->len; i++) {
|
|
WpPlugin *script = g_ptr_array_index (self->scripts, i);
|
|
g_object_set (script, "lua-engine", self->L, NULL);
|
|
wp_plugin_register (g_object_ref (script));
|
|
}
|
|
g_ptr_array_set_size (self->scripts, 0);
|
|
|
|
wp_object_update_features (WP_OBJECT (self), WP_PLUGIN_FEATURE_ENABLED, 0);
|
|
}
|
|
|
|
static void
|
|
wp_lua_scripting_plugin_disable (WpPlugin * plugin)
|
|
{
|
|
WpLuaScriptingPlugin * self = WP_LUA_SCRIPTING_PLUGIN (plugin);
|
|
g_clear_pointer (&self->L, wplua_unref);
|
|
}
|
|
|
|
static gboolean
|
|
wp_lua_scripting_plugin_supports_type (WpComponentLoader * cl,
|
|
const gchar * type)
|
|
{
|
|
return (!g_strcmp0 (type, "script/lua") || !g_strcmp0 (type, "config/lua"));
|
|
}
|
|
|
|
static gchar *
|
|
find_script (const gchar * script, WpCore *core)
|
|
{
|
|
g_autoptr (WpProperties) p = wp_core_get_properties (core);
|
|
const gchar *str = wp_properties_get (p, "wireplumber.daemon");
|
|
gboolean daemon = !g_strcmp0 (str, "true");
|
|
|
|
if ((!daemon || g_path_is_absolute (script)) &&
|
|
g_file_test (script, G_FILE_TEST_IS_REGULAR))
|
|
return g_strdup (script);
|
|
|
|
return wp_find_file (WP_LOOKUP_DIR_ENV_DATA |
|
|
WP_LOOKUP_DIR_XDG_CONFIG_HOME |
|
|
WP_LOOKUP_DIR_ETC |
|
|
WP_LOOKUP_DIR_PREFIX_SHARE,
|
|
script, "scripts");
|
|
}
|
|
|
|
static gboolean
|
|
wp_lua_scripting_plugin_load (WpComponentLoader * cl, const gchar * component,
|
|
const gchar * type, GVariant * args, GError ** error)
|
|
{
|
|
WpLuaScriptingPlugin * self = WP_LUA_SCRIPTING_PLUGIN (cl);
|
|
g_autoptr (WpCore) core = wp_object_get_core (WP_OBJECT (cl));
|
|
|
|
/* interpret component as a script */
|
|
if (!g_strcmp0 (type, "script/lua")) {
|
|
g_autofree gchar *filename = NULL;
|
|
g_autofree gchar *pluginname = NULL;
|
|
g_autoptr (WpPlugin) script = NULL;
|
|
|
|
filename = find_script (component, core);
|
|
if (!filename) {
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
|
|
"Could not locate script '%s'", component);
|
|
return FALSE;
|
|
}
|
|
|
|
pluginname = g_strdup_printf ("script:%s", component);
|
|
|
|
script = g_object_new (WP_TYPE_LUA_SCRIPT,
|
|
"core", core,
|
|
"name", pluginname,
|
|
"filename", filename,
|
|
"arguments", args,
|
|
NULL);
|
|
|
|
if (self->L) {
|
|
g_object_set (script, "lua-engine", self->L, NULL);
|
|
wp_plugin_register (g_steal_pointer (&script));
|
|
} else {
|
|
/* keep in a list and delay registering until the plugin is enabled */
|
|
wp_debug ("queing script %s", filename);
|
|
g_ptr_array_add (self->scripts, g_steal_pointer (&script));
|
|
}
|
|
return TRUE;
|
|
}
|
|
/* interpret component as a configuration file */
|
|
else if (!g_strcmp0 (type, "config/lua")) {
|
|
return wp_lua_scripting_load_configuration (component, core, error);
|
|
}
|
|
|
|
g_return_val_if_reached (FALSE);
|
|
}
|
|
|
|
static void
|
|
wp_lua_scripting_plugin_class_init (WpLuaScriptingPluginClass * klass)
|
|
{
|
|
GObjectClass *object_class = (GObjectClass *) klass;
|
|
WpPluginClass *plugin_class = (WpPluginClass *) klass;
|
|
WpComponentLoaderClass *cl_class = (WpComponentLoaderClass *) klass;
|
|
|
|
object_class->finalize = wp_lua_scripting_plugin_finalize;
|
|
|
|
plugin_class->enable = wp_lua_scripting_plugin_enable;
|
|
plugin_class->disable = wp_lua_scripting_plugin_disable;
|
|
|
|
cl_class->supports_type = wp_lua_scripting_plugin_supports_type;
|
|
cl_class->load = wp_lua_scripting_plugin_load;
|
|
}
|
|
|
|
WP_PLUGIN_EXPORT gboolean
|
|
wireplumber__module_init (WpCore * core, GVariant * args, GError ** error)
|
|
{
|
|
wp_plugin_register (g_object_new (wp_lua_scripting_plugin_get_type (),
|
|
"name", "lua-scripting",
|
|
"core", core,
|
|
NULL));
|
|
return TRUE;
|
|
}
|