Files
wireplumber/modules/module-lua-scripting/api.c
2021-02-03 17:16:51 +02:00

869 lines
22 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>
#define URI_API "resource:///org/freedesktop/pipewire/wireplumber/m-lua-scripting/api.lua"
/* helpers */
static WpCore *
get_wp_core (lua_State *L)
{
lua_pushliteral (L, "wireplumber_core");
lua_gettable (L, LUA_REGISTRYINDEX);
return lua_touserdata (L, -1);
}
static WpCore *
get_wp_export_core (lua_State *L)
{
lua_pushliteral (L, "wireplumber_export_core");
lua_gettable (L, LUA_REGISTRYINDEX);
return lua_touserdata (L, -1);
}
/* WpDebug */
static int
log_log (lua_State *L, GLogLevelFlags lvl)
{
lua_Debug ar;
const gchar *message;
gchar line_str[11];
gconstpointer instance = NULL;
GType type = G_TYPE_INVALID;
int index = 1;
if (!wp_log_level_is_enabled (lvl))
return 0;
lua_getstack (L, 1, &ar);
lua_getinfo (L, "nSl", &ar);
if (wplua_isobject (L, 1, G_TYPE_OBJECT)) {
instance = wplua_toobject (L, 1);
type = G_TYPE_FROM_INSTANCE (instance);
index++;
}
message = luaL_checkstring (L, index);
sprintf (line_str, "%d", ar.currentline);
wp_log_structured_standard (G_LOG_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;
}
/* WpObject */
static void
object_activate_done (WpObject *o, GAsyncResult *res, gpointer data)
{
g_autoptr (GError) error = NULL;
if (!wp_object_activate_finish (o, res, &error)) {
wp_warning_object (o, "failed to activate: %s", error->message);
}
}
static int
object_activate (lua_State *L)
{
WpObject *o = wplua_checkobject (L, 1, WP_TYPE_OBJECT);
WpObjectFeatures features = 0;
if (lua_type (L, 2) != LUA_TNONE) {
features = luaL_checkinteger (L, 2);
} else {
features = WP_OBJECT_FEATURES_ALL;
}
wp_object_activate (o, features, NULL,
(GAsyncReadyCallback) object_activate_done, NULL);
return 0;
}
static const luaL_Reg object_methods[] = {
{ "activate", object_activate },
{ 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 (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 = g_type_is_a (type, WP_TYPE_GLOBAL_PROXY) ?
WP_CONSTRAINT_TYPE_PW_GLOBAL_PROPERTY : WP_CONSTRAINT_TYPE_G_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_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 int
object_interest_new (lua_State *L)
{
WpObjectInterest *interest = NULL;
GType type = 0;
gchar *typestr;
luaL_checktype (L, 1, LUA_TTABLE);
/* type = "string" -> required */
lua_pushliteral (L, "type");
if (lua_gettable (L, -2) != LUA_TSTRING)
luaL_error (L, "Interest: expected 'type' as string");
/* "device" -> "WpDevice" */
typestr = g_strdup_printf ("Wp%s", lua_tostring (L, -1));
if (typestr[2] != 0) {
typestr[2] = g_ascii_toupper (typestr[2]);
type = g_type_from_name (typestr);
}
g_free (typestr);
lua_pop (L, 1);
if (!type)
luaL_error (L, "Interest: unknown type '%s'", lua_tostring (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, 1)) {
/* 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;
}
/* 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)) {
if (!wplua_isboxed (L, -1, WP_TYPE_OBJECT_INTEREST))
luaL_error (L, "ObjectManager: expected Interest");
/* steal the interest out of the GValue to avoid doing mem copy */
GValue *v = lua_touserdata (L, -1);
wp_object_manager_add_interest_full (om, g_value_get_boxed (v));
memset (v, 0, sizeof (GValue));
g_value_init (v, WP_TYPE_OBJECT_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_iterate (lua_State *L)
{
WpObjectManager *om = wplua_checkobject (L, 1, WP_TYPE_OBJECT_MANAGER);
WpIterator *it = wp_object_manager_iterate (om);
return push_wpiterator (L, it);
}
static int
object_manager_lookup (lua_State *L)
{
WpObjectManager *om = wplua_checkobject (L, 1, WP_TYPE_OBJECT_MANAGER);
WpObject *o = NULL;
if (lua_isuserdata (L, 2)) {
WpObjectInterest *oi = wplua_checkboxed (L, 2, WP_TYPE_OBJECT_INTEREST);
o = wp_object_manager_lookup_full (om, wp_object_interest_ref (oi));
} else {
o = wp_object_manager_lookup (om, WP_TYPE_OBJECT, NULL);
}
wplua_pushobject (L, o);
return 1;
}
static const luaL_Reg object_manager_methods[] = {
{ "activate", object_manager_activate },
{ "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);
g_autoptr (WpIterator) it = wp_metadata_iterate (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 const luaL_Reg metadata_methods[] = {
{ "iterate", metadata_iterate },
{ "find", metadata_find },
{ NULL, NULL }
};
/* WpSession */
static int
session_iterate_endpoints (lua_State *L)
{
WpSession *session = wplua_checkobject (L, 1, WP_TYPE_SESSION);
WpIterator *it = wp_session_iterate_endpoints (session);
return push_wpiterator (L, it);
}
static int
session_iterate_links (lua_State *L)
{
WpSession *session = wplua_checkobject (L, 1, WP_TYPE_SESSION);
WpIterator *it = wp_session_iterate_links (session);
return push_wpiterator (L, it);
}
static const luaL_Reg session_methods[] = {
{ "iterate_endpoints", session_iterate_endpoints },
{ "iterate_links", session_iterate_links },
{ NULL, NULL }
};
/* WpImplSession */
static int
impl_session_new (lua_State *L)
{
WpImplSession *session = wp_impl_session_new (get_wp_core (L));
wplua_pushobject (L, session);
return 1;
}
static int
impl_session_update_properties (lua_State *L)
{
WpImplSession *session = wplua_checkobject (L, 1, WP_TYPE_IMPL_SESSION);
luaL_checktype (L, 2, LUA_TTABLE);
WpProperties *props = wplua_table_to_properties (L, 2);
wp_impl_session_update_properties (session, props);
return 0;
}
static const luaL_Reg impl_session_methods[] = {
{ "update_properties", impl_session_update_properties },
{ NULL, NULL }
};
/* WpEndpoint */
static int
endpoint_iterate_streams (lua_State *L)
{
WpEndpoint *ep = wplua_checkobject (L, 1, WP_TYPE_ENDPOINT);
WpIterator *it = wp_endpoint_iterate_streams (ep);
return push_wpiterator (L, it);
}
static int
endpoint_create_link (lua_State *L)
{
WpEndpoint *ep = wplua_checkobject (L, 1, WP_TYPE_ENDPOINT);
luaL_checktype (L, 2, LUA_TTABLE);
WpProperties *props = wplua_table_to_properties (L, 2);
wp_endpoint_create_link (ep, props);
return 0;
}
static const luaL_Reg endpoint_methods[] = {
{ "iterate_streams", endpoint_iterate_streams },
{ "create_link", endpoint_create_link },
{ NULL, NULL }
};
/* WpEndpointLink */
static int
endpoint_link_get_state (lua_State *L)
{
WpEndpointLink *eplink = wplua_checkobject (L, 1, WP_TYPE_ENDPOINT_LINK);
const gchar *error = NULL;
WpEndpointLinkState state = wp_endpoint_link_get_state (eplink, &error);
g_autoptr (GEnumClass) state_class =
g_type_class_ref (WP_TYPE_ENDPOINT_LINK_STATE);
lua_pushstring (L, g_enum_get_value (state_class, state)->value_nick);
if (error)
lua_pushstring (L, error);
return error ? 2 : 1;
}
static int
endpoint_link_request_state (lua_State *L)
{
WpEndpointLink *eplink = wplua_checkobject (L, 1, WP_TYPE_ENDPOINT_LINK);
const gchar *states[] = { "inactive", "active" };
int state = luaL_checkoption (L, 2, NULL, states);
wp_endpoint_link_request_state (eplink, (WpEndpointLinkState) (state+1));
return 0;
}
static int
endpoint_link_get_linked_object_ids (lua_State *L)
{
WpEndpointLink *eplink = wplua_checkobject (L, 1, WP_TYPE_ENDPOINT_LINK);
guint32 output_endpoint, output_stream;
guint32 input_endpoint, input_stream;
wp_endpoint_link_get_linked_object_ids (eplink,
&output_endpoint, &output_stream,
&input_endpoint, &input_stream);
lua_pushinteger (L, output_endpoint);
lua_pushinteger (L, output_stream);
lua_pushinteger (L, input_endpoint);
lua_pushinteger (L, input_stream);
return 4;
}
static const luaL_Reg endpoint_link_methods[] = {
{ "get_state", endpoint_link_get_state },
{ "request_state", endpoint_link_request_state },
{ "get_linked_object_ids", endpoint_link_get_linked_object_ids },
{ 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);
wplua_pushobject (L, d);
return 1;
}
/* 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);
wplua_pushobject (L, d);
return 1;
}
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);
wplua_pushobject (L, d);
return 1;
}
static const luaL_Reg node_methods[] = {
{ 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);
wplua_pushobject (L, d);
return 1;
}
/* WpSessionItem */
static int
session_item_new (lua_State *L)
{
WpSessionItem *si = NULL;
const char *type = luaL_checkstring (L, 1);
WpCore *core = NULL;
lua_pushliteral (L, "wireplumber_core");
lua_gettable (L, LUA_REGISTRYINDEX);
core = lua_touserdata (L, -1);
si = wp_session_item_make (core, type);
wplua_pushobject (L, si);
return 1;
}
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);
g_auto (GVariantBuilder) b =
G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_VARDICT);
GVariant *config = NULL;
gboolean is_key = TRUE;
const gchar *key = NULL;
/* validate arguments */
luaL_checktype (L, 2, LUA_TTABLE);
/* build the configuration */
lua_pushnil (L);
while (lua_next (L, 2)) {
if (is_key) {
is_key = FALSE;
key = lua_tostring (L, -1);
} else {
is_key = TRUE;
switch (lua_type (L, -1)) {
case LUA_TBOOLEAN:
g_variant_builder_add (&b, "{sv}", key,
g_variant_new_boolean (lua_toboolean (L, -1)));
break;
case LUA_TNUMBER:
g_variant_builder_add (&b, "{sv}", key,
g_variant_new_int64 (lua_tointeger (L, -1)));
break;
case LUA_TSTRING:
g_variant_builder_add (&b, "{sv}", key,
g_variant_new_string (lua_tostring (L, -1)));
break;
case LUA_TUSERDATA: {
GValue *v = lua_touserdata (L, -1);
gpointer p = NULL;
if (G_VALUE_HOLDS_OBJECT (v)) {
p = g_value_get_object (v);
} else if (G_VALUE_HOLDS_BOXED (v)) {
p = g_value_get_boxed (v);
} else if (G_VALUE_HOLDS_POINTER (v)) {
p = g_value_get_pointer (v);
} else {
luaL_error (L, "Key '%s' does not hold a valid pointer", key);
break;
}
g_variant_builder_add (&b, "{sv}", key,
g_variant_new_uint64 ((guint64)p));
break;
}
default:
luaL_error (L, "Key '%s' with value type '%s' is not supported", key,
lua_typename(L, lua_type(L, -1)));
break;
}
}
lua_pop (L, 1);
}
config = g_variant_builder_end (&b);
lua_pushboolean (L, wp_session_item_configure (si, config));
return 1;
}
static int
session_item_activate (lua_State *L)
{
WpSessionItem *si = wplua_checkobject (L, 1, WP_TYPE_SESSION_ITEM);
GClosure *closure = wplua_function_to_closure (L, 2);
wp_session_item_activate_closure (si, closure);
return 0;
}
static int
session_item_deactivate (lua_State *L)
{
WpSessionItem *si = wplua_checkobject (L, 1, WP_TYPE_SESSION_ITEM);
wp_session_item_deactivate (si);
return 0;
}
static int
session_item_export (lua_State *L)
{
WpSessionItem *si = wplua_checkobject (L, 1, WP_TYPE_SESSION_ITEM);
WpSession *session = wplua_checkobject (L, 2, WP_TYPE_SESSION);
GClosure *closure = wplua_function_to_closure (L, 3);
wp_session_item_export_closure (si, session, closure);
return 0;
}
static int
session_item_unexport (lua_State *L)
{
WpSessionItem *si = wplua_checkobject (L, 1, WP_TYPE_SESSION_ITEM);
wp_session_item_unexport (si);
return 0;
}
static const luaL_Reg session_item_methods[] = {
{ "reset", session_item_reset },
{ "configure", session_item_configure },
{ "activate", session_item_activate },
{ "deactivate", session_item_deactivate },
{ "export", session_item_export },
{ "unexport", session_item_unexport },
{ NULL, NULL }
};
void
wp_lua_scripting_api_init (lua_State *L)
{
g_autoptr (GError) error = NULL;
luaL_newlib (L, log_funcs);
lua_setglobal (L, "WpDebug");
lua_pushcfunction (L, plugin_find);
lua_setglobal (L, "WpPlugin_find");
wplua_register_type_methods (L, WP_TYPE_OBJECT,
NULL, object_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, NULL);
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_SESSION,
NULL, session_methods);
wplua_register_type_methods (L, WP_TYPE_IMPL_SESSION,
impl_session_new, impl_session_methods);
wplua_register_type_methods (L, WP_TYPE_ENDPOINT,
NULL, endpoint_methods);
wplua_register_type_methods (L, WP_TYPE_ENDPOINT_LINK,
NULL, endpoint_link_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_SESSION_ITEM,
session_item_new, session_item_methods);
wplua_load_uri (L, URI_API, 0, 0, &error);
if (G_UNLIKELY (error))
wp_critical ("Failed to load api: %s", error->message);
}