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;
187 mrp_funcbridge_cfunc_t func;
224 static int import_create(lua_State *);
225 static int import_getfield(lua_State *);
226 static int import_setfield(lua_State *);
227 static int import_tostring(lua_State *);
228 static void import_destroy(void *);
230 static int import_link(lua_State *);
232 static void import_data_changed(struct userdata *, const char *,
233 int, mrp_domctl_value_t **);
234 static bool update_bridge(lua_State *, void *, const char *,
235 mrp_funcbridge_value_t *, char *,
236 mrp_funcbridge_value_t *);
238 static void array_class_create(lua_State *);
239 static pa_value *array_create(lua_State *, int, mrp_lua_strarray_t *);
240 static int array_getfield(lua_State *);
241 static int array_setfield(lua_State *);
242 static int array_getlength(lua_State *);
245 static void array_destroy(void *);
248 static int node_create(lua_State *);
249 static int node_getfield(lua_State *);
250 static int node_setfield(lua_State *);
251 static int node_tostring(lua_State *);
252 static void node_destroy(void *);
254 static int zone_create(lua_State *);
255 static int zone_getfield(lua_State *);
256 static int zone_setfield(lua_State *);
257 static void zone_destroy(void *);
259 static int resource_create(lua_State *);
260 static int resource_getfield(lua_State *);
261 static int resource_setfield(lua_State *);
262 static void resource_destroy(void *);
264 static int rtgroup_create(lua_State *);
265 static int rtgroup_getfield(lua_State *);
266 static int rtgroup_setfield(lua_State *);
267 static int rtgroup_tostring(lua_State *);
268 static void rtgroup_destroy(void *);
270 static bool rtgroup_accept(struct userdata *, mir_rtgroup *, mir_node *);
271 static int rtgroup_compare(struct userdata *, mir_rtgroup *,
272 mir_node *, mir_node *);
274 static bool accept_bridge(lua_State *, void *, const char *,
275 mrp_funcbridge_value_t *, char *,
276 mrp_funcbridge_value_t *);
277 static bool compare_bridge(lua_State *, void *, const char *,
278 mrp_funcbridge_value_t *, char *,
279 mrp_funcbridge_value_t *);
280 static bool change_bridge(lua_State *, void *, const char *,
281 mrp_funcbridge_value_t *, char *,
282 mrp_funcbridge_value_t *);
284 static int apclass_create(lua_State *);
285 static int apclass_getfield(lua_State *);
286 static int apclass_setfield(lua_State *);
287 static int apclass_tostring(lua_State *);
288 static void apclass_destroy(void *);
290 static route_t *route_check(lua_State *, int);
291 static int route_push(lua_State *, route_t *);
292 static void route_destroy(route_t *);
294 static int vollim_create(lua_State *);
295 static int vollim_getfield(lua_State *);
296 static int vollim_setfield(lua_State *);
297 static int vollim_tostring(lua_State *);
298 static void vollim_destroy(void *);
300 static double vollim_calculate(struct userdata *, int, mir_node *, uint32_t, void *);
301 static bool calculate_bridge(lua_State *, void *, const char *,
302 mrp_funcbridge_value_t *, char *,
303 mrp_funcbridge_value_t *);
305 static limit_data_t *limit_data_check(lua_State *, int);
308 static int limit_data_push(lua_State *, limit_data_t *);
311 static void limit_data_destroy(limit_data_t *);
313 static intarray_t *intarray_check(lua_State *, int, int, int);
314 static int intarray_push(lua_State *, intarray_t *);
315 static void intarray_destroy(intarray_t *);
317 static resource_name_t *resource_names_check(lua_State *, int);
318 static void resource_names_destroy(resource_name_t *);
320 static attribute_t *attributes_check(lua_State *, int);
321 static void attributes_destroy(attribute_t *);
323 static map_t *map_check(lua_State *, int);
324 static int map_push(lua_State *, map_t *);
325 static void map_destroy(map_t *);
327 static field_t field_check(lua_State *, int, const char **);
328 static field_t field_name_to_type(const char *, size_t);
329 static int make_id(char *buf, size_t len, const char *fmt, ...);
331 static void setup_murphy_interface(struct userdata *);
332 static char *comma_separated_list(mrp_lua_strarray_t *, char *, int);
334 static bool define_constants(lua_State *);
335 static bool register_methods(lua_State *);
337 static void *alloc(void *, void *, size_t, size_t);
338 static int panic(lua_State *);
341 MRP_LUA_METHOD_LIST_TABLE (
342 import_methods, /* methodlist name */
343 MRP_LUA_METHOD_CONSTRUCTOR (import_create)
344 MRP_LUA_METHOD (link, import_link )
347 MRP_LUA_METHOD_LIST_TABLE (
348 node_methods, /* methodlist name */
349 MRP_LUA_METHOD_CONSTRUCTOR (node_create)
353 MRP_LUA_METHOD_LIST_TABLE (
354 import_overrides, /* methodlist_name */
355 MRP_LUA_OVERRIDE_CALL (import_create)
356 MRP_LUA_OVERRIDE_GETFIELD (import_getfield)
357 MRP_LUA_OVERRIDE_SETFIELD (import_setfield)
358 MRP_LUA_OVERRIDE_STRINGIFY (import_tostring)
361 MRP_LUA_METHOD_LIST_TABLE (
362 array_overrides, /* methodlist_name */
363 MRP_LUA_OVERRIDE_GETFIELD (array_getfield)
364 MRP_LUA_OVERRIDE_SETFIELD (array_setfield)
365 MRP_LUA_OVERRIDE_GETLENGTH (array_getlength)
368 MRP_LUA_METHOD_LIST_TABLE (
369 node_overrides, /* methodlist name */
370 MRP_LUA_OVERRIDE_CALL (node_create)
371 MRP_LUA_OVERRIDE_GETFIELD (node_getfield)
372 MRP_LUA_OVERRIDE_SETFIELD (node_setfield)
373 MRP_LUA_OVERRIDE_STRINGIFY (node_tostring)
378 mdb, /* class name */
379 import, /* constructor name */
380 scripting_import, /* userdata type */
381 import_destroy, /* userdata destructor */
382 import_methods, /* class methods */
383 import_overrides /* override methods */
387 node, /* class name */
388 instance, /* constructor name */
389 scripting_node, /* userdata type */
390 node_destroy, /* userdata destructor */
391 node_methods, /* class methods */
392 node_overrides /* override methods */
395 MRP_LUA_CLASS_DEF_SIMPLE (
396 zone, /* class name */
397 scripting_zone, /* userdata type */
398 zone_destroy, /* userdata destructor */
399 MRP_LUA_METHOD_LIST ( /* methods */
400 MRP_LUA_METHOD_CONSTRUCTOR (zone_create)
402 MRP_LUA_METHOD_LIST ( /* overrides */
403 MRP_LUA_OVERRIDE_CALL (zone_create)
404 MRP_LUA_OVERRIDE_GETFIELD (zone_getfield)
405 MRP_LUA_OVERRIDE_SETFIELD (zone_setfield)
409 MRP_LUA_CLASS_DEF_SIMPLE (
410 audio_resource, /* class name */
411 scripting_resource, /* userdata type */
412 resource_destroy, /* userdata destructor */
413 MRP_LUA_METHOD_LIST ( /* methods */
414 MRP_LUA_METHOD_CONSTRUCTOR (resource_create)
416 MRP_LUA_METHOD_LIST ( /* overrides */
417 MRP_LUA_OVERRIDE_CALL (resource_create)
418 MRP_LUA_OVERRIDE_GETFIELD (resource_getfield)
419 MRP_LUA_OVERRIDE_SETFIELD (resource_setfield)
423 MRP_LUA_CLASS_DEF_SIMPLE (
424 routing_group, /* class name */
425 scripting_rtgroup, /* userdata type */
426 rtgroup_destroy, /* userdata destructor */
427 MRP_LUA_METHOD_LIST ( /* methods */
428 MRP_LUA_METHOD_CONSTRUCTOR (rtgroup_create)
430 MRP_LUA_METHOD_LIST ( /* overrides */
431 MRP_LUA_OVERRIDE_CALL (rtgroup_create)
432 MRP_LUA_OVERRIDE_GETFIELD (rtgroup_getfield)
433 MRP_LUA_OVERRIDE_SETFIELD (rtgroup_setfield)
434 MRP_LUA_OVERRIDE_STRINGIFY (rtgroup_tostring)
438 MRP_LUA_CLASS_DEF_SIMPLE (
439 application_class, /* class name */
440 scripting_apclass, /* userdata type */
441 apclass_destroy, /* userdata destructor */
442 MRP_LUA_METHOD_LIST ( /* methods */
443 MRP_LUA_METHOD_CONSTRUCTOR (apclass_create)
445 MRP_LUA_METHOD_LIST ( /* overrides */
446 MRP_LUA_OVERRIDE_CALL (apclass_create)
447 MRP_LUA_OVERRIDE_GETFIELD (apclass_getfield)
448 MRP_LUA_OVERRIDE_SETFIELD (apclass_setfield)
449 MRP_LUA_OVERRIDE_STRINGIFY (apclass_tostring)
453 MRP_LUA_CLASS_DEF_SIMPLE (
454 volume_limit, /* class name */
455 scripting_vollim, /* userdata type */
456 vollim_destroy, /* userdata destructor */
457 MRP_LUA_METHOD_LIST ( /* methods */
458 MRP_LUA_METHOD_CONSTRUCTOR (vollim_create)
460 MRP_LUA_METHOD_LIST ( /* overrides */
461 MRP_LUA_OVERRIDE_CALL (vollim_create)
462 MRP_LUA_OVERRIDE_GETFIELD (vollim_getfield)
463 MRP_LUA_OVERRIDE_SETFIELD (vollim_setfield)
464 MRP_LUA_OVERRIDE_STRINGIFY (vollim_tostring)
469 pa_scripting *pa_scripting_init(struct userdata *u)
471 pa_scripting *scripting;
476 scripting = pa_xnew0(pa_scripting, 1);
478 if (!(L = lua_newstate(alloc, u)))
479 pa_log("failed to initialize Lua");
481 lua_atpanic(L, &panic);
484 mrp_create_funcbridge_class(L);
485 mrp_lua_create_object_class(L, IMPORT_CLASS);
486 mrp_lua_create_object_class(L, NODE_CLASS);
487 mrp_lua_create_object_class(L, ZONE_CLASS);
488 mrp_lua_create_object_class(L, RESOURCE_CLASS);
489 mrp_lua_create_object_class(L, RTGROUP_CLASS);
490 mrp_lua_create_object_class(L, APPLICATION_CLASS);
491 mrp_lua_create_object_class(L, VOLLIM_CLASS);
493 array_class_create(L);
498 lua_pushlightuserdata(L, u);
499 lua_setglobal(L, USERDATA);
502 scripting->configured = false;
508 void pa_scripting_done(struct userdata *u)
510 pa_scripting *scripting;
512 if (u && (scripting = u->scripting)) {
518 bool pa_scripting_dofile(struct userdata *u, const char *file)
520 pa_scripting *scripting;
527 pa_assert_se((scripting = u->scripting));
528 pa_assert_se((L = scripting->L));
530 if (luaL_loadfile(L, file) || lua_pcall(L, 0, 0, 0)) {
532 pa_log("%s", lua_tostring(L, -1));
537 scripting->configured = true;
538 setup_murphy_interface(u);
539 pa_zoneset_update_module_property(u);
545 static int import_create(lua_State *L)
547 struct userdata *u = NULL;
548 pa_scripting *scripting;
551 scripting_import *imp;
552 const char *table = NULL;
553 mrp_lua_strarray_t *columns = NULL;
554 const char *condition = NULL;
556 mrp_funcbridge_t *update = NULL;
567 lua_getglobal(L, USERDATA);
568 if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
569 luaL_error(L, "missing or invalid global '" USERDATA "'");
571 pa_assert_se((scripting = u->scripting));
573 MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
575 switch (field_name_to_type(fldnam, fldnamlen)) {
576 case TABLE: table = luaL_checkstring(L, -1); break;
577 case COLUMNS: columns = mrp_lua_check_strarray(L, -1); break;
578 case CONDITION: condition = luaL_checkstring(L, -1); break;
579 case MAXROW: maxrow = luaL_checkint(L, -1); break;
580 case UPDATE: update = mrp_funcbridge_create_luafunc(L, -1); break;
581 default: luaL_error(L, "bad field '%s'", fldnam); break;
584 } /* MRP_LUA_FOREACH_FIELD */
589 luaL_error(L, "missing table field");
591 luaL_error(L, "missing columns field");
592 if (maxrow < 1 || maxrow >= MQI_QUERY_RESULT_MAX)
593 luaL_error(L, "missing or invalid maxrow field");
595 luaL_error(L, "missing update function");
597 maxcol = (int)columns->nstring;
599 if (maxcol >= MQI_COLUMN_MAX)
600 luaL_error(L, "too many columns (max %d allowed)", MQI_COLUMN_MAX);
602 if (scripting->configured)
603 luaL_error(L, "refuse to import '%s' after configuration phase",table);
605 imp = (scripting_import *)mrp_lua_create_object(L, IMPORT_CLASS, table,0);
608 imp->table = pa_xstrdup(table);
609 imp->columns = columns;
610 imp->condition = condition;
611 imp->values = array_create(L, maxrow, NULL);
612 imp->update = update;
614 for (i = 0, rows = imp->values->value.array; i < maxrow; i++) {
615 cols = (rows[i] = array_create(L, (int)maxcol, columns))->value.array;
616 lua_rawseti(L, -3, i+1); /* we add this to the import */
617 for (j = 0; j < maxcol; j++)
618 cols[j] = pa_xnew0(pa_value, 1);
621 lua_rawseti(L, -2, MQI_QUERY_RESULT_MAX);
626 static int import_getfield(lua_State *L)
628 scripting_import *imp;
635 if (!(imp = (scripting_import *)mrp_lua_check_object(L, IMPORT_CLASS, 1)))
638 pa_assert_se((values = imp->values));
640 if (lua_type(L, 2) == LUA_TNUMBER) {
641 colidx = lua_tointeger(L, 2);
643 if (colidx < 1 || colidx > -values->type)
646 lua_rawgeti(L, 1, colidx);
649 fld = field_check(L, 2, NULL);
653 case TABLE: lua_pushstring(L, imp->table); break;
654 case COLUMNS: mrp_lua_push_strarray(L, imp->columns); break;
655 case CONDITION: lua_pushstring(L, imp->condition); break;
656 case MAXROW: lua_pushinteger(L, -imp->values->type); break;
657 default: lua_pushnil(L); break;
665 static int import_setfield(lua_State *L)
671 f = luaL_checkstring(L, 2);
672 luaL_error(L, "attempt to set '%s' field of read-only mdb.import", f);
677 static int import_tostring(lua_State *L)
679 scripting_import *imp;
683 imp = (scripting_import *)mrp_lua_check_object(L, IMPORT_CLASS, 1);
685 lua_pushstring(L, imp->table);
690 static void import_destroy(void *data)
692 scripting_import *imp = (scripting_import *)data;
696 pa_xfree((void *)imp->table);
697 mrp_lua_free_strarray(imp->columns);
698 pa_xfree((void *)imp->condition);
703 static int import_link(lua_State *L)
705 scripting_import *imp;
706 mrp_lua_strarray_t *columns;
716 imp = (scripting_import *)mrp_lua_check_object(L, IMPORT_CLASS, 1);
717 rowidx = luaL_checkint(L, 2) - 1;
718 colnam = luaL_checkstring(L, 3);
721 pa_assert_se((columns = imp->columns));
725 if (rowidx >= 0 && rowidx < -imp->values->type) {
726 for (colidx = 0; colidx < columns->nstring; colidx++) {
727 if (!strcmp(colnam, columns->strings[colidx])) {
728 pa_assert_se((values = imp->values));
729 pa_assert_se((row = values->value.array[rowidx]));
730 pa_assert(colidx < (size_t)-row->type);
731 pa_assert_se((col = row->value.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->value.array));
794 maxrow = -ptval->type;
795 maxcol = (int)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->value.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->value.string);
818 pcval->type = pa_value_string;
819 pcval->value.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->value.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->value.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->value.floating = mcol->dbl;
837 if (pcval->type == pa_value_string)
838 pa_xfree((void *)pcval->value.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 *, (size_t)(dimension + 1));
915 value = lua_newuserdata(L, sizeof(pa_value));
916 value->type = -dimension;
917 value->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->value.array[dimension])) {
955 pa_assert(dimension == (int)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->value.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->value.string); break;
979 case pa_value_integer: lua_pushinteger(L, value->value.integer); break;
980 case pa_value_unsignd: lua_pushinteger(L, (int)(value->value.unsignd)); break;
981 case pa_value_floating: lua_pushnumber(L, value->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->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, (int)(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)
1258 scripting_resource *res;
1259 resource_name_t *name = NULL;
1260 attribute_t *attributes = NULL;
1265 lua_getglobal(L, USERDATA);
1266 if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
1267 luaL_error(L, "missing or invalid global '" USERDATA "'");
1271 MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
1273 switch (field_name_to_type(fldnam, fldnamlen)) {
1274 case NAME: name = resource_names_check(L, -1); break;
1275 case ATTRIBUTES: attributes = attributes_check(L, -1); break;
1276 default: luaL_error(L, "bad field '%s'", fldnam); break;
1279 } /* MRP_LUA_FOREACH_FIELD */
1282 luaL_error(L, "missing or invalid name field");
1284 pa_murphyif_add_audio_resource(u, mir_input, name->playback);
1285 pa_murphyif_add_audio_resource(u, mir_output, name->recording);
1288 for (attr = attributes; attr->prop && attr->def.name; attr++) {
1289 switch (attr->def.type) {
1291 pa_murphyif_add_audio_attribute(u, attr->prop,
1294 attr->def.value.string);
1297 pa_murphyif_add_audio_attribute(u, attr->prop,
1300 attr->def.value.integer);
1303 pa_murphyif_add_audio_attribute(u, attr->prop,
1306 attr->def.value.unsignd);
1309 pa_murphyif_add_audio_attribute(u, attr->prop,
1312 attr->def.value.floating);
1315 luaL_error(L, "invalid audio resource attribute '%s'",
1322 res = (scripting_resource *)mrp_lua_create_object(L, RTGROUP_CLASS,
1327 res->attributes = attributes;
1332 static int resource_getfield(lua_State *L)
1338 /* fld = field_check(L, 2, NULL);*/
1341 if (!mrp_lua_check_object(L,RESOURCE_CLASS,1))
1346 case NAME: lua_pushstring(L, rtg->name); break;
1347 case ATTRIBUTES: lua_pushinteger(L, rtgs->type); break;
1348 default: lua_pushnil(L); break;
1358 static int resource_setfield(lua_State *L)
1364 f = luaL_checkstring(L, 2);
1365 luaL_error(L, "attempt to set '%s' field of read-only resource_class", f);
1370 static void resource_destroy(void *data)
1372 scripting_resource *res = (scripting_resource *)data;
1376 resource_names_destroy(res->name);
1377 attributes_destroy(res->attributes);
1380 res->attributes = NULL;
1382 MRP_LUA_LEAVE_NOARG;
1386 static int rtgroup_create(lua_State *L)
1392 scripting_rtgroup *rtgs;
1393 const char *name = NULL;
1394 mir_direction type = 0;
1395 mrp_funcbridge_t *accept = NULL;
1396 mrp_funcbridge_t *compare = NULL;
1401 lua_getglobal(L, USERDATA);
1402 if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
1403 luaL_error(L, "missing or invalid global '" USERDATA "'");
1407 MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
1409 switch (field_name_to_type(fldnam, fldnamlen)) {
1410 case NAME: name = luaL_checkstring(L, -1); break;
1411 case NODE_TYPE: type = luaL_checkint(L, -1); break;
1412 case ACCEPT: accept = mrp_funcbridge_create_luafunc(L, -1); break;
1413 case COMPARE: compare = mrp_funcbridge_create_luafunc(L, -1); break;
1414 default: luaL_error(L, "bad field '%s'", fldnam); break;
1417 } /* MRP_LUA_FOREACH_FIELD */
1420 luaL_error(L, "missing name field");
1421 if (type != mir_input && type != mir_output)
1422 luaL_error(L, "missing or invalid node_type");
1424 luaL_error(L, "missing or invalid accept field");
1426 luaL_error(L, "missing or invalid compare field");
1428 make_id(id,sizeof(id), "%s_%sput", name, (type == mir_input) ? "in":"out");
1430 rtgs = (scripting_rtgroup *)mrp_lua_create_object(L, RTGROUP_CLASS, id,0);
1432 rtg = mir_router_create_rtgroup(u, type, pa_xstrdup(name),
1433 rtgroup_accept, rtgroup_compare);
1435 luaL_error(L, "failed to create routing group '%s'", id);
1437 rtg->scripting = rtgs;
1442 rtgs->accept = accept;
1443 rtgs->compare = compare;
1448 static int rtgroup_getfield(lua_State *L)
1450 scripting_rtgroup *rtgs;
1456 fld = field_check(L, 2, NULL);
1459 if (!(rtgs = (scripting_rtgroup *)mrp_lua_check_object(L,RTGROUP_CLASS,1)))
1462 pa_assert_se((rtg = rtgs->rtg));
1465 case NAME: lua_pushstring(L, rtg->name); break;
1466 case NODE_TYPE: lua_pushinteger(L, rtgs->type); break;
1467 default: lua_pushnil(L); break;
1474 static int rtgroup_setfield(lua_State *L)
1480 f = luaL_checkstring(L, 2);
1481 luaL_error(L, "attempt to set '%s' field of read-only routing_group", f);
1486 static int rtgroup_tostring(lua_State *L)
1488 scripting_rtgroup *rtgs;
1493 rtgs = (scripting_rtgroup *)mrp_lua_check_object(L, RTGROUP_CLASS, 1);
1494 pa_assert_se((rtg = rtgs->rtg));
1496 lua_pushstring(L, rtg->name);
1501 static void rtgroup_destroy(void *data)
1503 scripting_rtgroup *rtgs = (scripting_rtgroup *)data;
1508 pa_assert_se((rtg = rtgs->rtg));
1509 pa_assert(rtgs == rtg->scripting);
1511 rtg->scripting = NULL;
1513 MRP_LUA_LEAVE_NOARG;
1517 static bool rtgroup_accept(struct userdata *u,
1521 pa_scripting *scripting;
1523 scripting_rtgroup *rtgs;
1524 mrp_funcbridge_value_t args[2];
1526 mrp_funcbridge_value_t rv;
1530 pa_assert_se((scripting = u->scripting));
1531 pa_assert_se((L = scripting->L));
1533 pa_assert_se((rtgs = rtg->scripting));
1534 pa_assert(u == rtgs->userdata);
1535 pa_assert(rtgs->accept);
1540 if ((rtgs = rtg->scripting) && node->scripting) {
1542 args[0].pointer = rtgs;
1543 args[1].pointer = node->scripting;
1545 if (!mrp_funcbridge_call_from_c(L, rtgs->accept, "oo",args, &rt,&rv)) {
1546 if (rt != MRP_FUNCBRIDGE_STRING)
1547 pa_log("call to accept function failed");
1549 pa_log("call to accept function failed: %s", rv.string);
1550 mrp_free((void *)rv.string);
1554 if (rt != MRP_FUNCBRIDGE_BOOLEAN)
1555 pa_log("accept function returned invalid type");
1557 accept = rv.boolean;
1564 static int rtgroup_compare(struct userdata *u,
1569 pa_scripting *scripting;
1571 scripting_rtgroup *rtgs;
1572 mrp_funcbridge_value_t args[3];
1574 mrp_funcbridge_value_t rv;
1578 pa_assert_se((scripting = u->scripting));
1579 pa_assert_se((L = scripting->L));
1581 pa_assert_se((rtgs = rtg->scripting));
1582 pa_assert(u == rtgs->userdata);
1583 pa_assert(rtgs->compare);
1589 if ((rtgs = rtg->scripting) && node1->scripting && node2->scripting) {
1591 args[0].pointer = rtgs;
1592 args[1].pointer = node1->scripting;
1593 args[2].pointer = node2->scripting;
1595 if (!mrp_funcbridge_call_from_c(L, rtgs->compare, "ooo",args, &rt,&rv))
1596 pa_log("failed to call compare function");
1598 if (rt != MRP_FUNCBRIDGE_FLOATING)
1599 pa_log("compare function returned invalid type");
1601 result = (int)(rv.floating);
1609 static bool accept_bridge(lua_State *L, void *data,
1610 const char *signature, mrp_funcbridge_value_t *args,
1611 char *ret_type, mrp_funcbridge_value_t *ret_val)
1613 mir_rtgroup_accept_t accept;
1614 scripting_rtgroup *rtgs;
1623 pa_assert(signature);
1625 pa_assert(ret_type);
1628 pa_assert((accept = (mir_rtgroup_accept_t)data));
1630 if (strcmp(signature, "oo"))
1633 pa_assert_se((rtgs = args[0].pointer));
1634 pa_assert_se((u = rtgs->userdata));
1635 pa_assert_se((ns = args[1].pointer));
1637 if (!(rtg = rtgs->rtg) || !(node = ns->node))
1641 *ret_type = MRP_FUNCBRIDGE_BOOLEAN;
1642 ret_val->boolean = accept(u, rtg, node);
1650 static bool compare_bridge(lua_State *L, void *data,
1651 const char *signature, mrp_funcbridge_value_t *args,
1652 char *ret_type, mrp_funcbridge_value_t *ret_val)
1654 mir_rtgroup_compare_t compare;
1655 scripting_rtgroup *rtgs;
1656 scripting_node *ns1, *ns2;
1659 mir_node *node1, *node2;
1664 pa_assert(signature);
1666 pa_assert(ret_type);
1669 pa_assert_se((compare = (mir_rtgroup_compare_t)data));
1671 if (strcmp(signature, "ooo"))
1674 pa_assert_se((rtgs = args[0].pointer));
1675 pa_assert_se((u = rtgs->userdata));
1676 pa_assert_se((ns1 = args[1].pointer));
1677 pa_assert_se((ns2 = args[2].pointer));
1680 if (!(rtg = rtgs->rtg) || !(node1 = ns1->node) || !(node2 = ns2->node))
1684 *ret_type = MRP_FUNCBRIDGE_FLOATING;
1685 ret_val->floating = compare(u, rtg, node1, node2);
1693 static bool change_bridge(lua_State *L, void *data,
1694 const char *signature, mrp_funcbridge_value_t *args,
1695 char *ret_type, mrp_funcbridge_value_t *ret_val)
1697 mir_change_value_t change;
1698 scripting_import *imp;
1701 const char *s = "default";
1705 pa_assert(signature);
1707 pa_assert(ret_type);
1710 pa_assert_se((change = (mir_change_value_t)data));
1712 if (strcmp(signature, "o"))
1715 pa_assert_se((imp = args[0].pointer));
1716 pa_assert_se((u = imp->userdata));
1718 /* FIXME: is this how it is supposed to be done?! */
1720 if (imp->values && imp->values->value.array && imp->values->value.array[0] &&
1721 imp->values->value.array[0]->value.array &&
1722 imp->values->value.array[0]->value.array[0] &&
1723 imp->values->value.array[0]->value.array[0]->type == pa_value_string)
1724 pa_assert_se((s = imp->values->value.array[0]->value.array[0]->value.string));
1727 *ret_type = MRP_FUNCBRIDGE_NO_DATA;
1728 memset(ret_val, 0, sizeof(mrp_funcbridge_value_t));
1736 static int apclass_create(lua_State *L)
1741 scripting_apclass *ac;
1743 const char *class = NULL;
1744 mir_node_type type = -1;
1746 route_t *route = NULL;
1747 map_t *roles = NULL;
1748 map_t *binaries = NULL;
1749 pa_nodeset_resdef *resdef;
1757 lua_getglobal(L, USERDATA);
1758 if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
1759 luaL_error(L, "missing or invalid global '" USERDATA "'");
1763 MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
1765 switch (field_name_to_type(fldnam, fldnamlen)) {
1766 case CLASS: class = luaL_checkstring(L, -1); break;
1767 case NODE_TYPE: type = luaL_checkint(L, -1); break;
1768 case PRIORITY: priority = luaL_checkint(L, -1); break;
1769 case ROUTE: route = route_check(L, -1); break;
1770 case ROLES: roles = map_check(L, -1); break;
1771 case BINARIES: binaries = map_check(L, -1); break;
1772 default: luaL_error(L, "bad field '%s'", fldnam); break;
1775 } /* MRP_LUA_FOREACH_FIELD */
1777 if (type < mir_application_class_begin ||
1778 type >= mir_application_class_end )
1779 luaL_error(L, "missing or invalid node_type %d", type);
1781 luaL_error(L, "missing or invalid priority field");
1783 luaL_error(L, "missing or invalid route field");
1784 if (!roles && !binaries)
1785 luaL_error(L, "missing roles or binaries");
1787 make_id(name, sizeof(name), "%s", mir_node_type_str(type));
1789 mir_router_assign_class_priority(u, type, priority);
1794 for (i = 0; i < MRP_ZONE_MAX; i++) {
1795 if ((n = route->input[i]))
1796 ir &= mir_router_assign_class_to_rtgroup(u,type,i,mir_input,n);
1800 if (route->output) {
1801 for (i = 0; i < MRP_ZONE_MAX; i++) {
1802 if ((n = route->output[i]))
1803 or &= mir_router_assign_class_to_rtgroup(u,type,i,mir_output,n);
1807 ac = (scripting_apclass *)mrp_lua_create_object(L, APPLICATION_CLASS,
1810 if (!ir || !or || !ac)
1811 luaL_error(L, "failed to create application class '%s'", name);
1814 ac->name = pa_xstrdup(name);
1815 ac->class = class ? pa_xstrdup(class) : NULL;
1817 ac->priority = priority;
1820 ac->binaries = binaries;
1823 if (pa_nodeset_add_class(u, type, class)) {
1824 luaL_error(L, "node type '%s' is defined multiple times",
1825 mir_node_type_str(type));
1830 for (r = roles; r->name; r++) {
1831 resdef = r->needres ? &r->resource : NULL;
1833 if (r->role && strcmp(r->role, r->name)) {
1834 luaL_error(L, "conflicting roles in role definition '%s' (%s)",
1838 if (pa_nodeset_add_role(u, r->name, type, resdef)) {
1839 luaL_error(L, "role '%s' is added to mutiple application "
1840 "classes", r->name);
1846 for (b = binaries; b->name; b++) {
1847 resdef = b->needres ? &b->resource : NULL;
1849 if (pa_nodeset_add_binary(u, b->name, type, b->role, resdef)) {
1850 luaL_error(L, "binary '%s' is added to multiple application "
1851 "classes", b->name);
1859 static int apclass_getfield(lua_State *L)
1861 scripting_apclass *ac;
1866 fld = field_check(L, 2, NULL);
1869 if (!(ac=(scripting_apclass *)mrp_lua_check_object(L,APPLICATION_CLASS,1)))
1873 case NAME: lua_pushstring(L, ac->name); break;
1874 case NODE_TYPE: lua_pushinteger(L, ac->type); break;
1875 case PRIORITY: lua_pushinteger(L, ac->priority); break;
1876 case ROUTE: route_push(L, ac->route); break;
1877 case ROLES: map_push(L, ac->roles); break;
1878 case BINARIES: map_push(L, ac->binaries); break;
1879 default: lua_pushnil(L); break;
1886 static int apclass_setfield(lua_State *L)
1892 f = luaL_checkstring(L, 2);
1893 luaL_error(L,"attempt to set '%s' field of read-only application class",f);
1898 static int apclass_tostring(lua_State *L)
1900 scripting_apclass *ac;
1904 ac = (scripting_apclass *)mrp_lua_check_object(L, APPLICATION_CLASS, 1);
1906 lua_pushstring(L, ac->name);
1911 static void apclass_destroy(void *data)
1913 scripting_apclass *ac = (scripting_apclass *)data;
1920 pa_assert_se((u = ac->userdata));
1922 route_destroy(ac->route);
1925 pa_xfree((void *)ac->name);
1928 pa_nodeset_delete_class(u, ac->type);
1929 pa_xfree((void *)ac->class);
1933 for (r = ac->roles; r->name; r++)
1934 pa_nodeset_delete_role(u, r->name);
1936 map_destroy(ac->roles);
1941 for (b = ac->binaries; b->name; b++)
1942 pa_nodeset_delete_binary(u, b->name);
1944 map_destroy(ac->binaries);
1945 ac->binaries = NULL;
1948 MRP_LUA_LEAVE_NOARG;
1951 static const char **route_definition_check(lua_State *L, int idx)
1954 const char *zonenam;
1955 scripting_zone *zone;
1956 scripting_rtgroup *rtgs;
1962 idx = (idx < 0) ? lua_gettop(L) + idx + 1 : idx;
1964 luaL_checktype(L, idx, LUA_TTABLE);
1966 defs = pa_xnew0(const char *, MRP_ZONE_MAX);
1969 MRP_LUA_FOREACH_FIELD(L, idx, zonenam, zonelen) {
1971 luaL_error(L, "invalid route definition");
1973 mrp_lua_find_object(L, ZONE_CLASS, zonenam);
1975 if (!(zone = mrp_lua_check_object(L, NULL, -1)))
1976 luaL_error(L, "can't find zone '%s'", zonenam);
1980 if (zone->index >= MRP_ZONE_MAX)
1981 luaL_error(L, "Internal error: zone index overflow");
1983 switch (lua_type(L, -1)) {
1985 rtgnam = lua_tostring(L, -1);
1988 rtgs = (scripting_rtgroup*)mrp_lua_check_object(L,RTGROUP_CLASS,-1);
1989 if (!rtgs || !(rtg = rtgs->rtg))
2000 luaL_error(L, "missing or invalid routing group");
2002 defs[zone->index] = pa_xstrdup(rtgnam);
2007 luaL_error(L, "empty definition");
2012 static int route_definition_push(lua_State *L, const char **defs)
2016 lua_createtable(L, MRP_ZONE_MAX, 0);
2018 for (i = 0; i < MRP_ZONE_MAX; i++) {
2026 static void route_definition_free(const char **defs)
2031 for (i = 0; i < MRP_ZONE_MAX; i++)
2032 pa_xfree((void *)defs[i]);
2033 pa_xfree((void *)defs);
2038 static route_t *route_check(lua_State *L, int idx)
2043 const char **input = NULL;
2044 const char **output = NULL;
2046 idx = (idx < 0) ? lua_gettop(L) + idx + 1 : idx;
2048 luaL_checktype(L, idx, LUA_TTABLE);
2050 MRP_LUA_FOREACH_FIELD(L, idx, fldnam, fldnamlen) {
2051 switch (field_name_to_type(fldnam, fldnamlen)) {
2052 case INPUT: input = route_definition_check(L, -1); break;
2053 case OUTPUT: output = route_definition_check(L, -1); break;
2054 default: luaL_error(L, "invalid field '%s'", fldnam); break;
2056 } /* MRP_LUA_FOREACH_FIELD */
2058 if (!input && !output)
2059 luaL_error(L, "neither input nor output routing group were specified");
2061 rt = pa_xmalloc(sizeof(route_t));
2063 rt->output = output;
2068 static int route_push(lua_State *L, route_t *rt)
2070 if (!rt || (!rt->input && !rt->output))
2073 lua_createtable(L, 0, 2);
2076 lua_pushstring(L, "input");
2077 route_definition_push(L, rt->input);
2078 lua_settable(L, -3);
2082 lua_pushstring(L, "output");
2083 route_definition_push(L, rt->output);
2084 lua_settable(L, -3);
2091 static void route_destroy(route_t *rt)
2094 pa_xfree((void *)rt->input);
2095 pa_xfree((void *)rt->output);
2096 pa_xfree((void *)rt);
2101 static int vollim_create(lua_State *L)
2103 static int min = mir_application_class_begin;
2104 static int max = mir_application_class_end;
2109 scripting_vollim *vlim;
2110 const char *name = NULL;
2111 vollim_type type = 0;
2112 limit_data_t *limit = NULL;
2113 mrp_funcbridge_t *calculate = NULL;
2114 intarray_t *classes = NULL;
2115 bool suppress = false;
2116 bool correct = false;
2120 uint32_t mask, clmask;
2125 lua_getglobal(L, USERDATA);
2126 if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
2127 luaL_error(L, "missing or invalid global '" USERDATA "'");
2131 MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
2133 switch (field_name_to_type(fldnam, fldnamlen)) {
2134 case NAME: name = luaL_checkstring(L, -1); break;
2135 case TYPE: type = luaL_checkint(L, -1); break;
2136 case NODE_TYPE: classes = intarray_check(L, -1, min, max); break;
2137 case LIMIT: limit = limit_data_check(L, -1); break;
2138 case CALCULATE: calculate = mrp_funcbridge_create_luafunc(L,-1); break;
2139 default: luaL_error(L, "bad field '%s'", fldnam); break;
2142 } /* MRP_LUA_FOREACH_FIELD */
2145 luaL_error(L, "missing name field");
2146 if (type != vollim_class && type != vollim_generic && type != vollim_maximum)
2147 luaL_error(L, "missing or invalid type");
2148 if ((type == vollim_class || type == vollim_maximum) && !classes)
2149 luaL_error(L, "missing or invalid node_type for class/maximum limit");
2150 if (type == vollim_generic && classes)
2151 luaL_error(L, "can't specify node_type for generic volume limit");
2153 luaL_error(L, "missing or invalid limit");
2154 if (type != vollim_maximum && !calculate)
2155 luaL_error(L, "missing calculate field");
2156 if (type != vollim_maximum) {
2157 if (calculate->type == MRP_C_FUNCTION) {
2158 if (strcmp(calculate->c.signature, "odod"))
2159 luaL_error(L,"invalid calculate field (mismatching signature)");
2160 if (calculate->c.data == mir_volume_suppress) {
2161 if (type != vollim_class)
2162 luaL_error(L, "attempt to make generic volume supression");
2164 arglgh = sizeof(mir_volume_suppress_arg);
2166 else if (calculate->c.data == mir_volume_correction) {
2167 if (type != vollim_generic) {
2168 luaL_error(L, "attempt to make class based volume"
2172 arglgh = sizeof(double *);
2175 luaL_error(L, "invalid builtin.method for calculate");
2182 arglgh = sizeof(mir_volume_suppress_arg);
2184 case vollim_generic:
2186 arglgh = sizeof(double *);
2194 make_id(id, sizeof(id), "%s", name);
2196 (VOLLIM_CLASS)->userdata_size = sizeof(scripting_vollim) + arglgh;
2197 vlim = (scripting_vollim *)mrp_lua_create_object(L, VOLLIM_CLASS, id,0);
2198 (VOLLIM_CLASS)->userdata_size = sizeof(scripting_vollim);
2201 vlim->name = pa_xstrdup(name);
2203 vlim->classes = classes;
2204 vlim->limit = limit;
2205 vlim->calculate = calculate;
2208 mir_volume_suppress_arg *args = (mir_volume_suppress_arg *)(void *)vlim->args;
2209 size_t size = sizeof(int) * classes->nint;
2210 size_t n = mir_application_class_end - mir_application_class_begin;
2212 for (i = 0, clmask = 0; i < (int)(classes->nint); i++) {
2213 class = classes->ints[i];
2215 if (class <= mir_application_class_begin ||
2216 class > mir_application_class_end )
2218 pa_log("invalid triggering class id %d", class);
2220 classes->nint = n = 0;
2224 mask = ((uint32_t)1) << (class - mir_application_class_begin);
2226 if (!(clmask & mask) && n > 0)
2232 args->attenuation = limit->value;
2233 args->trigger.nclass = classes->nint;
2234 args->trigger.classes = pa_xmalloc(size);
2235 args->trigger.clmask = clmask;
2237 memcpy(args->trigger.classes, classes->ints, size);
2239 if (n > classes->nint)
2240 classes->ints = pa_xrealloc(classes->ints, sizeof(int) * n);
2243 for (i = mir_application_class_begin, n = 0;
2244 i < mir_application_class_end;
2247 if (!(clmask & (((uint32_t)1) << (i-mir_application_class_begin))))
2248 classes->ints[n++] = i;
2252 /* *(double **)vlim->args = limit->value; */
2254 memcpy(vlim->args, &limit->value, sizeof(limit->value));
2258 case vollim_generic:
2259 mir_volume_add_generic_limit(u, vollim_calculate, vlim->args);
2262 for (i = 0; i < (int)(classes->nint); i++) {
2263 mir_volume_add_class_limit(u, classes->ints[i], vollim_calculate,
2267 case vollim_maximum:
2268 mir_volume_add_maximum_limit(u, *(vlim->limit->value),
2269 classes->nint, classes->ints);
2278 static int vollim_getfield(lua_State *L)
2280 scripting_vollim *vlim;
2285 fld = field_check(L, 2, NULL);
2288 if (!(vlim = (scripting_vollim *)mrp_lua_check_object(L, VOLLIM_CLASS, 1)))
2292 case NAME: lua_pushstring(L, vlim->name); break;
2293 case TYPE: lua_pushinteger(L, vlim->type); break;
2294 case NODE_TYPE: intarray_push(L, vlim->classes); break;
2295 case LIMIT: lua_pushnumber(L, *vlim->limit->value); break;
2296 default: lua_pushnil(L); break;
2303 static int vollim_setfield(lua_State *L)
2309 f = luaL_checkstring(L, 2);
2310 luaL_error(L, "attempt to set '%s' field of read-only volume_limit", f);
2315 static int vollim_tostring(lua_State *L)
2317 scripting_vollim *vlim;
2321 vlim = (scripting_vollim *)mrp_lua_check_object(L, VOLLIM_CLASS, 1);
2323 lua_pushstring(L, vlim->name);
2328 static void vollim_destroy(void *data)
2330 scripting_vollim *vlim = (scripting_vollim *)data;
2334 pa_xfree((void *)vlim->name);
2335 intarray_destroy(vlim->classes);
2336 limit_data_destroy(vlim->limit);
2338 MRP_LUA_LEAVE_NOARG;
2342 static double vollim_calculate(struct userdata *u, int class,
2343 mir_node *node, uint32_t mask, void *data)
2345 static int offset = ((scripting_vollim *)0)->args - (char *)0;
2347 pa_scripting *scripting;
2349 scripting_vollim *vlim;
2350 mrp_funcbridge_value_t args[4];
2352 mrp_funcbridge_value_t rv;
2356 pa_assert_se((scripting = u->scripting));
2357 pa_assert_se((L = scripting->L));
2358 pa_assert(!class || (class >= mir_application_class_begin &&
2359 class < mir_application_class_end) );
2362 vlim = (scripting_vollim *)(void*)((char *)data - offset);
2364 pa_assert(u == vlim->userdata);
2368 if (node->scripting) {
2370 args[0].pointer = vlim;
2371 args[1].integer = class;
2372 args[2].pointer = node->scripting;
2373 args[3].integer = (int32_t)mask;
2375 if (!mrp_funcbridge_call_from_c(L,vlim->calculate,"odod",args,&rt,&rv))
2376 pa_log("failed to call calculate function");
2378 if (rt != MRP_FUNCBRIDGE_FLOATING)
2379 pa_log("accept function returned invalid type");
2381 limit = rv.floating;
2388 static bool calculate_bridge(lua_State *L, void *data, const char *signature,
2389 mrp_funcbridge_value_t *args,
2390 char *ret_type, mrp_funcbridge_value_t *ret_val)
2392 mir_volume_func_t calculate;
2393 scripting_vollim *vlim;
2403 pa_assert(signature);
2405 pa_assert(ret_type);
2408 pa_assert_se((calculate = (mir_volume_func_t)data));
2410 if (strcmp(signature, "odod"))
2413 pa_assert_se((vlim = args[0].pointer));
2414 pa_assert_se((u = vlim->userdata));
2415 pa_assert_se((ns = args[2].pointer));
2417 class = args[1].integer;
2418 mask = (uint32_t)args[3].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, mask, vlim->args);
2436 static limit_data_t *limit_data_check(lua_State *L, int idx)
2438 static double nolimit = 0.0;
2440 limit_data_t *ld = NULL;
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->value.floating;
2465 ld = pa_xnew0(limit_data_t, 1);
2466 ld->mallocd = false;
2467 ld->value = &nolimit;
2475 static int limit_data_push(lua_State *L, limit_data_t *ld)
2478 lua_pushnumber(L, *ld->value);
2486 static void limit_data_destroy(limit_data_t *ld)
2490 pa_xfree(ld->value);
2496 static intarray_t *intarray_check(lua_State *L, int idx, int min, int max)
2504 idx = (idx < 0) ? lua_gettop(L) + idx + 1 : idx;
2506 luaL_checktype(L, idx, LUA_TTABLE);
2508 if ((len = luaL_getn(L, idx)) < 1)
2511 size = sizeof(intarray_t) + sizeof(int) * (size_t)len;
2512 arr = pa_xmalloc0(sizeof(intarray_t));
2514 arr->nint = (size_t)len;
2515 arr->ints = pa_xmalloc0(size);
2517 for (i = 0; i < len; i++) {
2518 lua_pushnumber(L, (int)(i+1));
2519 lua_gettable(L, idx);
2521 val = luaL_checkint(L, -1);
2525 if (val < min || val >= max)
2526 luaL_error(L, "array [%u]: out of range value (%d)", i, val);
2535 static int intarray_push(lua_State *L, intarray_t *arr)
2542 lua_createtable(L, (int)(arr->nint), 0);
2544 for (i = 0; i < arr->nint; i++) {
2545 lua_pushinteger(L, (int)(i+1));
2546 lua_pushinteger(L, arr->ints[i]);
2547 lua_settable(L, -3);
2554 static void intarray_destroy(intarray_t *arr)
2557 pa_xfree(arr->ints);
2562 static resource_name_t *resource_names_check(lua_State *L, int tbl)
2564 resource_name_t *name;
2569 tbl = (tbl < 0) ? lua_gettop(L) + tbl + 1 : tbl;
2571 luaL_checktype(L, tbl, LUA_TTABLE);
2573 name = pa_xnew0(resource_name_t, 1);
2575 MRP_LUA_FOREACH_FIELD(L, tbl, fldnam, fldnamlen) {
2576 value = luaL_checkstring(L, -1);
2578 if (!strcmp(fldnam, "recording"))
2579 name->recording = pa_xstrdup(value);
2580 else if (!strcmp(fldnam, "playback"))
2581 name->playback = pa_xstrdup(value);
2583 luaL_error(L, "invalid field '%s' in resource name definition",
2591 static void resource_names_destroy(resource_name_t *name)
2594 pa_xfree((void *)name->recording);
2595 pa_xfree((void *)name->playback);
2600 static attribute_t *attributes_check(lua_State *L, int tbl)
2605 attribute_t *attr, *attrs = NULL;
2607 mrp_attr_value_t *v;
2610 tbl = (tbl < 0) ? lua_gettop(L) + tbl + 1 : tbl;
2612 luaL_checktype(L, tbl, LUA_TTABLE);
2614 MRP_LUA_FOREACH_FIELD(L, tbl, fldnam, fldnamlen) {
2616 luaL_error(L, "invalid attribute definition");
2618 attrs = pa_xrealloc(attrs, sizeof(attribute_t) * (nattr + 2));
2619 memset(attrs + nattr, 0, sizeof(attribute_t) * 2);
2621 attr = attrs + nattr++;
2622 v = &attr->def.value;
2623 def = lua_gettop(L);
2625 attr->def.name = pa_xstrdup(fldnam);
2627 if ((len = luaL_getn(L, def)) != 3)
2628 luaL_error(L, "invalid attribute definition '%s'", fldnam);
2630 for (i = 0; i < len; i++) {
2631 lua_pushnumber(L, (int)(i+1));
2632 lua_gettable(L, def);
2635 case 0: attr->prop = pa_xstrdup(luaL_checkstring(L,-1)); break;
2636 case 1: attr->def.type = luaL_checkint(L,-1); break;
2638 switch (attr->def.type) {
2639 case mqi_string: v->string = luaL_checkstring(L,-1); break;
2640 case mqi_integer: v->integer = luaL_checkint(L,-1); break;
2641 case mqi_unsignd: v->integer = luaL_checkint(L,-1); break;
2642 case mqi_floating: v->floating = luaL_checknumber(L,-1); break;
2643 default: memset(v, 0, sizeof(*v)); break;
2651 luaL_error(L, "missing property name definition from '%s'",fldnam);
2652 if (attr->def.type != mqi_string && attr->def.type != mqi_integer &&
2653 attr->def.type != mqi_unsignd && attr->def.type != mqi_floating)
2655 luaL_error(L, "invalid attribute type %d for '%s'",
2656 attr->def.type, fldnam);
2658 if (attr->def.type == mqi_unsignd && attr->def.value.integer < 0) {
2659 luaL_error(L, "attempt to give negative value (%d) for field '%s'",
2660 attr->def.value.integer, fldnam);
2667 static void attributes_destroy(attribute_t *attrs)
2672 for (attr = attrs; attr->prop && attr->def.name; attr++) {
2673 pa_xfree((void *)attr->prop);
2674 pa_xfree((void *)attr->def.name);
2675 if (attr->def.type == mqi_string)
2676 pa_xfree((void *)attr->def.value.string);
2682 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+1; 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 = (uint32_t)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, (int)(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++) {
3027 c = (char)tolower(c);
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, (size_t)(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" ,"odod", calculate_bridge,mir_volume_suppress },
3228 {"volume_correct" ,"odod", 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