2 * Module-murphy-ivi -- PulseAudio module for providing audio routing support
3 * Copyright (c) 2012, Intel Corporation.
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU Lesser General Public License,
7 * version 2.1, as published by the Free Software Foundation.
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.
12 * See the GNU Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this program; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St - Fifth Floor, Boston,
26 #include <pulsecore/pulsecore-config.h>
27 #include <pulsecore/core-util.h>
29 #include <murphy/common/macros.h>
30 #include <murphy/common/mm.h>
31 #include <murphy/core/lua-utils/object.h>
32 #include <murphy/core/lua-utils/funcbridge.h>
33 #include <murphy/core/lua-utils/strarray.h>
34 #include <murphy/core/lua-utils/funcbridge.h>
35 #include <murphy/domain-control/client.h>
36 #include <murphy/resource/data-types.h>
37 #include <murphy/resource/protocol.h>
39 #include "scripting.h"
45 #include "murphy-config.h"
47 #define IMPORT_CLASS MRP_LUA_CLASS(mdb, import)
48 #define NODE_CLASS MRP_LUA_CLASS(node, instance)
49 #define ZONE_CLASS MRP_LUA_CLASS_SIMPLE(zone)
50 #define RESOURCE_CLASS MRP_LUA_CLASS_SIMPLE(audio_resource)
51 #define RTGROUP_CLASS MRP_LUA_CLASS_SIMPLE(routing_group)
52 #define APPLICATION_CLASS MRP_LUA_CLASS_SIMPLE(application_class)
53 #define VOLLIM_CLASS MRP_LUA_CLASS_SIMPLE(volume_limit)
55 #define ARRAY_CLASSID MRP_LUA_CLASSID_ROOT "mdb_array"
57 #define USERDATA "murphy_ivi_userdata"
60 #define MRP_LUA_ENTER \
61 pa_log_debug("%s() enter", __FUNCTION__)
64 #define MRP_LUA_LEAVE(_v) \
66 pa_log_debug("%s() leave (%d)", __FUNCTION__, (_v)); \
70 #undef MRP_LUA_LEAVE_NOARG
71 #define MRP_LUA_LEAVE_NOARG \
72 pa_log_debug("%s() leave", __FUNCTION__)
74 typedef void (*update_func_t)(struct userdata *);
81 struct scripting_import {
82 struct userdata *userdata;
84 mrp_lua_strarray_t *columns;
85 const char *condition;
87 mrp_funcbridge_t *update;
90 struct scripting_node {
91 struct userdata *userdata;
97 const char *recording;
107 struct scripting_zone {
108 struct userdata *userdata;
113 struct scripting_resource {
114 struct userdata *userdata;
115 resource_name_t *name;
116 attribute_t *attributes;
119 struct scripting_rtgroup {
120 struct userdata *userdata;
123 mrp_funcbridge_t *accept;
124 mrp_funcbridge_t *compare;
136 pa_nodeset_resdef resource;
139 struct scripting_apclass {
140 struct userdata *userdata;
169 struct scripting_vollim {
170 struct userdata *userdata;
175 mrp_funcbridge_t *calculate;
188 mrp_funcbridge_cfunc_t func;
225 static int import_create(lua_State *);
226 static int import_getfield(lua_State *);
227 static int import_setfield(lua_State *);
228 static int import_tostring(lua_State *);
229 static void import_destroy(void *);
231 static int import_link(lua_State *);
233 static void import_data_changed(struct userdata *, const char *,
234 int, mrp_domctl_value_t **);
235 static bool update_bridge(lua_State *, void *, const char *,
236 mrp_funcbridge_value_t *, char *,
237 mrp_funcbridge_value_t *);
239 static void array_class_create(lua_State *);
240 static pa_value *array_create(lua_State *, int, mrp_lua_strarray_t *);
241 static int array_getfield(lua_State *);
242 static int array_setfield(lua_State *);
243 static int array_getlength(lua_State *);
246 static void array_destroy(void *);
249 static int node_create(lua_State *);
250 static int node_getfield(lua_State *);
251 static int node_setfield(lua_State *);
252 static int node_tostring(lua_State *);
253 static void node_destroy(void *);
255 static int zone_create(lua_State *);
256 static int zone_getfield(lua_State *);
257 static int zone_setfield(lua_State *);
258 static void zone_destroy(void *);
260 static int resource_create(lua_State *);
261 static int resource_getfield(lua_State *);
262 static int resource_setfield(lua_State *);
263 static void resource_destroy(void *);
265 static int rtgroup_create(lua_State *);
266 static int rtgroup_getfield(lua_State *);
267 static int rtgroup_setfield(lua_State *);
268 static int rtgroup_tostring(lua_State *);
269 static void rtgroup_destroy(void *);
271 static bool rtgroup_accept(struct userdata *, mir_rtgroup *, mir_node *);
272 static int rtgroup_compare(struct userdata *, mir_rtgroup *,
273 mir_node *, mir_node *);
275 static bool accept_bridge(lua_State *, void *, const char *,
276 mrp_funcbridge_value_t *, char *,
277 mrp_funcbridge_value_t *);
278 static bool compare_bridge(lua_State *, void *, const char *,
279 mrp_funcbridge_value_t *, char *,
280 mrp_funcbridge_value_t *);
281 static bool change_bridge(lua_State *, void *, const char *,
282 mrp_funcbridge_value_t *, char *,
283 mrp_funcbridge_value_t *);
285 static int apclass_create(lua_State *);
286 static int apclass_getfield(lua_State *);
287 static int apclass_setfield(lua_State *);
288 static int apclass_tostring(lua_State *);
289 static void apclass_destroy(void *);
291 static route_t *route_check(lua_State *, int);
292 static int route_push(lua_State *, route_t *);
293 static void route_destroy(route_t *);
295 static int vollim_create(lua_State *);
296 static int vollim_getfield(lua_State *);
297 static int vollim_setfield(lua_State *);
298 static int vollim_tostring(lua_State *);
299 static void vollim_destroy(void *);
301 static double vollim_calculate(struct userdata *, int, mir_node *, void *);
302 static bool calculate_bridge(lua_State *, void *, const char *,
303 mrp_funcbridge_value_t *, char *,
304 mrp_funcbridge_value_t *);
306 static limit_data_t *limit_data_check(lua_State *, int);
309 static int limit_data_push(lua_State *, limit_data_t *);
312 static void limit_data_destroy(limit_data_t *);
314 static intarray_t *intarray_check(lua_State *, int, int, int);
315 static int intarray_push(lua_State *, intarray_t *);
316 static void intarray_destroy(intarray_t *);
318 static resource_name_t *resource_names_check(lua_State *, int);
319 static void resource_names_destroy(resource_name_t *);
321 static attribute_t *attributes_check(lua_State *, int);
322 static void attributes_destroy(attribute_t *);
324 static map_t *map_check(lua_State *, int);
325 static int map_push(lua_State *, map_t *);
326 static void map_destroy(map_t *);
328 static field_t field_check(lua_State *, int, const char **);
329 static field_t field_name_to_type(const char *, size_t);
330 static int make_id(char *buf, size_t len, const char *fmt, ...);
332 static void setup_murphy_interface(struct userdata *);
333 static char *comma_separated_list(mrp_lua_strarray_t *, char *, int);
335 static bool define_constants(lua_State *);
336 static bool register_methods(lua_State *);
338 static void *alloc(void *, void *, size_t, size_t);
339 static int panic(lua_State *);
342 MRP_LUA_METHOD_LIST_TABLE (
343 import_methods, /* methodlist name */
344 MRP_LUA_METHOD_CONSTRUCTOR (import_create)
345 MRP_LUA_METHOD (link, import_link )
348 MRP_LUA_METHOD_LIST_TABLE (
349 node_methods, /* methodlist name */
350 MRP_LUA_METHOD_CONSTRUCTOR (node_create)
354 MRP_LUA_METHOD_LIST_TABLE (
355 import_overrides, /* methodlist_name */
356 MRP_LUA_OVERRIDE_CALL (import_create)
357 MRP_LUA_OVERRIDE_GETFIELD (import_getfield)
358 MRP_LUA_OVERRIDE_SETFIELD (import_setfield)
359 MRP_LUA_OVERRIDE_STRINGIFY (import_tostring)
362 MRP_LUA_METHOD_LIST_TABLE (
363 array_overrides, /* methodlist_name */
364 MRP_LUA_OVERRIDE_GETFIELD (array_getfield)
365 MRP_LUA_OVERRIDE_SETFIELD (array_setfield)
366 MRP_LUA_OVERRIDE_GETLENGTH (array_getlength)
369 MRP_LUA_METHOD_LIST_TABLE (
370 node_overrides, /* methodlist name */
371 MRP_LUA_OVERRIDE_CALL (node_create)
372 MRP_LUA_OVERRIDE_GETFIELD (node_getfield)
373 MRP_LUA_OVERRIDE_SETFIELD (node_setfield)
374 MRP_LUA_OVERRIDE_STRINGIFY (node_tostring)
379 mdb, /* class name */
380 import, /* constructor name */
381 scripting_import, /* userdata type */
382 import_destroy, /* userdata destructor */
383 import_methods, /* class methods */
384 import_overrides /* override methods */
388 node, /* class name */
389 instance, /* constructor name */
390 scripting_node, /* userdata type */
391 node_destroy, /* userdata destructor */
392 node_methods, /* class methods */
393 node_overrides /* override methods */
396 MRP_LUA_CLASS_DEF_SIMPLE (
397 zone, /* class name */
398 scripting_zone, /* userdata type */
399 zone_destroy, /* userdata destructor */
400 MRP_LUA_METHOD_LIST ( /* methods */
401 MRP_LUA_METHOD_CONSTRUCTOR (zone_create)
403 MRP_LUA_METHOD_LIST ( /* overrides */
404 MRP_LUA_OVERRIDE_CALL (zone_create)
405 MRP_LUA_OVERRIDE_GETFIELD (zone_getfield)
406 MRP_LUA_OVERRIDE_SETFIELD (zone_setfield)
410 MRP_LUA_CLASS_DEF_SIMPLE (
411 audio_resource, /* class name */
412 scripting_resource, /* userdata type */
413 resource_destroy, /* userdata destructor */
414 MRP_LUA_METHOD_LIST ( /* methods */
415 MRP_LUA_METHOD_CONSTRUCTOR (resource_create)
417 MRP_LUA_METHOD_LIST ( /* overrides */
418 MRP_LUA_OVERRIDE_CALL (resource_create)
419 MRP_LUA_OVERRIDE_GETFIELD (resource_getfield)
420 MRP_LUA_OVERRIDE_SETFIELD (resource_setfield)
424 MRP_LUA_CLASS_DEF_SIMPLE (
425 routing_group, /* class name */
426 scripting_rtgroup, /* userdata type */
427 rtgroup_destroy, /* userdata destructor */
428 MRP_LUA_METHOD_LIST ( /* methods */
429 MRP_LUA_METHOD_CONSTRUCTOR (rtgroup_create)
431 MRP_LUA_METHOD_LIST ( /* overrides */
432 MRP_LUA_OVERRIDE_CALL (rtgroup_create)
433 MRP_LUA_OVERRIDE_GETFIELD (rtgroup_getfield)
434 MRP_LUA_OVERRIDE_SETFIELD (rtgroup_setfield)
435 MRP_LUA_OVERRIDE_STRINGIFY (rtgroup_tostring)
439 MRP_LUA_CLASS_DEF_SIMPLE (
440 application_class, /* class name */
441 scripting_apclass, /* userdata type */
442 apclass_destroy, /* userdata destructor */
443 MRP_LUA_METHOD_LIST ( /* methods */
444 MRP_LUA_METHOD_CONSTRUCTOR (apclass_create)
446 MRP_LUA_METHOD_LIST ( /* overrides */
447 MRP_LUA_OVERRIDE_CALL (apclass_create)
448 MRP_LUA_OVERRIDE_GETFIELD (apclass_getfield)
449 MRP_LUA_OVERRIDE_SETFIELD (apclass_setfield)
450 MRP_LUA_OVERRIDE_STRINGIFY (apclass_tostring)
454 MRP_LUA_CLASS_DEF_SIMPLE (
455 volume_limit, /* class name */
456 scripting_vollim, /* userdata type */
457 vollim_destroy, /* userdata destructor */
458 MRP_LUA_METHOD_LIST ( /* methods */
459 MRP_LUA_METHOD_CONSTRUCTOR (vollim_create)
461 MRP_LUA_METHOD_LIST ( /* overrides */
462 MRP_LUA_OVERRIDE_CALL (vollim_create)
463 MRP_LUA_OVERRIDE_GETFIELD (vollim_getfield)
464 MRP_LUA_OVERRIDE_SETFIELD (vollim_setfield)
465 MRP_LUA_OVERRIDE_STRINGIFY (vollim_tostring)
470 pa_scripting *pa_scripting_init(struct userdata *u)
472 pa_scripting *scripting;
477 scripting = pa_xnew0(pa_scripting, 1);
479 if (!(L = lua_newstate(alloc, u)))
480 pa_log("failed to initialize Lua");
482 lua_atpanic(L, &panic);
485 mrp_create_funcbridge_class(L);
486 mrp_lua_create_object_class(L, IMPORT_CLASS);
487 mrp_lua_create_object_class(L, NODE_CLASS);
488 mrp_lua_create_object_class(L, ZONE_CLASS);
489 mrp_lua_create_object_class(L, RESOURCE_CLASS);
490 mrp_lua_create_object_class(L, RTGROUP_CLASS);
491 mrp_lua_create_object_class(L, APPLICATION_CLASS);
492 mrp_lua_create_object_class(L, VOLLIM_CLASS);
494 array_class_create(L);
499 lua_pushlightuserdata(L, u);
500 lua_setglobal(L, USERDATA);
503 scripting->configured = false;
509 void pa_scripting_done(struct userdata *u)
511 pa_scripting *scripting;
513 if (u && (scripting = u->scripting)) {
519 bool pa_scripting_dofile(struct userdata *u, const char *file)
521 pa_scripting *scripting;
528 pa_assert_se((scripting = u->scripting));
529 pa_assert_se((L = scripting->L));
531 if (luaL_loadfile(L, file) || lua_pcall(L, 0, 0, 0)) {
533 pa_log("%s", lua_tostring(L, -1));
538 scripting->configured = true;
539 setup_murphy_interface(u);
540 pa_zoneset_update_module_property(u);
546 static int import_create(lua_State *L)
549 pa_scripting *scripting;
552 scripting_import *imp;
553 const char *table = NULL;
554 mrp_lua_strarray_t *columns = NULL;
555 const char *condition = NULL;
557 mrp_funcbridge_t *update = NULL;
568 lua_getglobal(L, USERDATA);
569 if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
570 luaL_error(L, "missing or invalid global '" USERDATA "'");
572 pa_assert_se((scripting = u->scripting));
574 MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
576 switch (field_name_to_type(fldnam, fldnamlen)) {
577 case TABLE: table = luaL_checkstring(L, -1); break;
578 case COLUMNS: columns = mrp_lua_check_strarray(L, -1); break;
579 case CONDITION: condition = luaL_checkstring(L, -1); break;
580 case MAXROW: maxrow = luaL_checkint(L, -1); break;
581 case UPDATE: update = mrp_funcbridge_create_luafunc(L, -1); break;
582 default: luaL_error(L, "bad field '%s'", fldnam); break;
585 } /* MRP_LUA_FOREACH_FIELD */
590 luaL_error(L, "missing table field");
592 luaL_error(L, "missing columns field");
593 if (maxrow < 1 || maxrow >= MQI_QUERY_RESULT_MAX)
594 luaL_error(L, "missing or invalid maxrow field");
596 luaL_error(L, "missing update function");
598 maxcol = columns->nstring;
600 if (maxcol >= MQI_COLUMN_MAX)
601 luaL_error(L, "too many columns (max %d allowed)", MQI_COLUMN_MAX);
603 if (scripting->configured)
604 luaL_error(L, "refuse to import '%s' after configuration phase",table);
606 imp = (scripting_import *)mrp_lua_create_object(L, IMPORT_CLASS, table,0);
609 imp->table = pa_xstrdup(table);
610 imp->columns = columns;
611 imp->condition = condition;
612 imp->values = array_create(L, maxrow, NULL);
613 imp->update = update;
615 for (i = 0, rows = imp->values->array; i < maxrow; i++) {
616 cols = (rows[i] = array_create(L, maxcol, columns))->array;
617 lua_rawseti(L, -3, i+1); /* we add this to the import */
618 for (j = 0; j < maxcol; j++)
619 cols[j] = pa_xnew0(pa_value, 1);
622 lua_rawseti(L, -2, MQI_QUERY_RESULT_MAX);
627 static int import_getfield(lua_State *L)
629 scripting_import *imp;
636 if (!(imp = (scripting_import *)mrp_lua_check_object(L, IMPORT_CLASS, 1)))
639 pa_assert_se((values = imp->values));
641 if (lua_type(L, 2) == LUA_TNUMBER) {
642 colidx = lua_tointeger(L, 2);
644 if (colidx < 1 || colidx > -values->type)
647 lua_rawgeti(L, 1, colidx);
650 fld = field_check(L, 2, NULL);
654 case TABLE: lua_pushstring(L, imp->table); break;
655 case COLUMNS: mrp_lua_push_strarray(L, imp->columns); break;
656 case CONDITION: lua_pushstring(L, imp->condition); break;
657 case MAXROW: lua_pushinteger(L, -imp->values->type); break;
658 default: lua_pushnil(L); break;
666 static int import_setfield(lua_State *L)
672 f = luaL_checkstring(L, 2);
673 luaL_error(L, "attempt to set '%s' field of read-only mdb.import", f);
678 static int import_tostring(lua_State *L)
680 scripting_import *imp;
684 imp = (scripting_import *)mrp_lua_check_object(L, IMPORT_CLASS, 1);
686 lua_pushstring(L, imp->table);
691 static void import_destroy(void *data)
693 scripting_import *imp = (scripting_import *)data;
697 pa_xfree((void *)imp->table);
698 mrp_lua_free_strarray(imp->columns);
699 pa_xfree((void *)imp->condition);
704 static int import_link(lua_State *L)
706 scripting_import *imp;
707 mrp_lua_strarray_t *columns;
717 imp = (scripting_import *)mrp_lua_check_object(L, IMPORT_CLASS, 1);
718 rowidx = luaL_checkint(L, 2) - 1;
719 colnam = luaL_checkstring(L, 3);
722 pa_assert_se((columns = imp->columns));
726 if (rowidx >= 0 && rowidx < -imp->values->type) {
727 for (colidx = 0; colidx < columns->nstring; colidx++) {
728 if (!strcmp(colnam, columns->strings[colidx])) {
729 pa_assert_se((values = imp->values));
730 pa_assert_se((row = values->array[rowidx]));
731 pa_assert(colidx < (size_t)-row->type);
732 pa_assert_se((col = row->array[colidx]));
738 pa_log_debug("userdata: type:%d", col->type);
740 lua_pushlightuserdata(L, col);
745 static void import_data_changed(struct userdata *u,
748 mrp_domctl_value_t **mval)
750 static mrp_domctl_value_t empty;
752 pa_scripting *scripting;
754 scripting_import *imp;
755 mrp_domctl_value_t *mrow;
756 mrp_domctl_value_t *mcol;
757 pa_value *ptval, *prval, *pcval;
762 mrp_funcbridge_value_t arg;
763 mrp_funcbridge_value_t ret;
769 pa_assert(mval || nrow == 0);
770 pa_assert_se((scripting = u->scripting));
771 pa_assert_se((L = scripting->L));
773 pa_log_debug("table '%s' data changed: got %d rows", table, nrow);
775 mrp_lua_get_class_table(L, IMPORT_CLASS);
777 if (!lua_istable(L, -1)){
778 luaL_error(L, "internal error: failed to find '%s' table",
779 (IMPORT_CLASS)->constructor);
782 lua_pushstring(L, table);
785 if (!(imp = mrp_lua_to_object(L, IMPORT_CLASS, -1)))
786 pa_log("can't find import '%s'", table);
788 pa_assert(!strcmp(table, imp->table));
789 pa_assert(imp->columns);
790 pa_assert(imp->update);
791 pa_assert_se((ptval = imp->values));
792 pa_assert_se((prow = ptval->array));
794 maxrow = -ptval->type;
795 maxcol = imp->columns->nstring;
797 pa_assert(maxrow >= 0);
798 pa_assert(nrow <= maxrow);
800 pa_log_debug("import '%s' found", imp->table);
802 for (i = 0; i < maxrow; i++) {
803 pa_assert_se((prval = prow[i]));
804 pa_assert_se((pcol = prval->array));
805 pa_assert(prval->type < 0);
806 pa_assert(maxcol == -prval->type);
808 mrow = (i < nrow) ? mval[i] : NULL;
810 for (j = 0; j < maxcol; j++) {
812 mcol = mrow ? mrow + j : ∅
814 switch (mcol->type) {
815 case MRP_DOMCTL_STRING:
816 pa_assert(!pcval->type || pcval->type == pa_value_string);
817 pa_xfree((void *)pcval->string);
818 pcval->type = pa_value_string;
819 pcval->string = pa_xstrdup(mcol->str);
821 case MRP_DOMCTL_INTEGER:
822 pa_assert(!pcval->type || pcval->type == pa_value_integer);
823 pcval->type = pa_value_integer;
824 pcval->integer = mcol->s32;
826 case MRP_DOMCTL_UNSIGNED:
827 pa_assert(!pcval->type || pcval->type == pa_value_unsignd);
828 pcval->type = pa_value_unsignd;
829 pcval->unsignd = mcol->u32;
831 case MRP_DOMCTL_DOUBLE:
832 pa_assert(!pcval->type || pcval->type ==pa_value_floating);
833 pcval->type = pa_value_floating;
834 pcval->floating = mcol->dbl;
837 if (pcval->type == pa_value_string)
838 pa_xfree((void *)pcval->string);
839 memset(pcval, 0, sizeof(pa_value));
847 if (!mrp_funcbridge_call_from_c(L, imp->update, "o", &arg, &t, &ret)) {
848 pa_log("failed to call %s:update method (%s)",
849 imp->table, ret.string);
850 pa_xfree((void *)ret.string);
858 static bool update_bridge(lua_State *L, void *data, const char *signature,
859 mrp_funcbridge_value_t *args,
860 char *ret_type, mrp_funcbridge_value_t *ret_val)
862 update_func_t update;
863 scripting_import *imp;
869 pa_assert(signature);
874 pa_assert_se((update = (update_func_t)data));
876 if (strcmp(signature, "o"))
879 pa_assert_se((imp = args[0].pointer));
880 pa_assert_se((u = imp->userdata));
883 *ret_type = MRP_FUNCBRIDGE_NO_DATA;
884 memset(ret_val, 0, sizeof(mrp_funcbridge_value_t));
893 static void array_class_create(lua_State *L)
895 /* create a metatable for row's */
896 luaL_newmetatable(L, ARRAY_CLASSID);
897 lua_pushliteral(L, "__index");
898 lua_pushvalue(L, -2);
899 lua_settable(L, -3); /* metatable.__index = metatable */
900 luaL_openlib(L, NULL, array_overrides, 0);
904 static pa_value *array_create(lua_State *L, int dimension,
905 mrp_lua_strarray_t *names)
911 pa_assert(dimension >= 0);
912 pa_assert(dimension < MQI_QUERY_RESULT_MAX);
914 array = pa_xnew0(pa_value *, dimension + 1);
915 value = lua_newuserdata(L, sizeof(pa_value));
916 value->type = -dimension;
917 value->array = array;
919 array[dimension] = (pa_value *)names;
921 luaL_getmetatable(L, ARRAY_CLASSID);
922 lua_setmetatable(L, -2);
927 static int array_getfield(lua_State *L)
929 pa_value *arr, *value;
933 mrp_lua_strarray_t *names;
941 arr = (pa_value *)luaL_checkudata(L, 1, ARRAY_CLASSID);
943 pa_assert(arr->type < 0);
945 dimension = -arr->type;
946 key_type = lua_type(L, 2);
950 idx = lua_tointeger(L, 2) - 1;
954 if ((names = (mrp_lua_strarray_t *)arr->array[dimension])) {
955 pa_assert(dimension == names->nstring);
956 key = lua_tostring(L, 2);
958 for (i = 0; i < dimension; i++) {
959 if (!strcmp(key, names->strings[i])) {
972 if (idx < 0 || idx >= dimension || !(value = arr->array[idx]))
974 else if (value->type < 0)
975 lua_rawgeti(L, 1, 1 - value->type);
977 switch (value->type) {
978 case pa_value_string: lua_pushstring(L, value->string); break;
979 case pa_value_integer: lua_pushinteger(L, value->integer); break;
980 case pa_value_unsignd: lua_pushinteger(L, value->unsignd); break;
981 case pa_value_floating: lua_pushnumber(L, value->floating); break;
982 default: lua_pushnil(L); break;
989 static int array_setfield(lua_State *L)
995 luaL_error(L, "attempt to write to a read-only object");
1000 static int array_getlength(lua_State *L)
1010 static void array_destroy(void *data)
1012 pa_value *value = (pa_value *)data;
1017 pa_assert(value->type < 0);
1018 pa_xfree(value->array);
1021 MRP_LUA_LEAVE_NOARG;
1025 scripting_node *pa_scripting_node_create(struct userdata *u, mir_node *node)
1027 pa_scripting *scripting;
1034 pa_assert(node->amname);
1036 pa_assert_se((scripting = u->scripting));
1037 pa_assert_se((L = scripting->L));
1039 make_id(id, sizeof(id), "%s_%d", node->amname, node->index);
1041 if ((sn = (scripting_node *)mrp_lua_create_object(L, NODE_CLASS, id,0))) {
1043 sn->id = pa_xstrdup(id);
1050 void pa_scripting_node_destroy(struct userdata *u, mir_node *node)
1052 pa_scripting *scripting;
1061 pa_assert_se((scripting = u->scripting));
1062 pa_assert_se((L = scripting->L));
1064 if ((sn = node->scripting)) {
1065 mrp_lua_destroy_object(L, sn->id,0, sn);
1067 node->scripting = NULL;
1070 MRP_LUA_LEAVE_NOARG;
1073 static int node_create(lua_State *L)
1082 static int node_getfield(lua_State *L)
1090 fld = field_check(L, 2, NULL);
1093 if (!(sn = (scripting_node *)mrp_lua_check_object(L, NODE_CLASS, 1)))
1096 pa_assert_se((node = sn->node));
1099 case NAME: lua_pushstring(L, node->amname); break;
1100 case DESCRIPTION: lua_pushstring(L, node->amdescr); break;
1101 case DIRECTION: lua_pushinteger(L, node->direction); break;
1102 case IMPLEMENT: lua_pushinteger(L, node->implement); break;
1103 case CHANNELS: lua_pushinteger(L, node->channels); break;
1104 case LOCATION: lua_pushinteger(L, node->location); break;
1105 case PRIVACY: lua_pushinteger(L, node->privacy); break;
1106 case ZONE: lua_pushstring(L, node->zone); break;
1107 case TYPE: lua_pushinteger(L, node->type); break;
1108 case AVAILABLE: lua_pushboolean(L, node->available); break;
1109 default: lua_pushnil(L); break;
1116 static int node_setfield(lua_State *L)
1122 f = luaL_checkstring(L, 2);
1123 luaL_error(L, "attempt to set '%s' field of read-only node", f);
1128 static int node_tostring(lua_State *L)
1134 sn = (scripting_node *)mrp_lua_check_object(L, NODE_CLASS, 1);
1136 lua_pushstring(L, (sn && sn->id) ? sn->id : "<unknown node>");
1141 static void node_destroy(void *data)
1143 scripting_node *sn = (scripting_node *)data;
1148 if ((node = sn->node) && sn == node->scripting)
1149 node->scripting = NULL;
1151 pa_xfree((void *)sn->id);
1153 MRP_LUA_LEAVE_NOARG;
1157 static int zone_create(lua_State *L)
1159 static uint32_t index;
1164 scripting_zone *zone;
1165 const char *name = NULL;
1166 attribute_t *attributes = NULL;
1170 lua_getglobal(L, USERDATA);
1171 if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
1172 luaL_error(L, "missing or invalid global '" USERDATA "'");
1176 MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
1178 switch (field_name_to_type(fldnam, fldnamlen)) {
1179 case NAME: name = luaL_checkstring(L, -1); break;
1180 case ATTRIBUTES: attributes = attributes_check(L, -1); break;
1181 default: luaL_error(L, "bad field '%s'", fldnam); break;
1184 } /* MRP_LUA_FOREACH_FIELD */
1187 luaL_error(L, "missing or invalid name field");
1189 if (pa_zoneset_add_zone(u, name, index+1))
1190 luaL_error(L, "attempt to define zone '%s' multiple times", name);
1192 zone = (scripting_zone *)mrp_lua_create_object(L, ZONE_CLASS, name, 0);
1195 zone->name = pa_xstrdup(name);
1196 zone->index = ++index;
1202 static int zone_getfield(lua_State *L)
1204 scripting_zone *zone;
1209 fld = field_check(L, 2, NULL);
1212 if (!(zone = (scripting_zone *)mrp_lua_check_object(L, ZONE_CLASS, 1)))
1216 case NAME: lua_pushstring(L, zone->name); break;
1218 case ATTRIBUTES: lua_pushinteger(L, rtgs->type); break;
1220 default: lua_pushnil(L); break;
1227 static int zone_setfield(lua_State *L)
1233 f = luaL_checkstring(L, 2);
1234 luaL_error(L, "attempt to set '%s' field of read-only zone", f);
1239 static void zone_destroy(void *data)
1241 scripting_zone *zone = (scripting_zone *)data;
1245 pa_xfree((void *)zone->name);
1249 MRP_LUA_LEAVE_NOARG;
1253 static int resource_create(lua_State *L)
1259 scripting_resource *res;
1260 resource_name_t *name = NULL;
1261 attribute_t *attributes = NULL;
1266 lua_getglobal(L, USERDATA);
1267 if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
1268 luaL_error(L, "missing or invalid global '" USERDATA "'");
1272 MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
1274 switch (field_name_to_type(fldnam, fldnamlen)) {
1275 case NAME: name = resource_names_check(L, -1); break;
1276 case ATTRIBUTES: attributes = attributes_check(L, -1); break;
1277 default: luaL_error(L, "bad field '%s'", fldnam); break;
1280 } /* MRP_LUA_FOREACH_FIELD */
1283 luaL_error(L, "missing or invalid name field");
1285 pa_murphyif_add_audio_resource(u, mir_input, name->playback);
1286 pa_murphyif_add_audio_resource(u, mir_output, name->recording);
1289 for (attr = attributes; attr->prop && attr->def.name; attr++) {
1290 switch (attr->def.type) {
1292 pa_murphyif_add_audio_attribute(u, attr->prop,
1295 attr->def.value.string);
1298 pa_murphyif_add_audio_attribute(u, attr->prop,
1301 attr->def.value.integer);
1304 pa_murphyif_add_audio_attribute(u, attr->prop,
1307 attr->def.value.unsignd);
1310 pa_murphyif_add_audio_attribute(u, attr->prop,
1313 attr->def.value.floating);
1316 luaL_error(L, "invalid audio resource attribute '%s'",
1323 res = (scripting_resource *)mrp_lua_create_object(L, RTGROUP_CLASS,
1328 res->attributes = attributes;
1333 static int resource_getfield(lua_State *L)
1335 scripting_resource *res;
1340 fld = field_check(L, 2, NULL);
1343 if (!(res = (scripting_resource*)mrp_lua_check_object(L,RESOURCE_CLASS,1)))
1348 case NAME: lua_pushstring(L, rtg->name); break;
1349 case ATTRIBUTES: lua_pushinteger(L, rtgs->type); break;
1350 default: lua_pushnil(L); break;
1360 static int resource_setfield(lua_State *L)
1366 f = luaL_checkstring(L, 2);
1367 luaL_error(L, "attempt to set '%s' field of read-only resource_class", f);
1372 static void resource_destroy(void *data)
1374 scripting_resource *res = (scripting_resource *)data;
1378 resource_names_destroy(res->name);
1379 attributes_destroy(res->attributes);
1382 res->attributes = NULL;
1384 MRP_LUA_LEAVE_NOARG;
1388 static int rtgroup_create(lua_State *L)
1394 scripting_rtgroup *rtgs;
1395 const char *name = NULL;
1396 mir_direction type = 0;
1397 mrp_funcbridge_t *accept = NULL;
1398 mrp_funcbridge_t *compare = NULL;
1403 lua_getglobal(L, USERDATA);
1404 if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
1405 luaL_error(L, "missing or invalid global '" USERDATA "'");
1409 MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
1411 switch (field_name_to_type(fldnam, fldnamlen)) {
1412 case NAME: name = luaL_checkstring(L, -1); break;
1413 case NODE_TYPE: type = luaL_checkint(L, -1); break;
1414 case ACCEPT: accept = mrp_funcbridge_create_luafunc(L, -1); break;
1415 case COMPARE: compare = mrp_funcbridge_create_luafunc(L, -1); break;
1416 default: luaL_error(L, "bad field '%s'", fldnam); break;
1419 } /* MRP_LUA_FOREACH_FIELD */
1422 luaL_error(L, "missing name field");
1423 if (type != mir_input && type != mir_output)
1424 luaL_error(L, "missing or invalid node_type");
1426 luaL_error(L, "missing or invalid accept field");
1428 luaL_error(L, "missing or invalid compare field");
1430 make_id(id,sizeof(id), "%s_%sput", name, (type == mir_input) ? "in":"out");
1432 rtgs = (scripting_rtgroup *)mrp_lua_create_object(L, RTGROUP_CLASS, id,0);
1434 rtg = mir_router_create_rtgroup(u, type, pa_xstrdup(name),
1435 rtgroup_accept, rtgroup_compare);
1437 luaL_error(L, "failed to create routing group '%s'", id);
1439 rtg->scripting = rtgs;
1444 rtgs->accept = accept;
1445 rtgs->compare = compare;
1450 static int rtgroup_getfield(lua_State *L)
1452 scripting_rtgroup *rtgs;
1458 fld = field_check(L, 2, NULL);
1461 if (!(rtgs = (scripting_rtgroup *)mrp_lua_check_object(L,RTGROUP_CLASS,1)))
1464 pa_assert_se((rtg = rtgs->rtg));
1467 case NAME: lua_pushstring(L, rtg->name); break;
1468 case NODE_TYPE: lua_pushinteger(L, rtgs->type); break;
1469 default: lua_pushnil(L); break;
1476 static int rtgroup_setfield(lua_State *L)
1482 f = luaL_checkstring(L, 2);
1483 luaL_error(L, "attempt to set '%s' field of read-only routing_group", f);
1488 static int rtgroup_tostring(lua_State *L)
1490 scripting_rtgroup *rtgs;
1495 rtgs = (scripting_rtgroup *)mrp_lua_check_object(L, RTGROUP_CLASS, 1);
1496 pa_assert_se((rtg = rtgs->rtg));
1498 lua_pushstring(L, rtg->name);
1503 static void rtgroup_destroy(void *data)
1505 scripting_rtgroup *rtgs = (scripting_rtgroup *)data;
1510 pa_assert_se((rtg = rtgs->rtg));
1511 pa_assert(rtgs == rtg->scripting);
1513 rtg->scripting = NULL;
1515 MRP_LUA_LEAVE_NOARG;
1519 static bool rtgroup_accept(struct userdata *u,
1523 pa_scripting *scripting;
1525 scripting_rtgroup *rtgs;
1526 mrp_funcbridge_value_t args[2];
1528 mrp_funcbridge_value_t rv;
1532 pa_assert_se((scripting = u->scripting));
1533 pa_assert_se((L = scripting->L));
1535 pa_assert_se((rtgs = rtg->scripting));
1536 pa_assert(u == rtgs->userdata);
1537 pa_assert(rtgs->accept);
1542 if ((rtgs = rtg->scripting) && node->scripting) {
1544 args[0].pointer = rtgs;
1545 args[1].pointer = node->scripting;
1547 if (!mrp_funcbridge_call_from_c(L, rtgs->accept, "oo",args, &rt,&rv)) {
1548 if (rt != MRP_FUNCBRIDGE_STRING)
1549 pa_log("call to accept function failed");
1551 pa_log("call to accept function failed: %s", rv.string);
1552 mrp_free((void *)rv.string);
1556 if (rt != MRP_FUNCBRIDGE_BOOLEAN)
1557 pa_log("accept function returned invalid type");
1559 accept = rv.boolean;
1566 static int rtgroup_compare(struct userdata *u,
1571 pa_scripting *scripting;
1573 scripting_rtgroup *rtgs;
1574 mrp_funcbridge_value_t args[3];
1576 mrp_funcbridge_value_t rv;
1580 pa_assert_se((scripting = u->scripting));
1581 pa_assert_se((L = scripting->L));
1583 pa_assert_se((rtgs = rtg->scripting));
1584 pa_assert(u == rtgs->userdata);
1585 pa_assert(rtgs->compare);
1591 if ((rtgs = rtg->scripting) && node1->scripting && node2->scripting) {
1593 args[0].pointer = rtgs;
1594 args[1].pointer = node1->scripting;
1595 args[2].pointer = node2->scripting;
1597 if (!mrp_funcbridge_call_from_c(L, rtgs->compare, "ooo",args, &rt,&rv))
1598 pa_log("failed to call compare function");
1600 if (rt != MRP_FUNCBRIDGE_FLOATING)
1601 pa_log("compare function returned invalid type");
1603 result = rv.floating;
1611 static bool accept_bridge(lua_State *L, void *data,
1612 const char *signature, mrp_funcbridge_value_t *args,
1613 char *ret_type, mrp_funcbridge_value_t *ret_val)
1615 mir_rtgroup_accept_t accept;
1616 scripting_rtgroup *rtgs;
1625 pa_assert(signature);
1627 pa_assert(ret_type);
1630 pa_assert_se((accept = (mir_rtgroup_accept_t)data));
1632 if (strcmp(signature, "oo"))
1635 pa_assert_se((rtgs = args[0].pointer));
1636 pa_assert_se((u = rtgs->userdata));
1637 pa_assert_se((ns = args[1].pointer));
1639 if (!(rtg = rtgs->rtg) || !(node = ns->node))
1643 *ret_type = MRP_FUNCBRIDGE_BOOLEAN;
1644 ret_val->boolean = accept(u, rtg, node);
1652 static bool compare_bridge(lua_State *L, void *data,
1653 const char *signature, mrp_funcbridge_value_t *args,
1654 char *ret_type, mrp_funcbridge_value_t *ret_val)
1656 mir_rtgroup_compare_t compare;
1657 scripting_rtgroup *rtgs;
1658 scripting_node *ns1, *ns2;
1661 mir_node *node1, *node2;
1666 pa_assert(signature);
1668 pa_assert(ret_type);
1671 pa_assert_se((compare = (mir_rtgroup_compare_t)data));
1673 if (strcmp(signature, "ooo"))
1676 pa_assert_se((rtgs = args[0].pointer));
1677 pa_assert_se((u = rtgs->userdata));
1678 pa_assert_se((ns1 = args[1].pointer));
1679 pa_assert_se((ns2 = args[2].pointer));
1682 if (!(rtg = rtgs->rtg) || !(node1 = ns1->node) || !(node2 = ns2->node))
1686 *ret_type = MRP_FUNCBRIDGE_FLOATING;
1687 ret_val->floating = compare(u, rtg, node1, node2);
1695 static bool change_bridge(lua_State *L, void *data,
1696 const char *signature, mrp_funcbridge_value_t *args,
1697 char *ret_type, mrp_funcbridge_value_t *ret_val)
1699 mir_change_value_t change;
1700 scripting_import *imp;
1703 const char *s = "default";
1707 pa_assert(signature);
1709 pa_assert(ret_type);
1712 pa_assert_se((change = (mir_change_value_t)data));
1714 if (strcmp(signature, "o"))
1717 pa_assert_se((imp = args[0].pointer));
1718 pa_assert_se((u = imp->userdata));
1720 /* FIXME: is this how it is supposed to be done?! */
1722 if (imp->values && imp->values->array && imp->values->array[0] &&
1723 imp->values->array[0]->array &&
1724 imp->values->array[0]->array[0] &&
1725 imp->values->array[0]->array[0]->type == pa_value_string)
1726 pa_assert_se((s = imp->values->array[0]->array[0]->string));
1729 *ret_type = MRP_FUNCBRIDGE_NO_DATA;
1730 memset(ret_val, 0, sizeof(mrp_funcbridge_value_t));
1738 static int apclass_create(lua_State *L)
1743 scripting_apclass *ac;
1745 const char *class = NULL;
1746 mir_node_type type = -1;
1748 route_t *route = NULL;
1749 map_t *roles = NULL;
1750 map_t *binaries = NULL;
1751 bool needs_resource = false;
1752 pa_nodeset_resdef *resdef;
1760 lua_getglobal(L, USERDATA);
1761 if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
1762 luaL_error(L, "missing or invalid global '" USERDATA "'");
1766 MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
1768 switch (field_name_to_type(fldnam, fldnamlen)) {
1769 case CLASS: class = luaL_checkstring(L, -1); break;
1770 case NODE_TYPE: type = luaL_checkint(L, -1); break;
1771 case PRIORITY: priority = luaL_checkint(L, -1); break;
1772 case ROUTE: route = route_check(L, -1); break;
1773 case ROLES: roles = map_check(L, -1); break;
1774 case BINARIES: binaries = map_check(L, -1); break;
1775 default: luaL_error(L, "bad field '%s'", fldnam); break;
1778 } /* MRP_LUA_FOREACH_FIELD */
1780 if (type < mir_application_class_begin ||
1781 type >= mir_application_class_end )
1782 luaL_error(L, "missing or invalid node_type %d", type);
1784 luaL_error(L, "missing or invalid priority field");
1786 luaL_error(L, "missing or invalid route field");
1787 if (!roles && !binaries)
1788 luaL_error(L, "missing roles or binaries");
1790 make_id(name, sizeof(name), "%s", mir_node_type_str(type));
1792 mir_router_assign_class_priority(u, type, priority);
1797 for (i = 0; i < MRP_ZONE_MAX; i++) {
1798 if ((n = route->input[i]))
1799 ir &= mir_router_assign_class_to_rtgroup(u,type,i,mir_input,n);
1803 if (route->output) {
1804 for (i = 0; i < MRP_ZONE_MAX; i++) {
1805 if ((n = route->output[i]))
1806 or &= mir_router_assign_class_to_rtgroup(u,type,i,mir_output,n);
1810 ac = (scripting_apclass *)mrp_lua_create_object(L, APPLICATION_CLASS,
1813 if (!ir || !or || !ac)
1814 luaL_error(L, "failed to create application class '%s'", name);
1817 ac->name = pa_xstrdup(name);
1818 ac->class = class ? pa_xstrdup(class) : NULL;
1820 ac->priority = priority;
1823 ac->binaries = binaries;
1826 if (pa_nodeset_add_class(u, type, class)) {
1827 luaL_error(L, "node type '%s' is defined multiple times",
1828 mir_node_type_str(type));
1833 for (r = roles; r->name; r++) {
1834 resdef = r->needres ? &r->resource : NULL;
1836 if (r->role && strcmp(r->role, r->name)) {
1837 luaL_error(L, "conflicting roles in role definition '%s' (%s)",
1841 if (pa_nodeset_add_role(u, r->name, type, resdef)) {
1842 luaL_error(L, "role '%s' is added to mutiple application "
1843 "classes", r->name);
1849 for (b = binaries; b->name; b++) {
1850 resdef = b->needres ? &b->resource : NULL;
1852 if (pa_nodeset_add_binary(u, b->name, type, b->role, resdef)) {
1853 luaL_error(L, "binary '%s' is added to multiple application "
1854 "classes", b->name);
1862 static int apclass_getfield(lua_State *L)
1864 scripting_apclass *ac;
1869 fld = field_check(L, 2, NULL);
1872 if (!(ac=(scripting_apclass *)mrp_lua_check_object(L,APPLICATION_CLASS,1)))
1876 case NAME: lua_pushstring(L, ac->name); break;
1877 case NODE_TYPE: lua_pushinteger(L, ac->type); break;
1878 case PRIORITY: lua_pushinteger(L, ac->priority); break;
1879 case ROUTE: route_push(L, ac->route); break;
1880 case ROLES: map_push(L, ac->roles); break;
1881 case BINARIES: map_push(L, ac->binaries); break;
1882 default: lua_pushnil(L); break;
1889 static int apclass_setfield(lua_State *L)
1895 f = luaL_checkstring(L, 2);
1896 luaL_error(L,"attempt to set '%s' field of read-only application class",f);
1901 static int apclass_tostring(lua_State *L)
1903 scripting_apclass *ac;
1907 ac = (scripting_apclass *)mrp_lua_check_object(L, APPLICATION_CLASS, 1);
1909 lua_pushstring(L, ac->name);
1914 static void apclass_destroy(void *data)
1916 scripting_apclass *ac = (scripting_apclass *)data;
1924 pa_assert_se((u = ac->userdata));
1926 route_destroy(ac->route);
1929 pa_xfree((void *)ac->name);
1932 pa_nodeset_delete_class(u, ac->type);
1933 pa_xfree((void *)ac->class);
1937 for (r = ac->roles; r->name; r++)
1938 pa_nodeset_delete_role(u, r->name);
1940 map_destroy(ac->roles);
1945 for (b = ac->binaries; b->name; b++)
1946 pa_nodeset_delete_binary(u, b->name);
1948 map_destroy(ac->binaries);
1949 ac->binaries = NULL;
1952 MRP_LUA_LEAVE_NOARG;
1955 static const char **route_definition_check(lua_State *L, int idx)
1958 const char *zonenam;
1959 scripting_zone *zone;
1960 scripting_rtgroup *rtgs;
1966 idx = (idx < 0) ? lua_gettop(L) + idx + 1 : idx;
1968 luaL_checktype(L, idx, LUA_TTABLE);
1970 defs = pa_xnew0(const char *, MRP_ZONE_MAX);
1973 MRP_LUA_FOREACH_FIELD(L, idx, zonenam, zonelen) {
1975 luaL_error(L, "invalid route definition");
1977 mrp_lua_find_object(L, ZONE_CLASS, zonenam);
1979 if (!(zone = mrp_lua_check_object(L, NULL, -1)))
1980 luaL_error(L, "can't find zone '%s'", zonenam);
1984 if (zone->index >= MRP_ZONE_MAX)
1985 luaL_error(L, "Internal error: zone index overflow");
1987 switch (lua_type(L, -1)) {
1989 rtgnam = lua_tostring(L, -1);
1992 rtgs = (scripting_rtgroup*)mrp_lua_check_object(L,RTGROUP_CLASS,-1);
1993 if (!rtgs || !(rtg = rtgs->rtg))
2004 luaL_error(L, "missing or invalid routing group");
2006 defs[zone->index] = pa_xstrdup(rtgnam);
2011 luaL_error(L, "empty definition");
2016 static int route_definition_push(lua_State *L, const char **defs)
2020 lua_createtable(L, MRP_ZONE_MAX, 0);
2022 for (i = 0; i < MRP_ZONE_MAX; i++) {
2029 static void route_definition_free(const char **defs)
2034 for (i = 0; i < MRP_ZONE_MAX; i++)
2035 pa_xfree((void *)defs[i]);
2036 pa_xfree((void *)defs);
2041 static route_t *route_check(lua_State *L, int idx)
2046 const char **input = NULL;
2047 const char **output = NULL;
2049 idx = (idx < 0) ? lua_gettop(L) + idx + 1 : idx;
2051 luaL_checktype(L, idx, LUA_TTABLE);
2053 MRP_LUA_FOREACH_FIELD(L, idx, fldnam, fldnamlen) {
2054 switch (field_name_to_type(fldnam, fldnamlen)) {
2055 case INPUT: input = route_definition_check(L, -1); break;
2056 case OUTPUT: output = route_definition_check(L, -1); break;
2057 default: luaL_error(L, "invalid field '%s'", fldnam); break;
2059 } /* MRP_LUA_FOREACH_FIELD */
2061 if (!input && !output)
2062 luaL_error(L, "neither input nor output routing group were specified");
2064 rt = pa_xmalloc(sizeof(route_t));
2066 rt->output = output;
2071 static int route_push(lua_State *L, route_t *rt)
2073 if (!rt || (!rt->input && !rt->output))
2076 lua_createtable(L, 0, 2);
2079 lua_pushstring(L, "input");
2080 route_definition_push(L, rt->input);
2081 lua_settable(L, -3);
2085 lua_pushstring(L, "output");
2086 route_definition_push(L, rt->output);
2087 lua_settable(L, -3);
2094 static void route_destroy(route_t *rt)
2097 pa_xfree((void *)rt->input);
2098 pa_xfree((void *)rt->output);
2099 pa_xfree((void *)rt);
2104 static int vollim_create(lua_State *L)
2106 static int min = mir_application_class_begin;
2107 static int max = mir_application_class_end;
2112 scripting_vollim *vlim;
2113 const char *name = NULL;
2114 vollim_type type = 0;
2115 limit_data_t *limit = NULL;
2116 mrp_funcbridge_t *calculate = NULL;
2117 intarray_t *classes = NULL;
2118 bool suppress = false;
2119 bool correct = false;
2123 uint32_t mask, clmask;
2128 lua_getglobal(L, USERDATA);
2129 if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
2130 luaL_error(L, "missing or invalid global '" USERDATA "'");
2134 MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
2136 switch (field_name_to_type(fldnam, fldnamlen)) {
2137 case NAME: name = luaL_checkstring(L, -1); break;
2138 case TYPE: type = luaL_checkint(L, -1); break;
2139 case NODE_TYPE: classes = intarray_check(L, -1, min, max); break;
2140 case LIMIT: limit = limit_data_check(L, -1); break;
2141 case CALCULATE: calculate = mrp_funcbridge_create_luafunc(L,-1); break;
2142 default: luaL_error(L, "bad field '%s'", fldnam); break;
2145 } /* MRP_LUA_FOREACH_FIELD */
2148 luaL_error(L, "missing name field");
2149 if (type != vollim_class && type != vollim_generic && type != vollim_maximum)
2150 luaL_error(L, "missing or invalid type");
2151 if ((type == vollim_class || type == vollim_maximum) && !classes)
2152 luaL_error(L, "missing or invalid node_type for class/maximum limit");
2153 if (type == vollim_generic && classes)
2154 luaL_error(L, "can't specify node_type for generic volume limit");
2156 luaL_error(L, "missing or invalid limit");
2157 if (type != vollim_maximum && !calculate)
2158 luaL_error(L, "missing calculate field");
2159 if (type != vollim_maximum) {
2160 if (calculate->type == MRP_C_FUNCTION) {
2161 if (strcmp(calculate->c.signature, "odo"))
2162 luaL_error(L,"invalid calculate field (mismatching signature)");
2163 if (calculate->c.data == mir_volume_suppress) {
2164 if (type != vollim_class)
2165 luaL_error(L, "attempt to make generic volume supression");
2167 arglgh = sizeof(mir_volume_suppress_arg);
2169 else if (calculate->c.data == mir_volume_correction) {
2170 if (type != vollim_generic) {
2171 luaL_error(L, "attempt to make class based volume"
2175 arglgh = sizeof(double *);
2178 luaL_error(L, "invalid builtin.method for calculate");
2185 arglgh = sizeof(mir_volume_suppress_arg);
2187 case vollim_generic:
2189 arglgh = sizeof(double *);
2197 make_id(id, sizeof(id), "%s", name);
2199 (VOLLIM_CLASS)->userdata_size = sizeof(scripting_vollim) + arglgh;
2200 vlim = (scripting_vollim *)mrp_lua_create_object(L, VOLLIM_CLASS, id,0);
2201 (VOLLIM_CLASS)->userdata_size = sizeof(scripting_vollim);
2204 vlim->name = pa_xstrdup(name);
2206 vlim->classes = classes;
2207 vlim->limit = limit;
2208 vlim->calculate = calculate;
2211 mir_volume_suppress_arg *args = (mir_volume_suppress_arg *)vlim->args;
2212 size_t size = sizeof(int) * classes->nint;
2213 size_t n = mir_application_class_end - mir_application_class_begin;
2215 for (i = 0, clmask = 0; i < classes->nint; i++) {
2216 class = classes->ints[i];
2218 if (class <= mir_application_class_begin ||
2219 class > mir_application_class_end )
2221 pa_log("invalid triggering class id %d", class);
2223 classes->nint = n = 0;
2227 mask = ((uint32_t)1) << (class - mir_application_class_begin);
2229 if (!(clmask & mask) && n > 0)
2235 args->attenuation = limit->value;
2236 args->trigger.nclass = classes->nint;
2237 args->trigger.classes = pa_xmalloc(size);
2238 args->trigger.clmask = clmask;
2240 memcpy(args->trigger.classes, classes->ints, size);
2242 if (n > classes->nint)
2243 classes->ints = pa_xrealloc(classes->ints, sizeof(int) * n);
2246 for (i = mir_application_class_begin, n = 0;
2247 i < mir_application_class_end;
2250 if (!(clmask & (((uint32_t)1) << (i-mir_application_class_begin))))
2251 classes->ints[n++] = i;
2255 /* *(double **)vlim->args = limit->value; */
2257 memcpy(vlim->args, &limit->value, sizeof(limit->value));
2261 case vollim_generic:
2262 mir_volume_add_generic_limit(u, vollim_calculate, vlim->args);
2265 for (i = 0; i < classes->nint; i++) {
2266 mir_volume_add_class_limit(u, classes->ints[i], vollim_calculate,
2270 case vollim_maximum:
2271 mir_volume_add_maximum_limit(u, *(vlim->limit->value),
2272 classes->nint, classes->ints);
2281 static int vollim_getfield(lua_State *L)
2283 scripting_vollim *vlim;
2288 fld = field_check(L, 2, NULL);
2291 if (!(vlim = (scripting_vollim *)mrp_lua_check_object(L, VOLLIM_CLASS, 1)))
2295 case NAME: lua_pushstring(L, vlim->name); break;
2296 case TYPE: lua_pushinteger(L, vlim->type); break;
2297 case NODE_TYPE: intarray_push(L, vlim->classes); break;
2298 case LIMIT: lua_pushnumber(L, *vlim->limit->value); break;
2299 default: lua_pushnil(L); break;
2306 static int vollim_setfield(lua_State *L)
2312 f = luaL_checkstring(L, 2);
2313 luaL_error(L, "attempt to set '%s' field of read-only volume_limit", f);
2318 static int vollim_tostring(lua_State *L)
2320 scripting_vollim *vlim;
2324 vlim = (scripting_vollim *)mrp_lua_check_object(L, VOLLIM_CLASS, 1);
2326 lua_pushstring(L, vlim->name);
2331 static void vollim_destroy(void *data)
2333 scripting_vollim *vlim = (scripting_vollim *)data;
2337 pa_xfree((void *)vlim->name);
2338 intarray_destroy(vlim->classes);
2339 limit_data_destroy(vlim->limit);
2341 MRP_LUA_LEAVE_NOARG;
2345 static double vollim_calculate(struct userdata *u, int class, mir_node *node,
2348 static int offset = ((scripting_vollim *)0)->args - (char *)0;
2350 pa_scripting *scripting;
2352 scripting_vollim *vlim;
2353 mrp_funcbridge_value_t args[3];
2355 mrp_funcbridge_value_t rv;
2359 pa_assert_se((scripting = u->scripting));
2360 pa_assert_se((L = scripting->L));
2361 pa_assert(!class || (class >= mir_application_class_begin &&
2362 class < mir_application_class_end) );
2365 vlim = (scripting_vollim *)(data - offset);
2367 pa_assert(u == vlim->userdata);
2371 if (node->scripting) {
2373 args[0].pointer = vlim;
2374 args[1].integer = class;
2375 args[2].pointer = node->scripting;
2377 if (!mrp_funcbridge_call_from_c(L,vlim->calculate,"odo",args,&rt,&rv))
2378 pa_log("failed to call calculate function");
2380 if (rt != MRP_FUNCBRIDGE_FLOATING)
2381 pa_log("accept function returned invalid type");
2383 limit = rv.floating;
2390 static bool calculate_bridge(lua_State *L, void *data, const char *signature,
2391 mrp_funcbridge_value_t *args,
2392 char *ret_type, mrp_funcbridge_value_t *ret_val)
2394 mir_volume_func_t calculate;
2395 scripting_vollim *vlim;
2404 pa_assert(signature);
2406 pa_assert(ret_type);
2409 pa_assert_se((calculate = (mir_volume_func_t)data));
2411 if (strcmp(signature, "odo"))
2414 pa_assert_se((vlim = args[0].pointer));
2415 pa_assert_se((u = vlim->userdata));
2416 pa_assert_se((ns = args[2].pointer));
2418 class = args[1].integer;
2420 pa_assert(!class || (class >= mir_application_class_begin &&
2421 class < mir_application_class_end));
2423 if (!(node = ns->node))
2427 *ret_type = MRP_FUNCBRIDGE_FLOATING;
2428 /* TODO: check the vollim type vs. c function */
2429 ret_val->floating = calculate(u, class, node, vlim->args);
2436 static limit_data_t *limit_data_check(lua_State *L, int idx)
2438 static double nolimit = 0.0;
2444 switch (lua_type(L, idx)) {
2446 if ((value = lua_tonumber(L, idx)) > 0.0)
2447 luaL_error(L, "volume limit is in dB and can't be positive");
2449 ld = pa_xnew0(limit_data_t, 1);
2451 ld->value = pa_xnew0(double, 1);
2455 case LUA_TLIGHTUSERDATA:
2456 if (!(v = lua_touserdata(L, idx)) || v->type < 0)
2457 luaL_error(L, "broken link for volume limit value");
2459 ld = pa_xnew0(limit_data_t, 1);
2460 ld->mallocd = false;
2461 ld->value = &v->floating;
2465 ld->mallocd = false;
2466 ld->value = &nolimit;
2474 static int limit_data_push(lua_State *L, limit_data_t *ld)
2477 lua_pushnumber(L, *ld->value);
2485 static void limit_data_destroy(limit_data_t *ld)
2489 pa_xfree(ld->value);
2495 static intarray_t *intarray_check(lua_State *L, int idx, int min, int max)
2503 idx = (idx < 0) ? lua_gettop(L) + idx + 1 : idx;
2505 luaL_checktype(L, idx, LUA_TTABLE);
2507 if ((len = luaL_getn(L, idx)) < 1)
2510 size = sizeof(intarray_t) + sizeof(int) * len;
2511 arr = pa_xmalloc0(sizeof(intarray_t));
2514 arr->ints = pa_xmalloc0(size);
2516 for (i = 0; i < len; i++) {
2517 lua_pushnumber(L, (int)(i+1));
2518 lua_gettable(L, idx);
2520 val = luaL_checkint(L, -1);
2524 if (val < min || val >= max)
2525 luaL_error(L, "array [%u]: out of range value (%d)", i, val);
2534 static int intarray_push(lua_State *L, intarray_t *arr)
2541 lua_createtable(L, arr->nint, 0);
2543 for (i = 0; i < arr->nint; i++) {
2544 lua_pushinteger(L, (int)(i+1));
2545 lua_pushinteger(L, arr->ints[i]);
2546 lua_settable(L, -3);
2553 static void intarray_destroy(intarray_t *arr)
2556 pa_xfree(arr->ints);
2561 static resource_name_t *resource_names_check(lua_State *L, int tbl)
2563 resource_name_t *name;
2568 tbl = (tbl < 0) ? lua_gettop(L) + tbl + 1 : tbl;
2570 luaL_checktype(L, tbl, LUA_TTABLE);
2572 name = pa_xnew0(resource_name_t, 1);
2574 MRP_LUA_FOREACH_FIELD(L, tbl, fldnam, fldnamlen) {
2575 value = luaL_checkstring(L, -1);
2577 if (!strcmp(fldnam, "recording"))
2578 name->recording = pa_xstrdup(value);
2579 else if (!strcmp(fldnam, "playback"))
2580 name->playback = pa_xstrdup(value);
2582 luaL_error(L, "invalid field '%s' in resource name definition",
2590 static void resource_names_destroy(resource_name_t *name)
2593 pa_xfree((void *)name->recording);
2594 pa_xfree((void *)name->playback);
2599 static attribute_t *attributes_check(lua_State *L, int tbl)
2604 attribute_t *attr, *attrs = NULL;
2606 mrp_attr_value_t *v;
2609 tbl = (tbl < 0) ? lua_gettop(L) + tbl + 1 : tbl;
2611 luaL_checktype(L, tbl, LUA_TTABLE);
2613 MRP_LUA_FOREACH_FIELD(L, tbl, fldnam, fldnamlen) {
2615 luaL_error(L, "invalid attribute definition");
2617 attrs = pa_xrealloc(attrs, sizeof(attribute_t) * (nattr + 2));
2618 memset(attrs + nattr, 0, sizeof(attribute_t) * 2);
2620 attr = attrs + nattr++;
2621 v = &attr->def.value;
2622 def = lua_gettop(L);
2624 attr->def.name = pa_xstrdup(fldnam);
2626 if ((len = luaL_getn(L, def)) != 3)
2627 luaL_error(L, "invalid attribute definition '%s'", fldnam);
2629 for (i = 0; i < len; i++) {
2630 lua_pushnumber(L, (int)(i+1));
2631 lua_gettable(L, def);
2634 case 0: attr->prop = pa_xstrdup(luaL_checkstring(L,-1)); break;
2635 case 1: attr->def.type = luaL_checkint(L,-1); break;
2637 switch (attr->def.type) {
2638 case mqi_string: v->string = luaL_checkstring(L,-1); break;
2639 case mqi_integer: v->integer = luaL_checkint(L,-1); break;
2640 case mqi_unsignd: v->integer = luaL_checkint(L,-1); break;
2641 case mqi_floating: v->floating = luaL_checknumber(L,-1); break;
2642 default: memset(v, 0, sizeof(*v)); break;
2650 luaL_error(L, "missing property name definition from '%s'",fldnam);
2651 if (attr->def.type != mqi_string && attr->def.type != mqi_integer &&
2652 attr->def.type != mqi_unsignd && attr->def.type != mqi_floating)
2654 luaL_error(L, "invalid attribute type %d for '%s'",
2655 attr->def.type, fldnam);
2657 if (attr->def.type == mqi_unsignd && attr->def.value.integer < 0) {
2658 luaL_error(L, "attempt to give negative value (%d) for field '%s'",
2659 attr->def.value.integer, fldnam);
2666 static void attributes_destroy(attribute_t *attrs)
2671 for (attr = attrs; attr->prop && attr->def.name; attr++) {
2672 pa_xfree((void *)attr->prop);
2673 pa_xfree((void *)attr->def.name);
2674 if (attr->def.type == mqi_string)
2675 pa_xfree((void *)attr->def.value.string);
2681 static map_t *map_check(lua_State *L, int tbl)
2688 map_t *m, *map = NULL;
2692 pa_nodeset_resdef *rd;
2694 tbl = (tbl < 0) ? lua_gettop(L) + tbl + 1 : tbl;
2696 luaL_checktype(L, tbl, LUA_TTABLE);
2698 MRP_LUA_FOREACH_FIELD(L, tbl, name, namlen) {
2700 luaL_error(L, "invalid role or binary definition");
2702 map = pa_xrealloc(map, sizeof(map_t) * (n + 2));
2703 memset(map + n, 0, sizeof(map_t) * 2);
2706 def = lua_gettop(L);
2708 m->name = pa_xstrdup(name);
2710 switch (lua_type(L, -1)) {
2718 m->role = mrp_strdup(lua_tostring(L, def));
2724 if ((len = luaL_getn(L, def)) < 1)
2725 luaL_error(L, "invalid resource definition '%s'", name);
2727 for (i = 1; i <= len; i++) {
2728 lua_pushnumber(L, (int)i);
2729 lua_gettable(L, def);
2732 priority = luaL_checkint(L, -1);
2734 if (priority < 0 || priority > 7) {
2735 luaL_error(L, "invalid priority %d for '%s'",
2739 m->resource.priority = priority;
2742 option = luaL_checkstring(L, -1);
2745 if (pa_streq(option, "autorelease"))
2746 rd->flags.rset |= RESPROTO_RSETFLAG_AUTORELEASE;
2747 else if (pa_streq(option, "mandatory"))
2748 rd->flags.audio |= RESPROTO_RESFLAG_MANDATORY;
2749 else if (pa_streq(option, "shared"))
2750 rd->flags.audio |= RESPROTO_RESFLAG_SHARED;
2751 else if (!pa_streq(option, "optional") &&
2752 !pa_streq(option, "exclusive") )
2755 m->role = pa_xstrdup(option);
2757 luaL_error(L, "multiple role definition '%s','%s'",
2769 luaL_error(L, "invalid resource specification. "
2770 "Should be either 'no_resource' or a table");
2773 } /* FOREACH_FIELD */
2778 static int map_push(lua_State *L, map_t *map)
2787 for (m = map; m->name; m++) {
2790 lua_pushstring(L, m->role);
2792 lua_pushnumber(L, 0);
2796 lua_pushinteger(L, m->resource.priority);
2798 lua_pushstring(L, m->role);
2799 if (m->resource.flags.rset & RESPROTO_RSETFLAG_AUTORELEASE)
2800 lua_pushstring(L, "autorelease");
2801 if (m->resource.flags.audio & RESPROTO_RESFLAG_MANDATORY)
2802 lua_pushstring(L, "mandatory");
2804 lua_pushstring(L, "optional");
2805 if (m->resource.flags.audio & RESPROTO_RESFLAG_SHARED)
2806 lua_pushstring(L, "shared");
2808 lua_pushstring(L, "exclusive");
2810 lua_setfield(L, -2, m->name);
2817 static void map_destroy(map_t *map)
2822 for (m = map; m->name; m++) {
2823 pa_xfree((void *)m->name);
2824 pa_xfree((void *)m->role);
2831 static field_t field_check(lua_State *L, int idx, const char **ret_fldnam)
2837 if (!(fldnam = lua_tolstring(L, idx, &fldnamlen)))
2840 fldtyp = field_name_to_type(fldnam, fldnamlen);
2843 *ret_fldnam = fldnam;
2848 static field_t field_name_to_type(const char *name, size_t len)
2855 if (!strcmp(name, "name"))
2859 if (!strcmp(name, "type"))
2863 if (!strcmp(name, "zone"))
2874 if (!strcmp(name, "class"))
2878 if (!strcmp(name, "input"))
2882 if (!strcmp(name, "limit"))
2886 if (!strcmp(name, "route"))
2888 if (!strcmp(name, "roles"))
2892 if (!strcmp(name, "table"))
2903 if (!strcmp(name, "accept"))
2907 if (!strcmp(name, "maxrow"))
2911 if (!strcmp(name, "output"))
2915 if (!strcmp(name, "tables"))
2919 if (!strcmp(name, "update"))
2930 if (!strcmp(name, "compare"))
2932 if (!strcmp(name, "columns"))
2936 if (!strcmp(name, "privacy"))
2947 if (!strcmp(name, "binaries"))
2951 if (!strcmp(name, "channels"))
2955 if (!strcmp(name, "location"))
2959 if (!strcmp(name, "priority"))
2970 if (!strcmp(name, "available"))
2974 if (!strcmp(name, "calculate"))
2976 if (!strcmp(name, "condition"))
2980 if (!strcmp(name, "direction"))
2984 if (!strcmp(name, "implement"))
2988 if (!strcmp(name, "node_type"))
2997 if (!strcmp(name, "attributes"))
3002 if (!strcmp(name, "autorelease"))
3004 if (!strcmp(name, "description"))
3015 static int make_id(char *buf, size_t len, const char *fmt, ...)
3022 l = vsnprintf(buf, len, fmt, ap);
3025 for (p = buf; (c = *p); p++) {
3028 else if (!isdigit(c))
3037 static void setup_murphy_interface(struct userdata *u)
3039 pa_scripting *scripting;
3040 scripting_import *imp;
3044 bool need_domainctl;
3046 const char *columns;
3053 pa_assert_se((scripting = u->scripting));
3054 pa_assert_se((L = scripting->L));
3056 top = lua_gettop(L);
3058 mrp_lua_get_class_table(L, IMPORT_CLASS);
3059 class = lua_gettop(L);
3061 if (!lua_istable(L, class)){
3062 luaL_error(L, "internal error: failed to find '%s' table",
3063 (IMPORT_CLASS)->constructor);
3066 need_domainctl = false;
3069 while (lua_next(L, class)) {
3070 if (lua_isstring(L, -2)) {
3071 if ((imp = mrp_lua_to_object(L, IMPORT_CLASS, -1))) {
3072 key = lua_tostring(L, -2);
3074 pa_assert(!strcmp(key, imp->table));
3075 pa_assert_se((values = imp->values));
3077 pa_log_debug("adding import '%s'", imp->table);
3079 need_domainctl = true;
3080 columns = comma_separated_list(imp->columns, buf,sizeof(buf));
3082 pa_murphyif_add_watch(u, imp->table, columns, imp->condition,
3090 pa_murphyif_setup_domainctl(u, import_data_changed);
3094 MRP_LUA_LEAVE_NOARG;
3098 static char *comma_separated_list(mrp_lua_strarray_t *arr, char *buf, int len)
3107 for (i = 0, e = (p = buf) + len; i < arr->nstring && p < e; i++)
3108 p += snprintf(p, e-p, "%s%s", (p == buf ? "" : ","), arr->strings[i]);
3110 return (p < e) ? buf : NULL;
3114 static bool define_constants(lua_State *L)
3116 static const_def_t mdb_const[] = {
3117 { "string" , mqi_string },
3118 { "integer" , mqi_integer },
3119 { "unsigned" , mqi_unsignd },
3120 { "floating" , mqi_floating },
3124 static const_def_t node_const[] = {
3125 { "input" , mir_input },
3126 { "output" , mir_output },
3127 { "device" , mir_device },
3128 { "stream" , mir_stream },
3129 { "internal" , mir_internal },
3130 { "external" , mir_external },
3131 { "radio" , mir_radio },
3132 { "player" , mir_player },
3133 { "navigator" , mir_navigator },
3134 { "game" , mir_game },
3135 { "browser" , mir_browser },
3136 { "camera" , mir_camera },
3137 { "phone" , mir_phone },
3138 { "alert" , mir_alert },
3139 { "event" , mir_event },
3140 { "system" , mir_system },
3141 { "speakers" , mir_speakers },
3142 { "microphone" , mir_microphone },
3143 { "jack" , mir_jack },
3144 { "spdif" , mir_spdif },
3145 { "hdmi" , mir_hdmi },
3146 { "wired_headset" , mir_wired_headset },
3147 { "wired_headphone" , mir_wired_headphone },
3148 { "usb_headset" , mir_usb_headset },
3149 { "usb_headphone" , mir_usb_headphone },
3150 { "bluetooth_sco" , mir_bluetooth_sco },
3151 { "bluetooth_a2dp" , mir_bluetooth_a2dp },
3152 { "bluetooth_carkit" , mir_bluetooth_carkit },
3153 { "bluetooth_source" , mir_bluetooth_source },
3154 { "bluetooth_sink" , mir_bluetooth_sink },
3158 static const_def_t vollim_const[] = {
3159 { "class" , vollim_class },
3160 { "generic" , vollim_generic },
3161 { "maximum" , vollim_maximum },
3166 bool success = true;
3169 lua_getglobal(L, "mdb");
3171 if (!lua_istable(L, -1))
3174 for (cd = mdb_const; cd->name; cd++) {
3175 lua_pushstring(L, cd->name);
3176 lua_pushinteger(L, cd->value);
3184 lua_getglobal(L, "node");
3186 if (!lua_istable(L, -1))
3189 for (cd = node_const; cd->name; cd++) {
3190 lua_pushstring(L, cd->name);
3191 lua_pushinteger(L, cd->value);
3198 lua_getglobal(L, "volume_limit");
3200 if (!lua_istable(L, -1))
3203 for (cd = vollim_const; cd->name; cd++) {
3204 lua_pushstring(L, cd->name);
3205 lua_pushinteger(L, cd->value);
3211 lua_pushnumber(L, 0);
3212 lua_setglobal(L, "no_resource");
3218 static bool register_methods(lua_State *L)
3220 static funcbridge_def_t funcbridge_defs[] = {
3221 {"make_routes" ,"o" , update_bridge ,mir_router_make_routing },
3222 {"make_volumes" ,"o" , update_bridge ,mir_volume_make_limiting },
3223 {"accept_default" ,"oo" , accept_bridge ,mir_router_default_accept },
3224 {"compare_default","ooo", compare_bridge ,mir_router_default_compare},
3225 {"accept_phone" ,"oo" , accept_bridge ,mir_router_phone_accept },
3226 {"compare_phone" ,"ooo", compare_bridge ,mir_router_phone_compare },
3227 {"volume_supress" ,"odo", calculate_bridge,mir_volume_suppress },
3228 {"volume_correct" ,"odo", calculate_bridge,mir_volume_correction },
3229 {"change_volume_context","o",change_bridge,mir_volume_change_context},
3230 { NULL , NULL, NULL , NULL }
3233 funcbridge_def_t *d;
3234 bool success = true;
3236 for (d = funcbridge_defs; d->name; d++) {
3237 if (!mrp_funcbridge_create_cfunc(L,d->name,d->sign,d->func,d->data)) {
3238 pa_log("%s: failed to register builtin function '%s'",
3249 static void *alloc(void *ud, void *ptr, size_t osize, size_t nsize)
3257 mem = pa_xrealloc(ptr, nsize);
3266 static int panic(lua_State *L)
3270 pa_log("PANIC: unprotected error in call to Lua API (%s)",
3271 lua_tostring(L,-1));
3280 * indent-tabs-mode: nil