
This allows scripts to declare when they have finished their loading, so we can now also know when wireplumber is done loading and ready to handle clients Related to !313
1436 lines
36 KiB
C
1436 lines
36 KiB
C
/* WirePlumber
|
|
*
|
|
* Copyright © 2020 Collabora Ltd.
|
|
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
*/
|
|
|
|
#include <glib/gstdio.h>
|
|
#include <wp/wp.h>
|
|
#include <pipewire/pipewire.h>
|
|
#include <wplua/wplua.h>
|
|
|
|
#define URI_API "resource:///org/freedesktop/pipewire/wireplumber/m-lua-scripting/api.lua"
|
|
|
|
void wp_lua_scripting_pod_init (lua_State *L);
|
|
void wp_lua_scripting_json_init (lua_State *L);
|
|
|
|
/* helpers */
|
|
|
|
static WpCore *
|
|
get_wp_core (lua_State *L)
|
|
{
|
|
WpCore *core = NULL;
|
|
lua_pushliteral (L, "wireplumber_core");
|
|
lua_gettable (L, LUA_REGISTRYINDEX);
|
|
core = lua_touserdata (L, -1);
|
|
lua_pop (L, 1);
|
|
return core;
|
|
}
|
|
|
|
static WpCore *
|
|
get_wp_export_core (lua_State *L)
|
|
{
|
|
WpCore *core = NULL;
|
|
lua_pushliteral (L, "wireplumber_export_core");
|
|
lua_gettable (L, LUA_REGISTRYINDEX);
|
|
if (wplua_isobject (L, -1, WP_TYPE_CORE))
|
|
core = wplua_toobject (L, -1);
|
|
lua_pop (L, 1);
|
|
return core ? core : get_wp_core(L);
|
|
}
|
|
|
|
/* GLib */
|
|
|
|
static int
|
|
glib_get_monotonic_time (lua_State *L)
|
|
{
|
|
lua_pushinteger (L, g_get_monotonic_time ());
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
glib_get_real_time (lua_State *L)
|
|
{
|
|
lua_pushinteger (L, g_get_real_time ());
|
|
return 1;
|
|
}
|
|
|
|
static gboolean
|
|
access_parse_mode (const gchar * mode_str, gint *mode)
|
|
{
|
|
*mode = 0;
|
|
|
|
if (!mode_str)
|
|
return FALSE;
|
|
else {
|
|
for (guint i = 0; i < strlen (mode_str); i++) {
|
|
switch (mode_str[i]) {
|
|
case 'r': *mode |= R_OK; break;
|
|
case 'w': *mode |= W_OK; break;
|
|
case 'x': *mode |= X_OK; break;
|
|
case 'f': *mode |= F_OK; break;
|
|
case '-': break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static int
|
|
glib_access (lua_State *L)
|
|
{
|
|
const gchar *filename = luaL_checkstring (L, 1);
|
|
int mode = 0;
|
|
if (!access_parse_mode (luaL_checkstring (L, 2), &mode))
|
|
luaL_error (L, "invalid mode string: '%s'", lua_tostring (L, 2));
|
|
lua_pushboolean (L, g_access (filename, mode) >= 0);
|
|
return 1;
|
|
}
|
|
|
|
static const luaL_Reg glib_methods[] = {
|
|
{ "get_monotonic_time", glib_get_monotonic_time },
|
|
{ "get_real_time", glib_get_real_time },
|
|
{ "access", glib_access },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* GSource */
|
|
|
|
static int
|
|
source_destroy (lua_State *L)
|
|
{
|
|
GSource *source = wplua_checkboxed (L, 1, G_TYPE_SOURCE);
|
|
g_source_destroy (source);
|
|
return 0;
|
|
}
|
|
|
|
static const luaL_Reg source_methods[] = {
|
|
{ "destroy", source_destroy },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* WpCore */
|
|
|
|
static int
|
|
core_get_info (lua_State *L)
|
|
{
|
|
WpCore * core = get_wp_core (L);
|
|
g_autoptr (WpProperties) p = wp_core_get_remote_properties (core);
|
|
|
|
lua_newtable (L);
|
|
lua_pushinteger (L, wp_core_get_remote_cookie (core));
|
|
lua_setfield (L, -2, "cookie");
|
|
lua_pushstring (L, wp_core_get_remote_name (core));
|
|
lua_setfield (L, -2, "name");
|
|
lua_pushstring (L, wp_core_get_remote_user_name (core));
|
|
lua_setfield (L, -2, "user_name");
|
|
lua_pushstring (L, wp_core_get_remote_host_name (core));
|
|
lua_setfield (L, -2, "host_name");
|
|
lua_pushstring (L, wp_core_get_remote_version (core));
|
|
lua_setfield (L, -2, "version");
|
|
wplua_properties_to_table (L, p);
|
|
lua_setfield (L, -2, "properties");
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
core_idle_add (lua_State *L)
|
|
{
|
|
GSource *source = NULL;
|
|
luaL_checktype (L, 1, LUA_TFUNCTION);
|
|
wp_core_idle_add_closure (get_wp_core (L), &source,
|
|
wplua_function_to_closure (L, 1));
|
|
wplua_pushboxed (L, G_TYPE_SOURCE, source);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
core_timeout_add (lua_State *L)
|
|
{
|
|
GSource *source = NULL;
|
|
lua_Integer timeout_ms = luaL_checkinteger (L, 1);
|
|
luaL_checktype (L, 2, LUA_TFUNCTION);
|
|
wp_core_timeout_add_closure (get_wp_core (L), &source, timeout_ms,
|
|
wplua_function_to_closure (L, 2));
|
|
wplua_pushboxed (L, G_TYPE_SOURCE, source);
|
|
return 1;
|
|
}
|
|
|
|
static void
|
|
on_core_done (WpCore * core, GAsyncResult * res, GClosure * closure)
|
|
{
|
|
g_autoptr (GError) error = NULL;
|
|
GValue val = G_VALUE_INIT;
|
|
int n_vals = 0;
|
|
|
|
if (!wp_core_sync_finish (core, res, &error)) {
|
|
g_value_init (&val, G_TYPE_STRING);
|
|
g_value_set_string (&val, error->message);
|
|
n_vals = 1;
|
|
}
|
|
g_closure_invoke (closure, NULL, n_vals, &val, NULL);
|
|
g_value_unset (&val);
|
|
g_closure_invalidate (closure);
|
|
g_closure_unref (closure);
|
|
}
|
|
|
|
static int
|
|
core_sync (lua_State *L)
|
|
{
|
|
luaL_checktype (L, 1, LUA_TFUNCTION);
|
|
GClosure * closure = wplua_function_to_closure (L, 1);
|
|
g_closure_sink (g_closure_ref (closure));
|
|
wp_core_sync (get_wp_core (L), NULL, (GAsyncReadyCallback) on_core_done,
|
|
closure);
|
|
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 *daemon = wp_properties_get (p, "wireplumber.daemon");
|
|
if (!g_strcmp0 (daemon, "true")) {
|
|
wp_warning ("script attempted to quit, but the engine is "
|
|
"running in the wireplumber daemon; 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;
|
|
}
|
|
|
|
#include "require.c"
|
|
|
|
static int
|
|
core_require_api (lua_State *L)
|
|
{
|
|
WpCore * core = get_wp_core (L);
|
|
g_autoptr (WpProperties) p = wp_core_get_properties (core);
|
|
const gchar *daemon = wp_properties_get (p, "wireplumber.daemon");
|
|
if (!g_strcmp0 (daemon, "true")) {
|
|
wp_warning ("script attempted to load an API module, but the engine is "
|
|
"running in the wireplumber daemon; ignoring");
|
|
return 0;
|
|
}
|
|
return wp_require_api_transition_new_from_lua (L, core);
|
|
}
|
|
|
|
static const luaL_Reg core_funcs[] = {
|
|
{ "get_info", core_get_info },
|
|
{ "idle_add", core_idle_add },
|
|
{ "timeout_add", core_timeout_add },
|
|
{ "sync", core_sync },
|
|
{ "quit", core_quit },
|
|
{ "require_api", core_require_api },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* WpLog */
|
|
|
|
static int
|
|
log_log (lua_State *L, GLogLevelFlags lvl)
|
|
{
|
|
lua_Debug ar = {0};
|
|
const gchar *message, *tmp;
|
|
gchar domain[25];
|
|
gchar line_str[11];
|
|
gconstpointer instance = NULL;
|
|
GType type = G_TYPE_INVALID;
|
|
int index = 1;
|
|
|
|
if (!wp_log_level_is_enabled (lvl))
|
|
return 0;
|
|
|
|
g_warn_if_fail (lua_getstack (L, 1, &ar) == 1);
|
|
g_warn_if_fail (lua_getinfo (L, "nSl", &ar) == 1);
|
|
|
|
if (wplua_isobject (L, 1, G_TYPE_OBJECT)) {
|
|
instance = wplua_toobject (L, 1);
|
|
type = G_TYPE_FROM_INSTANCE (instance);
|
|
index++;
|
|
}
|
|
else if (wplua_isboxed (L, 1, G_TYPE_BOXED)) {
|
|
instance = wplua_toboxed (L, 1);
|
|
type = wplua_gvalue_userdata_type (L, 1);
|
|
index++;
|
|
}
|
|
|
|
message = luaL_checkstring (L, index);
|
|
tmp = ar.source ? g_strrstr (ar.source, ".lua") : NULL;
|
|
snprintf (domain, 25, "script/%.*s",
|
|
tmp ? MIN((gint)(tmp - ar.source), 17) : 17,
|
|
ar.source);
|
|
snprintf (line_str, 11, "%d", ar.currentline);
|
|
ar.name = ar.name ? ar.name : "chunk";
|
|
|
|
wp_log_structured_standard (domain, lvl,
|
|
ar.source, line_str, ar.name, type, instance, "%s", message);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
log_warning (lua_State *L) { return log_log (L, G_LOG_LEVEL_WARNING); }
|
|
|
|
static int
|
|
log_message (lua_State *L) { return log_log (L, G_LOG_LEVEL_MESSAGE); }
|
|
|
|
static int
|
|
log_info (lua_State *L) { return log_log (L, G_LOG_LEVEL_INFO); }
|
|
|
|
static int
|
|
log_debug (lua_State *L) { return log_log (L, G_LOG_LEVEL_DEBUG); }
|
|
|
|
static int
|
|
log_trace (lua_State *L) { return log_log (L, WP_LOG_LEVEL_TRACE); }
|
|
|
|
static const luaL_Reg log_funcs[] = {
|
|
{ "warning", log_warning },
|
|
{ "message", log_message },
|
|
{ "info", log_info },
|
|
{ "debug", log_debug },
|
|
{ "trace", log_trace },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* WpPlugin */
|
|
|
|
static int
|
|
plugin_find (lua_State *L)
|
|
{
|
|
const char *name = luaL_checkstring (L, 1);
|
|
WpPlugin *plugin = wp_plugin_find (get_wp_core (L), name);
|
|
if (plugin)
|
|
wplua_pushobject (L, plugin);
|
|
else
|
|
lua_pushnil (L);
|
|
return 1;
|
|
}
|
|
|
|
static const luaL_Reg plugin_funcs[] = {
|
|
{ "find", plugin_find },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* WpObject */
|
|
|
|
static void
|
|
object_activate_done (WpObject *o, GAsyncResult * res, GClosure * closure)
|
|
{
|
|
g_autoptr (GError) error = NULL;
|
|
GValue val[2] = { G_VALUE_INIT, G_VALUE_INIT };
|
|
int n_vals = 1;
|
|
|
|
if (!wp_object_activate_finish (o, res, &error)) {
|
|
wp_message_object (o, "%s", error->message);
|
|
if (closure) {
|
|
g_value_init (&val[1], G_TYPE_STRING);
|
|
g_value_set_string (&val[1], error->message);
|
|
n_vals = 2;
|
|
}
|
|
}
|
|
if (closure) {
|
|
g_value_init_from_instance (&val[0], o);
|
|
g_closure_invoke (closure, NULL, n_vals, val, NULL);
|
|
g_value_unset (&val[0]);
|
|
g_value_unset (&val[1]);
|
|
g_closure_invalidate (closure);
|
|
g_closure_unref (closure);
|
|
}
|
|
}
|
|
|
|
static int
|
|
object_activate (lua_State *L)
|
|
{
|
|
WpObject *o = wplua_checkobject (L, 1, WP_TYPE_OBJECT);
|
|
WpObjectFeatures features = luaL_checkinteger (L, 2);
|
|
GClosure * closure = luaL_opt (L, wplua_checkclosure, 3, NULL);
|
|
if (closure)
|
|
g_closure_sink (g_closure_ref (closure));
|
|
wp_object_activate (o, features, NULL,
|
|
(GAsyncReadyCallback) object_activate_done, closure);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
object_deactivate (lua_State *L)
|
|
{
|
|
WpObject *o = wplua_checkobject (L, 1, WP_TYPE_OBJECT);
|
|
WpObjectFeatures features = luaL_checkinteger (L, 2);
|
|
wp_object_deactivate (o, features);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
object_get_active_features (lua_State *L)
|
|
{
|
|
WpObject *o = wplua_checkobject (L, 1, WP_TYPE_OBJECT);
|
|
WpObjectFeatures features = wp_object_get_active_features (o);
|
|
lua_pushinteger (L, features);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
object_get_supported_features (lua_State *L)
|
|
{
|
|
WpObject *o = wplua_checkobject (L, 1, WP_TYPE_OBJECT);
|
|
WpObjectFeatures features = wp_object_get_supported_features (o);
|
|
lua_pushinteger (L, features);
|
|
return 1;
|
|
}
|
|
|
|
static const luaL_Reg object_methods[] = {
|
|
{ "activate", object_activate },
|
|
{ "deactivate", object_deactivate },
|
|
{ "get_active_features", object_get_active_features },
|
|
{ "get_supported_features", object_get_supported_features },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* WpProxy */
|
|
|
|
static int
|
|
proxy_get_interface_type (lua_State *L)
|
|
{
|
|
WpProxy * p = wplua_checkobject (L, 1, WP_TYPE_PROXY);
|
|
guint32 version = 0;
|
|
const gchar *type = wp_proxy_get_interface_type (p, &version);
|
|
lua_pushstring (L, type);
|
|
lua_pushinteger (L, version);
|
|
return 2;
|
|
}
|
|
|
|
static const luaL_Reg proxy_methods[] = {
|
|
{ "get_interface_type", proxy_get_interface_type },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* WpGlobalProxy */
|
|
|
|
static int
|
|
global_proxy_request_destroy (lua_State *L)
|
|
{
|
|
WpGlobalProxy * p = wplua_checkobject (L, 1, WP_TYPE_GLOBAL_PROXY);
|
|
wp_global_proxy_request_destroy (p);
|
|
return 0;
|
|
}
|
|
|
|
static const luaL_Reg global_proxy_methods[] = {
|
|
{ "request_destroy", global_proxy_request_destroy },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* WpIterator */
|
|
|
|
static int
|
|
iterator_next (lua_State *L)
|
|
{
|
|
WpIterator *it = wplua_checkboxed (L, 1, WP_TYPE_ITERATOR);
|
|
g_auto (GValue) v = G_VALUE_INIT;
|
|
if (it && wp_iterator_next (it, &v)) {
|
|
return wplua_gvalue_to_lua (L, &v);
|
|
} else {
|
|
lua_pushnil (L);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
static int
|
|
push_wpiterator (lua_State *L, WpIterator *it)
|
|
{
|
|
lua_pushcfunction (L, iterator_next);
|
|
wplua_pushboxed (L, WP_TYPE_ITERATOR, it);
|
|
return 2;
|
|
}
|
|
|
|
/* Metadata WpIterator */
|
|
|
|
static int
|
|
metadata_iterator_next (lua_State *L)
|
|
{
|
|
WpIterator *it = wplua_checkboxed (L, 1, WP_TYPE_ITERATOR);
|
|
g_auto (GValue) item = G_VALUE_INIT;
|
|
if (wp_iterator_next (it, &item)) {
|
|
guint32 s = 0;
|
|
const gchar *k = NULL, *t = NULL, *v = NULL;
|
|
wp_metadata_iterator_item_extract (&item, &s, &k, &t, &v);
|
|
lua_pushinteger (L, s);
|
|
lua_pushstring (L, k);
|
|
lua_pushstring (L, t);
|
|
lua_pushstring (L, v);
|
|
return 4;
|
|
} else {
|
|
lua_pushnil (L);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
static int
|
|
push_metadata_wpiterator (lua_State *L, WpIterator *it)
|
|
{
|
|
lua_pushcfunction (L, metadata_iterator_next);
|
|
wplua_pushboxed (L, WP_TYPE_ITERATOR, it);
|
|
return 2;
|
|
}
|
|
|
|
/* WpObjectInterest */
|
|
|
|
static GVariant *
|
|
constraint_value_to_variant (lua_State *L, int idx)
|
|
{
|
|
switch (lua_type (L, idx)) {
|
|
case LUA_TBOOLEAN:
|
|
return g_variant_new_boolean (lua_toboolean (L, idx));
|
|
case LUA_TSTRING:
|
|
return g_variant_new_string (lua_tostring (L, idx));
|
|
case LUA_TNUMBER:
|
|
if (lua_isinteger (L, idx))
|
|
return g_variant_new_int64 (lua_tointeger (L, idx));
|
|
else
|
|
return g_variant_new_double (lua_tonumber (L, idx));
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
static void
|
|
object_interest_new_add_constraint (lua_State *L, GType type,
|
|
WpObjectInterest *interest)
|
|
{
|
|
int constraint_idx;
|
|
WpConstraintType ctype;
|
|
const gchar *subject;
|
|
WpConstraintVerb verb;
|
|
GVariant *value = NULL;
|
|
|
|
constraint_idx = lua_absindex (L, -1);
|
|
|
|
/* verify this is a Constraint{} */
|
|
if (lua_type (L, constraint_idx) != LUA_TTABLE) {
|
|
luaL_error (L, "Interest: expected Constraint at index %d",
|
|
lua_tointeger (L, -2));
|
|
}
|
|
|
|
if (luaL_getmetafield (L, constraint_idx, "__name") == LUA_TNIL ||
|
|
g_strcmp0 (lua_tostring (L, -1), "Constraint") != 0) {
|
|
luaL_error (L, "Interest: expected Constraint at index %d",
|
|
lua_tointeger (L, -2));
|
|
}
|
|
lua_pop (L, 1);
|
|
|
|
/* get the constraint type */
|
|
lua_pushliteral (L, "type");
|
|
if (lua_gettable (L, constraint_idx) == LUA_TNUMBER)
|
|
ctype = lua_tointeger (L, -1);
|
|
else
|
|
ctype = WP_CONSTRAINT_TYPE_PW_GLOBAL_PROPERTY;
|
|
lua_pop (L, 1);
|
|
|
|
/* get t[1] (the subject) and t[2] (the verb) */
|
|
lua_geti (L, constraint_idx, 1);
|
|
subject = lua_tostring (L, -1);
|
|
|
|
lua_geti (L, constraint_idx, 2);
|
|
verb = lua_tostring (L, -1)[0];
|
|
|
|
switch (verb) {
|
|
case WP_CONSTRAINT_VERB_EQUALS:
|
|
case WP_CONSTRAINT_VERB_NOT_EQUALS:
|
|
case WP_CONSTRAINT_VERB_MATCHES: {
|
|
lua_geti (L, constraint_idx, 3);
|
|
value = constraint_value_to_variant (L, -1);
|
|
if (G_UNLIKELY (!value))
|
|
luaL_error (L, "Constraint: bad value type");
|
|
break;
|
|
}
|
|
case WP_CONSTRAINT_VERB_IN_RANGE: {
|
|
GVariant *values[2];
|
|
lua_geti (L, constraint_idx, 3);
|
|
lua_geti (L, constraint_idx, 4);
|
|
values[0] = constraint_value_to_variant (L, -2);
|
|
values[1] = constraint_value_to_variant (L, -1);
|
|
if (G_UNLIKELY (!values[0] || !values[1])) {
|
|
g_clear_pointer (&values[0], g_variant_unref);
|
|
g_clear_pointer (&values[1], g_variant_unref);
|
|
luaL_error (L, "Constraint: bad value type");
|
|
}
|
|
value = g_variant_new_tuple (values, 2);
|
|
break;
|
|
}
|
|
case WP_CONSTRAINT_VERB_IN_LIST: {
|
|
GPtrArray *values =
|
|
g_ptr_array_new_with_free_func ((GDestroyNotify) g_variant_unref);
|
|
int i = 3;
|
|
while (lua_geti (L, constraint_idx, i++) != LUA_TNIL) {
|
|
GVariant *tmp = constraint_value_to_variant (L, -1);
|
|
if (G_UNLIKELY (!tmp)) {
|
|
g_ptr_array_unref (values);
|
|
luaL_error (L, "Constraint: bad value type");
|
|
}
|
|
g_ptr_array_add (values, g_variant_ref_sink (tmp));
|
|
lua_pop (L, 1);
|
|
}
|
|
value = g_variant_new_tuple ((GVariant **) values->pdata, values->len);
|
|
g_ptr_array_unref (values);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
wp_object_interest_add_constraint (interest, ctype, subject, verb, value);
|
|
lua_settop (L, constraint_idx);
|
|
}
|
|
|
|
static GType
|
|
parse_gtype (const gchar *str)
|
|
{
|
|
g_autofree gchar *typestr = NULL;
|
|
GType res = G_TYPE_INVALID;
|
|
|
|
g_return_val_if_fail (str, res);
|
|
|
|
/* "device" -> "WpDevice" */
|
|
typestr = g_strdup_printf ("Wp%s", str);
|
|
if (typestr[2] != 0) {
|
|
typestr[2] = g_ascii_toupper (typestr[2]);
|
|
res = g_type_from_name (typestr);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
static int
|
|
object_interest_new_index (lua_State *L, int idx, GType def_type)
|
|
{
|
|
WpObjectInterest *interest = NULL;
|
|
GType type = def_type;
|
|
|
|
luaL_checktype (L, idx, LUA_TTABLE);
|
|
|
|
/* type = "string" */
|
|
lua_pushliteral (L, "type");
|
|
if (lua_gettable (L, idx) == LUA_TSTRING) {
|
|
type = parse_gtype (lua_tostring (L, -1));
|
|
if (type == G_TYPE_INVALID)
|
|
luaL_error (L, "Interest: unknown type '%s'", lua_tostring (L, -1));
|
|
}
|
|
else if (def_type == G_TYPE_INVALID)
|
|
luaL_error (L, "Interest: expected 'type' as string");
|
|
lua_pop (L, 1);
|
|
|
|
interest = wp_object_interest_new_type (type);
|
|
wplua_pushboxed (L, WP_TYPE_OBJECT_INTEREST, interest);
|
|
|
|
/* add constraints */
|
|
lua_pushnil (L);
|
|
while (lua_next (L, idx)) {
|
|
/* if the key isn't "type" */
|
|
if (!(lua_type (L, -2) == LUA_TSTRING &&
|
|
!g_strcmp0 ("type", lua_tostring (L, -2))))
|
|
object_interest_new_add_constraint (L, type, interest);
|
|
lua_pop (L, 1);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
object_interest_new (lua_State *L)
|
|
{
|
|
return object_interest_new_index (L, 1, G_TYPE_INVALID);
|
|
}
|
|
|
|
static int
|
|
object_interest_matches (lua_State *L)
|
|
{
|
|
WpObjectInterest *interest = wplua_checkboxed (L, 1, WP_TYPE_OBJECT_INTEREST);
|
|
gboolean matches = FALSE;
|
|
|
|
if (wplua_isobject (L, 2, G_TYPE_OBJECT)) {
|
|
matches = wp_object_interest_matches (interest, wplua_toobject (L, 2));
|
|
}
|
|
else if (lua_istable (L, 2)) {
|
|
g_autoptr (WpProperties) props = wplua_table_to_properties (L, 2);
|
|
matches = wp_object_interest_matches (interest, props);
|
|
} else
|
|
luaL_argerror (L, 2, "expected GObject or table");
|
|
|
|
lua_pushboolean (L, matches);
|
|
return 1;
|
|
}
|
|
|
|
static const luaL_Reg object_interest_methods[] = {
|
|
{ "matches", object_interest_matches },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
static WpObjectInterest *
|
|
get_optional_object_interest (lua_State *L, int idx, GType def_type)
|
|
{
|
|
if (lua_isnoneornil (L, idx))
|
|
return NULL;
|
|
else if (lua_isuserdata (L, idx))
|
|
return wplua_checkboxed (L, idx, WP_TYPE_OBJECT_INTEREST);
|
|
else if (lua_istable (L, idx)) {
|
|
object_interest_new_index (L, idx, def_type);
|
|
return wplua_toboxed (L, -1);
|
|
} else {
|
|
luaL_error (L, "expected Interest or none/nil");
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/* WpObjectManager */
|
|
|
|
static int
|
|
object_manager_new (lua_State *L)
|
|
{
|
|
WpObjectManager *om;
|
|
|
|
/* validate arguments */
|
|
luaL_checktype (L, 1, LUA_TTABLE);
|
|
|
|
/* push to Lua asap to have a way to unref in case of error */
|
|
om = wp_object_manager_new ();
|
|
wplua_pushobject (L, om);
|
|
|
|
lua_pushnil (L);
|
|
while (lua_next (L, 1)) {
|
|
WpObjectInterest *interest =
|
|
wplua_checkboxed (L, -1, WP_TYPE_OBJECT_INTEREST);
|
|
wp_object_manager_add_interest_full (om, wp_object_interest_ref (interest));
|
|
lua_pop (L, 1);
|
|
}
|
|
|
|
/* request all the features for Lua scripts to make their job easier */
|
|
wp_object_manager_request_object_features (om,
|
|
WP_TYPE_OBJECT, WP_OBJECT_FEATURES_ALL);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
object_manager_activate (lua_State *L)
|
|
{
|
|
WpObjectManager *om = wplua_checkobject (L, 1, WP_TYPE_OBJECT_MANAGER);
|
|
wp_core_install_object_manager (get_wp_core (L), om);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
object_manager_get_n_objects (lua_State *L)
|
|
{
|
|
WpObjectManager *om = wplua_checkobject (L, 1, WP_TYPE_OBJECT_MANAGER);
|
|
lua_pushinteger (L, wp_object_manager_get_n_objects (om));
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
object_manager_iterate (lua_State *L)
|
|
{
|
|
WpObjectManager *om = wplua_checkobject (L, 1, WP_TYPE_OBJECT_MANAGER);
|
|
WpObjectInterest *oi = get_optional_object_interest (L, 2, G_TYPE_OBJECT);
|
|
WpIterator *it = oi ?
|
|
wp_object_manager_new_filtered_iterator_full (om,
|
|
wp_object_interest_ref (oi)) :
|
|
wp_object_manager_new_iterator (om);
|
|
return push_wpiterator (L, it);
|
|
}
|
|
|
|
static int
|
|
object_manager_lookup (lua_State *L)
|
|
{
|
|
WpObjectManager *om = wplua_checkobject (L, 1, WP_TYPE_OBJECT_MANAGER);
|
|
WpObjectInterest *oi = get_optional_object_interest (L, 2, G_TYPE_OBJECT);
|
|
WpObject *o = oi ?
|
|
wp_object_manager_lookup_full (om, wp_object_interest_ref (oi)) :
|
|
wp_object_manager_lookup (om, G_TYPE_OBJECT, NULL);
|
|
if (o) {
|
|
wplua_pushobject (L, o);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static const luaL_Reg object_manager_methods[] = {
|
|
{ "activate", object_manager_activate },
|
|
{ "get_n_objects", object_manager_get_n_objects },
|
|
{ "iterate", object_manager_iterate },
|
|
{ "lookup", object_manager_lookup },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* WpMetadata */
|
|
|
|
static int
|
|
metadata_iterate (lua_State *L)
|
|
{
|
|
WpMetadata *metadata = wplua_checkobject (L, 1, WP_TYPE_METADATA);
|
|
lua_Integer subject = luaL_checkinteger (L, 2);
|
|
WpIterator *it = wp_metadata_new_iterator (metadata, subject);
|
|
return push_metadata_wpiterator (L, it);
|
|
}
|
|
|
|
static int
|
|
metadata_find (lua_State *L)
|
|
{
|
|
WpMetadata *metadata = wplua_checkobject (L, 1, WP_TYPE_METADATA);
|
|
lua_Integer subject = luaL_checkinteger (L, 2);
|
|
const char *key = luaL_checkstring (L, 3), *v = NULL, *t = NULL;
|
|
v = wp_metadata_find (metadata, subject, key, &t);
|
|
lua_pushstring (L, v);
|
|
lua_pushstring (L, t);
|
|
return 2;
|
|
}
|
|
|
|
static int
|
|
metadata_set (lua_State *L)
|
|
{
|
|
WpMetadata *metadata = wplua_checkobject (L, 1, WP_TYPE_METADATA);
|
|
lua_Integer subject = luaL_checkinteger (L, 2);
|
|
const char *key = luaL_opt (L, luaL_checkstring, 3, NULL);
|
|
const char *type = luaL_opt (L, luaL_checkstring, 4, NULL);
|
|
const char *value = luaL_opt (L, luaL_checkstring, 5, NULL);
|
|
wp_metadata_set (metadata, subject, key, type, value);
|
|
return 0;
|
|
}
|
|
|
|
static const luaL_Reg metadata_methods[] = {
|
|
{ "iterate", metadata_iterate },
|
|
{ "find", metadata_find },
|
|
{ "set", metadata_set },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* WpImplMetadata */
|
|
|
|
static int
|
|
impl_metadata_new (lua_State *L)
|
|
{
|
|
const char *name = luaL_checkstring (L, 1);
|
|
WpProperties *properties = NULL;
|
|
|
|
if (lua_type (L, 2) != LUA_TNONE) {
|
|
luaL_checktype (L, 2, LUA_TTABLE);
|
|
properties = wplua_table_to_properties (L, 2);
|
|
}
|
|
|
|
WpImplMetadata *m = wp_impl_metadata_new_full (get_wp_core (L),
|
|
name, properties);
|
|
if (m)
|
|
wplua_pushobject (L, m);
|
|
return m ? 1 : 0;
|
|
}
|
|
|
|
/* WpEndpoint */
|
|
|
|
static const luaL_Reg endpoint_methods[] = {
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* Device */
|
|
|
|
static int
|
|
device_new (lua_State *L)
|
|
{
|
|
const char *factory = luaL_checkstring (L, 1);
|
|
WpProperties *properties = NULL;
|
|
|
|
if (lua_type (L, 2) != LUA_TNONE) {
|
|
luaL_checktype (L, 2, LUA_TTABLE);
|
|
properties = wplua_table_to_properties (L, 2);
|
|
}
|
|
|
|
WpDevice *d = wp_device_new_from_factory (get_wp_export_core (L),
|
|
factory, properties);
|
|
if (d)
|
|
wplua_pushobject (L, d);
|
|
return d ? 1 : 0;
|
|
}
|
|
|
|
/* WpSpaDevice */
|
|
|
|
static int
|
|
spa_device_new (lua_State *L)
|
|
{
|
|
const char *factory = luaL_checkstring (L, 1);
|
|
WpProperties *properties = NULL;
|
|
|
|
if (lua_type (L, 2) != LUA_TNONE) {
|
|
luaL_checktype (L, 2, LUA_TTABLE);
|
|
properties = wplua_table_to_properties (L, 2);
|
|
}
|
|
|
|
WpSpaDevice *d = wp_spa_device_new_from_spa_factory (get_wp_export_core (L),
|
|
factory, properties);
|
|
if (d)
|
|
wplua_pushobject (L, d);
|
|
return d ? 1 : 0;
|
|
}
|
|
|
|
static int
|
|
spa_device_get_managed_object (lua_State *L)
|
|
{
|
|
WpSpaDevice *device = wplua_checkobject (L, 1, WP_TYPE_SPA_DEVICE);
|
|
guint id = luaL_checkinteger (L, 2);
|
|
GObject *obj = wp_spa_device_get_managed_object (device, id);
|
|
if (obj)
|
|
wplua_pushobject (L, obj);
|
|
return obj ? 1 : 0;
|
|
}
|
|
|
|
static int
|
|
spa_device_store_managed_object (lua_State *L)
|
|
{
|
|
WpSpaDevice *device = wplua_checkobject (L, 1, WP_TYPE_SPA_DEVICE);
|
|
guint id = luaL_checkinteger (L, 2);
|
|
GObject *obj = (lua_type (L, 3) != LUA_TNIL) ?
|
|
g_object_ref (wplua_checkobject (L, 3, G_TYPE_OBJECT)) : NULL;
|
|
|
|
wp_spa_device_store_managed_object (device, id, obj);
|
|
return 0;
|
|
}
|
|
|
|
static const luaL_Reg spa_device_methods[] = {
|
|
{ "get_managed_object", spa_device_get_managed_object },
|
|
{ "store_managed_object", spa_device_store_managed_object },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* Node */
|
|
|
|
static int
|
|
node_new (lua_State *L)
|
|
{
|
|
const char *factory = luaL_checkstring (L, 1);
|
|
WpProperties *properties = NULL;
|
|
|
|
if (lua_type (L, 2) != LUA_TNONE) {
|
|
luaL_checktype (L, 2, LUA_TTABLE);
|
|
properties = wplua_table_to_properties (L, 2);
|
|
}
|
|
|
|
WpNode *d = wp_node_new_from_factory (get_wp_export_core (L),
|
|
factory, properties);
|
|
if (d)
|
|
wplua_pushobject (L, d);
|
|
return d ? 1 : 0;
|
|
}
|
|
|
|
static int
|
|
node_get_state (lua_State *L)
|
|
{
|
|
WpNode *node = wplua_checkobject (L, 1, WP_TYPE_NODE);
|
|
const gchar *error = NULL;
|
|
WpNodeState state = wp_node_get_state (node, &error);
|
|
wplua_enum_to_lua (L, state, WP_TYPE_NODE_STATE);
|
|
lua_pushstring (L, error ? error : "");
|
|
return 2;
|
|
}
|
|
|
|
static int
|
|
node_get_n_input_ports (lua_State *L)
|
|
{
|
|
WpNode *node = wplua_checkobject (L, 1, WP_TYPE_NODE);
|
|
guint max = 0;
|
|
guint ports = wp_node_get_n_input_ports (node, &max);
|
|
lua_pushinteger (L, ports);
|
|
lua_pushinteger (L, max);
|
|
return 2;
|
|
}
|
|
|
|
static int
|
|
node_get_n_output_ports (lua_State *L)
|
|
{
|
|
WpNode *node = wplua_checkobject (L, 1, WP_TYPE_NODE);
|
|
guint max = 0;
|
|
guint ports = wp_node_get_n_output_ports (node, &max);
|
|
lua_pushinteger (L, ports);
|
|
lua_pushinteger (L, max);
|
|
return 2;
|
|
}
|
|
|
|
static int
|
|
node_get_n_ports (lua_State *L)
|
|
{
|
|
WpNode *node = wplua_checkobject (L, 1, WP_TYPE_NODE);
|
|
guint ports = wp_node_get_n_ports (node);
|
|
lua_pushinteger (L, ports);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
node_iterate_ports (lua_State *L)
|
|
{
|
|
WpNode *node = wplua_checkobject (L, 1, WP_TYPE_NODE);
|
|
WpObjectInterest *oi = get_optional_object_interest (L, 2, WP_TYPE_PORT);
|
|
WpIterator *it = oi ?
|
|
wp_node_new_ports_filtered_iterator_full (node,
|
|
wp_object_interest_ref (oi)) :
|
|
wp_node_new_ports_iterator (node);
|
|
return push_wpiterator (L, it);
|
|
}
|
|
|
|
static int
|
|
node_lookup_port (lua_State *L)
|
|
{
|
|
WpNode *node = wplua_checkobject (L, 1, WP_TYPE_NODE);
|
|
WpObjectInterest *oi = get_optional_object_interest (L, 2, WP_TYPE_PORT);
|
|
WpPort *port = oi ?
|
|
wp_node_lookup_port_full (node, wp_object_interest_ref (oi)) :
|
|
wp_node_lookup_port (node, G_TYPE_OBJECT, NULL);
|
|
if (port) {
|
|
wplua_pushobject (L, port);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
node_send_command (lua_State *L)
|
|
{
|
|
WpNode *node = wplua_checkobject (L, 1, WP_TYPE_NODE);
|
|
const char *command = luaL_checkstring (L, 2);
|
|
wp_node_send_command (node, command);
|
|
return 0;
|
|
}
|
|
|
|
static const luaL_Reg node_methods[] = {
|
|
{ "get_state", node_get_state },
|
|
{ "get_n_input_ports", node_get_n_input_ports },
|
|
{ "get_n_output_ports", node_get_n_output_ports },
|
|
{ "get_n_ports", node_get_n_ports },
|
|
{ "iterate_ports", node_iterate_ports },
|
|
{ "lookup_port", node_lookup_port },
|
|
{ "send_command", node_send_command },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* ImplNode */
|
|
|
|
static int
|
|
impl_node_new (lua_State *L)
|
|
{
|
|
const char *factory = luaL_checkstring (L, 1);
|
|
WpProperties *properties = NULL;
|
|
|
|
if (lua_type (L, 2) != LUA_TNONE) {
|
|
luaL_checktype (L, 2, LUA_TTABLE);
|
|
properties = wplua_table_to_properties (L, 2);
|
|
}
|
|
|
|
WpImplNode *d = wp_impl_node_new_from_pw_factory (get_wp_export_core (L),
|
|
factory, properties);
|
|
if (d)
|
|
wplua_pushobject (L, d);
|
|
return d ? 1 : 0;
|
|
}
|
|
|
|
/* Port */
|
|
|
|
static int
|
|
port_get_direction (lua_State *L)
|
|
{
|
|
WpPort *port = wplua_checkobject (L, 1, WP_TYPE_PORT);
|
|
WpDirection direction = wp_port_get_direction (port);
|
|
wplua_enum_to_lua (L, direction, WP_TYPE_DIRECTION);
|
|
return 1;
|
|
}
|
|
|
|
static const luaL_Reg port_methods[] = {
|
|
{ "get_direction", port_get_direction },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* Link */
|
|
|
|
static int
|
|
link_new (lua_State *L)
|
|
{
|
|
const char *factory = luaL_checkstring (L, 1);
|
|
WpProperties *properties = NULL;
|
|
|
|
if (lua_type (L, 2) != LUA_TNONE) {
|
|
luaL_checktype (L, 2, LUA_TTABLE);
|
|
properties = wplua_table_to_properties (L, 2);
|
|
}
|
|
|
|
WpLink *l = wp_link_new_from_factory (get_wp_core (L), factory, properties);
|
|
if (l)
|
|
wplua_pushobject (L, l);
|
|
return l ? 1 : 0;
|
|
}
|
|
|
|
/* Client */
|
|
|
|
static gboolean
|
|
client_parse_permissions (const gchar * perms_str, guint32 *perms)
|
|
{
|
|
*perms = 0;
|
|
|
|
if (!perms_str)
|
|
return FALSE;
|
|
else if (g_strcmp0 (perms_str, "all") == 0)
|
|
*perms = PW_PERM_ALL;
|
|
else {
|
|
for (guint i = 0; i < strlen (perms_str); i++) {
|
|
switch (perms_str[i]) {
|
|
case 'r': *perms |= PW_PERM_R; break;
|
|
case 'w': *perms |= PW_PERM_W; break;
|
|
case 'x': *perms |= PW_PERM_X; break;
|
|
case 'm': *perms |= PW_PERM_M; break;
|
|
case '-': break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static int
|
|
client_update_permissions (lua_State *L)
|
|
{
|
|
WpClient *client = wplua_checkobject (L, 1, WP_TYPE_CLIENT);
|
|
g_autoptr (GArray) arr = NULL;
|
|
|
|
luaL_checktype (L, 2, LUA_TTABLE);
|
|
|
|
lua_pushnil(L);
|
|
while (lua_next (L, -2)) {
|
|
struct pw_permission perm = {0};
|
|
|
|
if (lua_type (L, -2) == LUA_TSTRING &&
|
|
(!g_ascii_strcasecmp (lua_tostring(L, -2), "any") ||
|
|
!g_ascii_strcasecmp (lua_tostring(L, -2), "all")))
|
|
perm.id = PW_ID_ANY;
|
|
else if (lua_isinteger (L, -2))
|
|
perm.id = lua_tointeger (L, -2);
|
|
else
|
|
luaL_error (L, "invalid key for permissions array");
|
|
|
|
if (!client_parse_permissions (lua_tostring (L, -1), &perm.permissions))
|
|
luaL_error (L, "invalid permission string: '%s'", lua_tostring (L, -1));
|
|
|
|
if (!arr)
|
|
arr = g_array_new (FALSE, FALSE, sizeof (struct pw_permission));
|
|
|
|
g_array_append_val (arr, perm);
|
|
lua_pop (L, 1);
|
|
}
|
|
|
|
wp_client_update_permissions_array (client, arr->len,
|
|
(const struct pw_permission *) arr->data);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
client_send_error (lua_State *L)
|
|
{
|
|
WpClient *client = wplua_checkobject (L, 1, WP_TYPE_CLIENT);
|
|
guint id = luaL_checkinteger (L, 2);
|
|
int res = luaL_checkinteger (L, 3);
|
|
const char *message = luaL_checkstring (L, 4);
|
|
wp_client_send_error (client, id, res, message);
|
|
return 0;
|
|
}
|
|
|
|
static const luaL_Reg client_methods[] = {
|
|
{ "update_permissions", client_update_permissions },
|
|
{ "send_error", client_send_error },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* WpSessionItem */
|
|
|
|
static int
|
|
session_item_new (lua_State *L)
|
|
{
|
|
const char *type = luaL_checkstring (L, 1);
|
|
WpSessionItem *si = wp_session_item_make (get_wp_core (L), type);
|
|
if (si)
|
|
wplua_pushobject (L, si);
|
|
return si ? 1 : 0;
|
|
}
|
|
|
|
static int
|
|
session_item_get_associated_proxy (lua_State *L)
|
|
{
|
|
WpSessionItem *si = wplua_checkobject (L, 1, WP_TYPE_SESSION_ITEM);
|
|
const char *typestr = luaL_checkstring (L, 2);
|
|
WpProxy *proxy = wp_session_item_get_associated_proxy (si,
|
|
parse_gtype (typestr));
|
|
if (proxy)
|
|
wplua_pushobject (L, proxy);
|
|
return proxy ? 1 : 0;
|
|
}
|
|
|
|
static int
|
|
session_item_reset (lua_State *L)
|
|
{
|
|
WpSessionItem *si = wplua_checkobject (L, 1, WP_TYPE_SESSION_ITEM);
|
|
wp_session_item_reset (si);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
session_item_configure (lua_State *L)
|
|
{
|
|
WpSessionItem *si = wplua_checkobject (L, 1, WP_TYPE_SESSION_ITEM);
|
|
WpProperties *props = wp_properties_new_empty ();
|
|
|
|
/* validate arguments */
|
|
luaL_checktype (L, 2, LUA_TTABLE);
|
|
|
|
/* build the configuration properties */
|
|
lua_pushnil (L);
|
|
while (lua_next (L, 2)) {
|
|
const gchar *key = NULL;
|
|
g_autofree gchar *var = NULL;
|
|
|
|
switch (lua_type (L, -1)) {
|
|
case LUA_TBOOLEAN:
|
|
var = g_strdup_printf ("%u", lua_toboolean (L, -1));
|
|
break;
|
|
case LUA_TNUMBER:
|
|
if (lua_isinteger (L, -1))
|
|
var = g_strdup_printf ("%lld", lua_tointeger (L, -1));
|
|
else
|
|
var = g_strdup_printf ("%f", lua_tonumber (L, -1));
|
|
break;
|
|
case LUA_TSTRING:
|
|
var = g_strdup (lua_tostring (L, -1));
|
|
break;
|
|
case LUA_TUSERDATA: {
|
|
GValue *v = lua_touserdata (L, -1);
|
|
gpointer p = g_value_peek_pointer (v);
|
|
var = g_strdup_printf ("%p", p);
|
|
break;
|
|
}
|
|
default:
|
|
luaL_error (L, "configure does not support lua type ",
|
|
lua_typename(L, lua_type(L, -1)));
|
|
break;
|
|
}
|
|
|
|
key = luaL_tolstring (L, -2, NULL);
|
|
wp_properties_set (props, key, var);
|
|
lua_pop (L, 2);
|
|
}
|
|
|
|
lua_pushboolean (L, wp_session_item_configure (si, props));
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
session_item_register (lua_State *L)
|
|
{
|
|
WpSessionItem *si = wplua_checkobject (L, 1, WP_TYPE_SESSION_ITEM);
|
|
wp_session_item_register (g_object_ref (si));
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
session_item_remove (lua_State *L)
|
|
{
|
|
WpSessionItem *si = wplua_checkobject (L, 1, WP_TYPE_SESSION_ITEM);
|
|
wp_session_item_remove (si);
|
|
return 0;
|
|
}
|
|
|
|
static const luaL_Reg session_item_methods[] = {
|
|
{ "get_associated_proxy", session_item_get_associated_proxy },
|
|
{ "reset", session_item_reset },
|
|
{ "configure", session_item_configure },
|
|
{ "register", session_item_register },
|
|
{ "remove", session_item_remove },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* WpPipewireObject */
|
|
|
|
static int
|
|
pipewire_object_iterate_params (lua_State *L)
|
|
{
|
|
WpPipewireObject *pwobj = wplua_checkobject (L, 1, WP_TYPE_PIPEWIRE_OBJECT);
|
|
const gchar *id = luaL_checkstring (L, 2);
|
|
WpIterator *it = wp_pipewire_object_enum_params_sync (pwobj, id, NULL);
|
|
return push_wpiterator (L, it);
|
|
}
|
|
|
|
static int
|
|
pipewire_object_set_param (lua_State *L)
|
|
{
|
|
WpPipewireObject *pwobj = wplua_checkobject (L, 1, WP_TYPE_PIPEWIRE_OBJECT);
|
|
const gchar *id = luaL_checkstring (L, 2);
|
|
WpSpaPod *pod = wplua_checkboxed (L, 3, WP_TYPE_SPA_POD);
|
|
wp_pipewire_object_set_param (pwobj, id, 0, wp_spa_pod_ref (pod));
|
|
return 0;
|
|
}
|
|
|
|
static const luaL_Reg pipewire_object_methods[] = {
|
|
{ "iterate_params", pipewire_object_iterate_params },
|
|
{ "set_param" , pipewire_object_set_param },
|
|
{ "set_params" , pipewire_object_set_param }, /* deprecated, compat only */
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* WpState */
|
|
|
|
static int
|
|
state_new (lua_State *L)
|
|
{
|
|
const gchar *name = luaL_checkstring (L, 1);
|
|
WpState *state = wp_state_new (name);
|
|
wplua_pushobject (L, state);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
state_clear (lua_State *L)
|
|
{
|
|
WpState *state = wplua_checkobject (L, 1, WP_TYPE_STATE);
|
|
wp_state_clear (state);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
state_save (lua_State *L)
|
|
{
|
|
WpState *state = wplua_checkobject (L, 1, WP_TYPE_STATE);
|
|
luaL_checktype (L, 2, LUA_TTABLE);
|
|
g_autoptr (WpProperties) props = wplua_table_to_properties (L, 2);
|
|
g_autoptr (GError) error = NULL;
|
|
gboolean saved = wp_state_save (state, props, &error);
|
|
lua_pushboolean (L, saved);
|
|
lua_pushstring (L, error ? error->message : "");
|
|
return 2;
|
|
}
|
|
|
|
static int
|
|
state_load (lua_State *L)
|
|
{
|
|
WpState *state = wplua_checkobject (L, 1, WP_TYPE_STATE);
|
|
g_autoptr (WpProperties) props = wp_state_load (state);
|
|
wplua_properties_to_table (L, props);
|
|
return 1;
|
|
}
|
|
|
|
static const luaL_Reg state_methods[] = {
|
|
{ "clear", state_clear },
|
|
{ "save" , state_save },
|
|
{ "load" , state_load },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* ImplModule */
|
|
|
|
static int
|
|
impl_module_new (lua_State *L)
|
|
{
|
|
const char *name, *args = NULL;
|
|
WpProperties *properties = NULL;
|
|
|
|
name = luaL_checkstring (L, 1);
|
|
|
|
if (lua_type (L, 2) != LUA_TNONE && lua_type (L, 2) != LUA_TNIL)
|
|
args = luaL_checkstring (L, 2);
|
|
|
|
if (lua_type (L, 3) != LUA_TNONE && lua_type (L, 3) != LUA_TNIL) {
|
|
luaL_checktype (L, 3, LUA_TTABLE);
|
|
properties = wplua_table_to_properties (L, 3);
|
|
}
|
|
|
|
WpImplModule *m = wp_impl_module_load (get_wp_export_core (L),
|
|
name, args, properties);
|
|
|
|
if (m) {
|
|
wplua_pushobject (L, m);
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void
|
|
wp_lua_scripting_api_init (lua_State *L)
|
|
{
|
|
g_autoptr (GError) error = NULL;
|
|
|
|
luaL_newlib (L, glib_methods);
|
|
lua_setglobal (L, "GLib");
|
|
|
|
luaL_newlib (L, log_funcs);
|
|
lua_setglobal (L, "WpLog");
|
|
|
|
luaL_newlib (L, core_funcs);
|
|
lua_setglobal (L, "WpCore");
|
|
|
|
luaL_newlib (L, plugin_funcs);
|
|
lua_setglobal (L, "WpPlugin");
|
|
|
|
wp_lua_scripting_pod_init (L);
|
|
wp_lua_scripting_json_init (L);
|
|
|
|
wplua_register_type_methods (L, G_TYPE_SOURCE,
|
|
NULL, source_methods);
|
|
wplua_register_type_methods (L, WP_TYPE_OBJECT,
|
|
NULL, object_methods);
|
|
wplua_register_type_methods (L, WP_TYPE_PROXY,
|
|
NULL, proxy_methods);
|
|
wplua_register_type_methods (L, WP_TYPE_GLOBAL_PROXY,
|
|
NULL, global_proxy_methods);
|
|
wplua_register_type_methods (L, WP_TYPE_OBJECT_INTEREST,
|
|
object_interest_new, object_interest_methods);
|
|
wplua_register_type_methods (L, WP_TYPE_OBJECT_MANAGER,
|
|
object_manager_new, object_manager_methods);
|
|
wplua_register_type_methods (L, WP_TYPE_METADATA,
|
|
NULL, metadata_methods);
|
|
wplua_register_type_methods (L, WP_TYPE_IMPL_METADATA,
|
|
impl_metadata_new, NULL);
|
|
wplua_register_type_methods (L, WP_TYPE_ENDPOINT,
|
|
NULL, endpoint_methods);
|
|
wplua_register_type_methods (L, WP_TYPE_DEVICE,
|
|
device_new, NULL);
|
|
wplua_register_type_methods (L, WP_TYPE_SPA_DEVICE,
|
|
spa_device_new, spa_device_methods);
|
|
wplua_register_type_methods (L, WP_TYPE_NODE,
|
|
node_new, node_methods);
|
|
wplua_register_type_methods (L, WP_TYPE_IMPL_NODE,
|
|
impl_node_new, NULL);
|
|
wplua_register_type_methods (L, WP_TYPE_PORT,
|
|
NULL, port_methods);
|
|
wplua_register_type_methods (L, WP_TYPE_LINK,
|
|
link_new, NULL);
|
|
wplua_register_type_methods (L, WP_TYPE_CLIENT,
|
|
NULL, client_methods);
|
|
wplua_register_type_methods (L, WP_TYPE_SESSION_ITEM,
|
|
session_item_new, session_item_methods);
|
|
wplua_register_type_methods (L, WP_TYPE_PIPEWIRE_OBJECT,
|
|
NULL, pipewire_object_methods);
|
|
wplua_register_type_methods (L, WP_TYPE_STATE,
|
|
state_new, state_methods);
|
|
wplua_register_type_methods (L, WP_TYPE_IMPL_MODULE,
|
|
impl_module_new, NULL);
|
|
|
|
if (!wplua_load_uri (L, URI_API, &error) ||
|
|
!wplua_pcall (L, 0, 0, &error)) {
|
|
wp_critical ("Failed to load api: %s", error->message);
|
|
}
|
|
}
|