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;
135 pa_nodeset_resdef resource;
138 struct scripting_apclass {
139 struct userdata *userdata;
167 struct scripting_vollim {
168 struct userdata *userdata;
173 mrp_funcbridge_t *calculate;
186 mrp_funcbridge_cfunc_t func;
223 static int import_create(lua_State *);
224 static int import_getfield(lua_State *);
225 static int import_setfield(lua_State *);
226 static int import_tostring(lua_State *);
227 static void import_destroy(void *);
229 static int import_link(lua_State *);
231 static void import_data_changed(struct userdata *, const char *,
232 int, mrp_domctl_value_t **);
233 static bool update_bridge(lua_State *, void *, const char *,
234 mrp_funcbridge_value_t *, char *,
235 mrp_funcbridge_value_t *);
237 static void array_class_create(lua_State *);
238 static pa_value *array_create(lua_State *, int, mrp_lua_strarray_t *);
239 static int array_getfield(lua_State *);
240 static int array_setfield(lua_State *);
241 static int array_getlength(lua_State *);
244 static void array_destroy(void *);
247 static int node_create(lua_State *);
248 static int node_getfield(lua_State *);
249 static int node_setfield(lua_State *);
250 static int node_tostring(lua_State *);
251 static void node_destroy(void *);
253 static int zone_create(lua_State *);
254 static int zone_getfield(lua_State *);
255 static int zone_setfield(lua_State *);
256 static void zone_destroy(void *);
258 static int resource_create(lua_State *);
259 static int resource_getfield(lua_State *);
260 static int resource_setfield(lua_State *);
261 static void resource_destroy(void *);
263 static int rtgroup_create(lua_State *);
264 static int rtgroup_getfield(lua_State *);
265 static int rtgroup_setfield(lua_State *);
266 static int rtgroup_tostring(lua_State *);
267 static void rtgroup_destroy(void *);
269 static pa_bool_t rtgroup_accept(struct userdata *, mir_rtgroup *, mir_node *);
270 static int rtgroup_compare(struct userdata *, mir_rtgroup *,
271 mir_node *, mir_node *);
273 static bool accept_bridge(lua_State *, void *, const char *,
274 mrp_funcbridge_value_t *, char *,
275 mrp_funcbridge_value_t *);
276 static bool compare_bridge(lua_State *, void *, const char *,
277 mrp_funcbridge_value_t *, char *,
278 mrp_funcbridge_value_t *);
280 static int apclass_create(lua_State *);
281 static int apclass_getfield(lua_State *);
282 static int apclass_setfield(lua_State *);
283 static int apclass_tostring(lua_State *);
284 static void apclass_destroy(void *);
286 static route_t *route_check(lua_State *, int);
287 static int route_push(lua_State *, route_t *);
288 static void route_destroy(route_t *);
290 static int vollim_create(lua_State *);
291 static int vollim_getfield(lua_State *);
292 static int vollim_setfield(lua_State *);
293 static int vollim_tostring(lua_State *);
294 static void vollim_destroy(void *);
296 static double vollim_calculate(struct userdata *, int, mir_node *, void *);
297 static bool calculate_bridge(lua_State *, void *, const char *,
298 mrp_funcbridge_value_t *, char *,
299 mrp_funcbridge_value_t *);
301 static limit_data_t *limit_data_check(lua_State *, int);
304 static int limit_data_push(lua_State *, limit_data_t *);
307 static void limit_data_destroy(limit_data_t *);
309 static intarray_t *intarray_check(lua_State *, int, int, int);
310 static int intarray_push(lua_State *, intarray_t *);
311 static void intarray_destroy(intarray_t *);
313 static resource_name_t *resource_names_check(lua_State *, int);
314 static void resource_names_destroy(resource_name_t *);
316 static attribute_t *attributes_check(lua_State *, int);
317 static void attributes_destroy(attribute_t *);
319 static map_t *map_check(lua_State *, int);
320 static int map_push(lua_State *, map_t *);
321 static void map_destroy(map_t *);
323 static field_t field_check(lua_State *, int, const char **);
324 static field_t field_name_to_type(const char *, size_t);
325 static int make_id(char *buf, size_t len, const char *fmt, ...);
327 static void setup_murphy_interface(struct userdata *);
328 static char *comma_separated_list(mrp_lua_strarray_t *, char *, int);
330 static bool define_constants(lua_State *);
331 static bool register_methods(lua_State *);
333 static void *alloc(void *, void *, size_t, size_t);
334 static int panic(lua_State *);
337 MRP_LUA_METHOD_LIST_TABLE (
338 import_methods, /* methodlist name */
339 MRP_LUA_METHOD_CONSTRUCTOR (import_create)
340 MRP_LUA_METHOD (link, import_link )
343 MRP_LUA_METHOD_LIST_TABLE (
344 node_methods, /* methodlist name */
345 MRP_LUA_METHOD_CONSTRUCTOR (node_create)
349 MRP_LUA_METHOD_LIST_TABLE (
350 import_overrides, /* methodlist_name */
351 MRP_LUA_OVERRIDE_CALL (import_create)
352 MRP_LUA_OVERRIDE_GETFIELD (import_getfield)
353 MRP_LUA_OVERRIDE_SETFIELD (import_setfield)
354 MRP_LUA_OVERRIDE_STRINGIFY (import_tostring)
357 MRP_LUA_METHOD_LIST_TABLE (
358 array_overrides, /* methodlist_name */
359 MRP_LUA_OVERRIDE_GETFIELD (array_getfield)
360 MRP_LUA_OVERRIDE_SETFIELD (array_setfield)
361 MRP_LUA_OVERRIDE_GETLENGTH (array_getlength)
364 MRP_LUA_METHOD_LIST_TABLE (
365 node_overrides, /* methodlist name */
366 MRP_LUA_OVERRIDE_CALL (node_create)
367 MRP_LUA_OVERRIDE_GETFIELD (node_getfield)
368 MRP_LUA_OVERRIDE_SETFIELD (node_setfield)
369 MRP_LUA_OVERRIDE_STRINGIFY (node_tostring)
374 mdb, /* class name */
375 import, /* constructor name */
376 scripting_import, /* userdata type */
377 import_destroy, /* userdata destructor */
378 import_methods, /* class methods */
379 import_overrides /* override methods */
383 node, /* class name */
384 instance, /* constructor name */
385 scripting_node, /* userdata type */
386 node_destroy, /* userdata destructor */
387 node_methods, /* class methods */
388 node_overrides /* override methods */
391 MRP_LUA_CLASS_DEF_SIMPLE (
392 zone, /* class name */
393 scripting_zone, /* userdata type */
394 zone_destroy, /* userdata destructor */
395 MRP_LUA_METHOD_LIST ( /* methods */
396 MRP_LUA_METHOD_CONSTRUCTOR (zone_create)
398 MRP_LUA_METHOD_LIST ( /* overrides */
399 MRP_LUA_OVERRIDE_CALL (zone_create)
400 MRP_LUA_OVERRIDE_GETFIELD (zone_getfield)
401 MRP_LUA_OVERRIDE_SETFIELD (zone_setfield)
405 MRP_LUA_CLASS_DEF_SIMPLE (
406 audio_resource, /* class name */
407 scripting_resource, /* userdata type */
408 resource_destroy, /* userdata destructor */
409 MRP_LUA_METHOD_LIST ( /* methods */
410 MRP_LUA_METHOD_CONSTRUCTOR (resource_create)
412 MRP_LUA_METHOD_LIST ( /* overrides */
413 MRP_LUA_OVERRIDE_CALL (resource_create)
414 MRP_LUA_OVERRIDE_GETFIELD (resource_getfield)
415 MRP_LUA_OVERRIDE_SETFIELD (resource_setfield)
419 MRP_LUA_CLASS_DEF_SIMPLE (
420 routing_group, /* class name */
421 scripting_rtgroup, /* userdata type */
422 rtgroup_destroy, /* userdata destructor */
423 MRP_LUA_METHOD_LIST ( /* methods */
424 MRP_LUA_METHOD_CONSTRUCTOR (rtgroup_create)
426 MRP_LUA_METHOD_LIST ( /* overrides */
427 MRP_LUA_OVERRIDE_CALL (rtgroup_create)
428 MRP_LUA_OVERRIDE_GETFIELD (rtgroup_getfield)
429 MRP_LUA_OVERRIDE_SETFIELD (rtgroup_setfield)
430 MRP_LUA_OVERRIDE_STRINGIFY (rtgroup_tostring)
434 MRP_LUA_CLASS_DEF_SIMPLE (
435 application_class, /* class name */
436 scripting_apclass, /* userdata type */
437 apclass_destroy, /* userdata destructor */
438 MRP_LUA_METHOD_LIST ( /* methods */
439 MRP_LUA_METHOD_CONSTRUCTOR (apclass_create)
441 MRP_LUA_METHOD_LIST ( /* overrides */
442 MRP_LUA_OVERRIDE_CALL (apclass_create)
443 MRP_LUA_OVERRIDE_GETFIELD (apclass_getfield)
444 MRP_LUA_OVERRIDE_SETFIELD (apclass_setfield)
445 MRP_LUA_OVERRIDE_STRINGIFY (apclass_tostring)
449 MRP_LUA_CLASS_DEF_SIMPLE (
450 volume_limit, /* class name */
451 scripting_vollim, /* userdata type */
452 vollim_destroy, /* userdata destructor */
453 MRP_LUA_METHOD_LIST ( /* methods */
454 MRP_LUA_METHOD_CONSTRUCTOR (vollim_create)
456 MRP_LUA_METHOD_LIST ( /* overrides */
457 MRP_LUA_OVERRIDE_CALL (vollim_create)
458 MRP_LUA_OVERRIDE_GETFIELD (vollim_getfield)
459 MRP_LUA_OVERRIDE_SETFIELD (vollim_setfield)
460 MRP_LUA_OVERRIDE_STRINGIFY (vollim_tostring)
465 pa_scripting *pa_scripting_init(struct userdata *u)
467 pa_scripting *scripting;
472 scripting = pa_xnew0(pa_scripting, 1);
474 if (!(L = lua_newstate(alloc, u)))
475 pa_log("failed to initialize Lua");
477 lua_atpanic(L, &panic);
480 mrp_create_funcbridge_class(L);
481 mrp_lua_create_object_class(L, IMPORT_CLASS);
482 mrp_lua_create_object_class(L, NODE_CLASS);
483 mrp_lua_create_object_class(L, ZONE_CLASS);
484 mrp_lua_create_object_class(L, RESOURCE_CLASS);
485 mrp_lua_create_object_class(L, RTGROUP_CLASS);
486 mrp_lua_create_object_class(L, APPLICATION_CLASS);
487 mrp_lua_create_object_class(L, VOLLIM_CLASS);
489 array_class_create(L);
494 lua_pushlightuserdata(L, u);
495 lua_setglobal(L, USERDATA);
498 scripting->configured = FALSE;
504 void pa_scripting_done(struct userdata *u)
506 pa_scripting *scripting;
508 if (u && (scripting = u->scripting)) {
514 pa_bool_t pa_scripting_dofile(struct userdata *u, const char *file)
516 pa_scripting *scripting;
523 pa_assert_se((scripting = u->scripting));
524 pa_assert_se((L = scripting->L));
526 if (luaL_loadfile(L, file) || lua_pcall(L, 0, 0, 0)) {
528 pa_log("%s", lua_tostring(L, -1));
533 scripting->configured = TRUE;
534 setup_murphy_interface(u);
535 pa_zoneset_update_module_property(u);
541 static int import_create(lua_State *L)
544 pa_scripting *scripting;
547 scripting_import *imp;
548 const char *table = NULL;
549 mrp_lua_strarray_t *columns = NULL;
550 const char *condition = NULL;
552 mrp_funcbridge_t *update = NULL;
563 lua_getglobal(L, USERDATA);
564 if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
565 luaL_error(L, "missing or invalid global '" USERDATA "'");
567 pa_assert_se((scripting = u->scripting));
569 MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
571 switch (field_name_to_type(fldnam, fldnamlen)) {
572 case TABLE: table = luaL_checkstring(L, -1); break;
573 case COLUMNS: columns = mrp_lua_check_strarray(L, -1); break;
574 case CONDITION: condition = luaL_checkstring(L, -1); break;
575 case MAXROW: maxrow = luaL_checkint(L, -1); break;
576 case UPDATE: update = mrp_funcbridge_create_luafunc(L, -1); break;
577 default: luaL_error(L, "bad field '%s'", fldnam); break;
580 } /* MRP_LUA_FOREACH_FIELD */
585 luaL_error(L, "missing table field");
587 luaL_error(L, "missing columns field");
588 if (maxrow < 1 || maxrow >= MQI_QUERY_RESULT_MAX)
589 luaL_error(L, "missing or invalid maxrow field");
591 luaL_error(L, "missing update function");
593 maxcol = columns->nstring;
595 if (maxcol >= MQI_COLUMN_MAX)
596 luaL_error(L, "too many columns (max %d allowed)", MQI_COLUMN_MAX);
598 if (scripting->configured)
599 luaL_error(L, "refuse to import '%s' after configuration phase",table);
601 imp = (scripting_import *)mrp_lua_create_object(L, IMPORT_CLASS, table,0);
604 imp->table = pa_xstrdup(table);
605 imp->columns = columns;
606 imp->condition = condition;
607 imp->values = array_create(L, maxrow, NULL);
608 imp->update = update;
610 for (i = 0, rows = imp->values->array; i < maxrow; i++) {
611 cols = (rows[i] = array_create(L, maxcol, columns))->array;
612 lua_rawseti(L, -3, i+1); /* we add this to the import */
613 for (j = 0; j < maxcol; j++)
614 cols[j] = pa_xnew0(pa_value, 1);
617 lua_rawseti(L, -2, MQI_QUERY_RESULT_MAX);
622 static int import_getfield(lua_State *L)
624 scripting_import *imp;
631 if (!(imp = (scripting_import *)mrp_lua_check_object(L, IMPORT_CLASS, 1)))
634 pa_assert_se((values = imp->values));
636 if (lua_type(L, 2) == LUA_TNUMBER) {
637 colidx = lua_tointeger(L, 2);
639 if (colidx < 1 || colidx > -values->type)
642 lua_rawgeti(L, 1, colidx);
645 fld = field_check(L, 2, NULL);
649 case TABLE: lua_pushstring(L, imp->table); break;
650 case COLUMNS: mrp_lua_push_strarray(L, imp->columns); break;
651 case CONDITION: lua_pushstring(L, imp->condition); break;
652 case MAXROW: lua_pushinteger(L, -imp->values->type); break;
653 default: lua_pushnil(L); break;
661 static int import_setfield(lua_State *L)
667 f = luaL_checkstring(L, 2);
668 luaL_error(L, "attempt to set '%s' field of read-only mdb.import", f);
673 static int import_tostring(lua_State *L)
675 scripting_import *imp;
679 imp = (scripting_import *)mrp_lua_check_object(L, IMPORT_CLASS, 1);
681 lua_pushstring(L, imp->table);
686 static void import_destroy(void *data)
688 scripting_import *imp = (scripting_import *)data;
692 pa_xfree((void *)imp->table);
693 mrp_lua_free_strarray(imp->columns);
694 pa_xfree((void *)imp->condition);
699 static int import_link(lua_State *L)
701 scripting_import *imp;
702 mrp_lua_strarray_t *columns;
712 imp = (scripting_import *)mrp_lua_check_object(L, IMPORT_CLASS, 1);
713 rowidx = luaL_checkint(L, 2) - 1;
714 colnam = luaL_checkstring(L, 3);
717 pa_assert_se((columns = imp->columns));
721 if (rowidx >= 0 && rowidx < -imp->values->type) {
722 for (colidx = 0; colidx < columns->nstring; colidx++) {
723 if (!strcmp(colnam, columns->strings[colidx])) {
724 pa_assert_se((values = imp->values));
725 pa_assert_se((row = values->array[rowidx]));
726 pa_assert(colidx < (size_t)-row->type);
727 pa_assert_se((col = row->array[colidx]));
733 pa_log_debug("userdata: type:%d", col->type);
735 lua_pushlightuserdata(L, col);
740 static void import_data_changed(struct userdata *u,
743 mrp_domctl_value_t **mval)
745 static mrp_domctl_value_t empty;
747 pa_scripting *scripting;
749 scripting_import *imp;
750 mrp_domctl_value_t *mrow;
751 mrp_domctl_value_t *mcol;
752 pa_value *ptval, *prval, *pcval;
757 mrp_funcbridge_value_t arg;
758 mrp_funcbridge_value_t ret;
764 pa_assert(mval || nrow == 0);
765 pa_assert_se((scripting = u->scripting));
766 pa_assert_se((L = scripting->L));
768 pa_log_debug("table '%s' data changed: got %d rows", table, nrow);
770 mrp_lua_get_class_table(L, IMPORT_CLASS);
772 if (!lua_istable(L, -1)){
773 luaL_error(L, "internal error: failed to find '%s' table",
774 (IMPORT_CLASS)->constructor);
777 lua_pushstring(L, table);
780 if (!(imp = mrp_lua_to_object(L, IMPORT_CLASS, -1)))
781 pa_log("can't find import '%s'", table);
783 pa_assert(!strcmp(table, imp->table));
784 pa_assert(imp->columns);
785 pa_assert(imp->update);
786 pa_assert_se((ptval = imp->values));
787 pa_assert_se((prow = ptval->array));
789 maxrow = -ptval->type;
790 maxcol = imp->columns->nstring;
792 pa_assert(maxrow >= 0);
793 pa_assert(nrow <= maxrow);
795 pa_log_debug("import '%s' found", imp->table);
797 for (i = 0; i < maxrow; i++) {
798 pa_assert_se((prval = prow[i]));
799 pa_assert_se((pcol = prval->array));
800 pa_assert(prval->type < 0);
801 pa_assert(maxcol == -prval->type);
803 mrow = (i < nrow) ? mval[i] : NULL;
805 for (j = 0; j < maxcol; j++) {
807 mcol = mrow ? mrow + j : ∅
809 switch (mcol->type) {
810 case MRP_DOMCTL_STRING:
811 pa_assert(!pcval->type || pcval->type == pa_value_string);
812 pa_xfree((void *)pcval->string);
813 pcval->type = pa_value_string;
814 pcval->string = pa_xstrdup(mcol->str);
816 case MRP_DOMCTL_INTEGER:
817 pa_assert(!pcval->type || pcval->type == pa_value_integer);
818 pcval->type = pa_value_integer;
819 pcval->integer = mcol->s32;
821 case MRP_DOMCTL_UNSIGNED:
822 pa_assert(!pcval->type || pcval->type == pa_value_unsignd);
823 pcval->type = pa_value_unsignd;
824 pcval->unsignd = mcol->u32;
826 case MRP_DOMCTL_DOUBLE:
827 pa_assert(!pcval->type || pcval->type ==pa_value_floating);
828 pcval->type = pa_value_floating;
829 pcval->floating = mcol->dbl;
832 if (pcval->type == pa_value_string)
833 pa_xfree((void *)pcval->string);
834 memset(pcval, 0, sizeof(pa_value));
842 if (!mrp_funcbridge_call_from_c(L, imp->update, "o", &arg, &t, &ret)) {
843 pa_log("failed to call %s:update method (%s)",
844 imp->table, ret.string);
845 pa_xfree((void *)ret.string);
853 static bool update_bridge(lua_State *L, void *data, const char *signature,
854 mrp_funcbridge_value_t *args,
855 char *ret_type, mrp_funcbridge_value_t *ret_val)
857 update_func_t update;
858 scripting_import *imp;
864 pa_assert(signature);
869 pa_assert_se((update = (update_func_t)data));
871 if (strcmp(signature, "o"))
874 pa_assert_se((imp = args[0].pointer));
875 pa_assert_se((u = imp->userdata));
878 *ret_type = MRP_FUNCBRIDGE_NO_DATA;
879 memset(ret_val, 0, sizeof(mrp_funcbridge_value_t));
888 static void array_class_create(lua_State *L)
890 /* create a metatable for row's */
891 luaL_newmetatable(L, ARRAY_CLASSID);
892 lua_pushliteral(L, "__index");
893 lua_pushvalue(L, -2);
894 lua_settable(L, -3); /* metatable.__index = metatable */
895 luaL_openlib(L, NULL, array_overrides, 0);
899 static pa_value *array_create(lua_State *L, int dimension,
900 mrp_lua_strarray_t *names)
906 pa_assert(dimension >= 0);
907 pa_assert(dimension < MQI_QUERY_RESULT_MAX);
909 array = pa_xnew0(pa_value *, dimension + 1);
910 value = lua_newuserdata(L, sizeof(pa_value));
911 value->type = -dimension;
912 value->array = array;
914 array[dimension] = (pa_value *)names;
916 luaL_getmetatable(L, ARRAY_CLASSID);
917 lua_setmetatable(L, -2);
922 static int array_getfield(lua_State *L)
924 pa_value *arr, *value;
928 mrp_lua_strarray_t *names;
936 arr = (pa_value *)luaL_checkudata(L, 1, ARRAY_CLASSID);
938 pa_assert(arr->type < 0);
940 dimension = -arr->type;
941 key_type = lua_type(L, 2);
945 idx = lua_tointeger(L, 2) - 1;
949 if ((names = (mrp_lua_strarray_t *)arr->array[dimension])) {
950 pa_assert(dimension == names->nstring);
951 key = lua_tostring(L, 2);
953 for (i = 0; i < dimension; i++) {
954 if (!strcmp(key, names->strings[i])) {
967 if (idx < 0 || idx >= dimension || !(value = arr->array[idx]))
969 else if (value->type < 0)
970 lua_rawgeti(L, 1, 1 - value->type);
972 switch (value->type) {
973 case pa_value_string: lua_pushstring(L, value->string); break;
974 case pa_value_integer: lua_pushinteger(L, value->integer); break;
975 case pa_value_unsignd: lua_pushinteger(L, value->unsignd); break;
976 case pa_value_floating: lua_pushnumber(L, value->floating); break;
977 default: lua_pushnil(L); break;
984 static int array_setfield(lua_State *L)
990 luaL_error(L, "attempt to write to a read-only object");
995 static int array_getlength(lua_State *L)
1005 static void array_destroy(void *data)
1007 pa_value *value = (pa_value *)data;
1012 pa_assert(value->type < 0);
1013 pa_xfree(value->array);
1016 MRP_LUA_LEAVE_NOARG;
1020 scripting_node *pa_scripting_node_create(struct userdata *u, mir_node *node)
1022 pa_scripting *scripting;
1029 pa_assert(node->amname);
1031 pa_assert_se((scripting = u->scripting));
1032 pa_assert_se((L = scripting->L));
1034 make_id(id, sizeof(id), "%s_%d", node->amname, node->index);
1036 if ((sn = (scripting_node *)mrp_lua_create_object(L, NODE_CLASS, id,0))) {
1038 sn->id = pa_xstrdup(id);
1045 void pa_scripting_node_destroy(struct userdata *u, mir_node *node)
1047 pa_scripting *scripting;
1056 pa_assert_se((scripting = u->scripting));
1057 pa_assert_se((L = scripting->L));
1059 if ((sn = node->scripting)) {
1060 mrp_lua_destroy_object(L, sn->id,0, sn);
1062 node->scripting = NULL;
1065 MRP_LUA_LEAVE_NOARG;
1068 static int node_create(lua_State *L)
1077 static int node_getfield(lua_State *L)
1085 fld = field_check(L, 2, NULL);
1088 if (!(sn = (scripting_node *)mrp_lua_check_object(L, NODE_CLASS, 1)))
1091 pa_assert_se((node = sn->node));
1094 case NAME: lua_pushstring(L, node->amname); break;
1095 case DESCRIPTION: lua_pushstring(L, node->amdescr); break;
1096 case DIRECTION: lua_pushinteger(L, node->direction); break;
1097 case IMPLEMENT: lua_pushinteger(L, node->implement); break;
1098 case CHANNELS: lua_pushinteger(L, node->channels); break;
1099 case LOCATION: lua_pushinteger(L, node->location); break;
1100 case PRIVACY: lua_pushinteger(L, node->privacy); break;
1101 case ZONE: lua_pushstring(L, node->zone); break;
1102 case TYPE: lua_pushinteger(L, node->type); break;
1103 case AVAILABLE: lua_pushboolean(L, node->available); break;
1104 default: lua_pushnil(L); break;
1111 static int node_setfield(lua_State *L)
1117 f = luaL_checkstring(L, 2);
1118 luaL_error(L, "attempt to set '%s' field of read-only node", f);
1123 static int node_tostring(lua_State *L)
1129 sn = (scripting_node *)mrp_lua_check_object(L, NODE_CLASS, 1);
1131 lua_pushstring(L, (sn && sn->id) ? sn->id : "<unknown node>");
1136 static void node_destroy(void *data)
1138 scripting_node *sn = (scripting_node *)data;
1143 if ((node = sn->node) && sn == node->scripting)
1144 node->scripting = NULL;
1146 pa_xfree((void *)sn->id);
1148 MRP_LUA_LEAVE_NOARG;
1152 static int zone_create(lua_State *L)
1154 static uint32_t index;
1159 scripting_zone *zone;
1160 const char *name = NULL;
1161 attribute_t *attributes = NULL;
1165 lua_getglobal(L, USERDATA);
1166 if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
1167 luaL_error(L, "missing or invalid global '" USERDATA "'");
1171 MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
1173 switch (field_name_to_type(fldnam, fldnamlen)) {
1174 case NAME: name = luaL_checkstring(L, -1); break;
1175 case ATTRIBUTES: attributes = attributes_check(L, -1); break;
1176 default: luaL_error(L, "bad field '%s'", fldnam); break;
1179 } /* MRP_LUA_FOREACH_FIELD */
1182 luaL_error(L, "missing or invalid name field");
1184 if (pa_zoneset_add_zone(u, name, index+1))
1185 luaL_error(L, "attempt to define zone '%s' multiple times", name);
1187 zone = (scripting_zone *)mrp_lua_create_object(L, ZONE_CLASS,
1191 zone->name = pa_xstrdup(name);
1192 zone->index = ++index;
1198 static int zone_getfield(lua_State *L)
1200 scripting_zone *zone;
1205 fld = field_check(L, 2, NULL);
1208 if (!(zone = (scripting_zone *)mrp_lua_check_object(L, ZONE_CLASS, 1)))
1212 case NAME: lua_pushstring(L, zone->name); break;
1214 case ATTRIBUTES: lua_pushinteger(L, rtgs->type); break;
1216 default: lua_pushnil(L); break;
1223 static int zone_setfield(lua_State *L)
1229 f = luaL_checkstring(L, 2);
1230 luaL_error(L, "attempt to set '%s' field of read-only zone", f);
1235 static void zone_destroy(void *data)
1237 scripting_zone *zone = (scripting_zone *)data;
1241 pa_xfree((void *)zone->name);
1245 MRP_LUA_LEAVE_NOARG;
1249 static int resource_create(lua_State *L)
1255 scripting_resource *res;
1256 resource_name_t *name = NULL;
1257 attribute_t *attributes = NULL;
1262 lua_getglobal(L, USERDATA);
1263 if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
1264 luaL_error(L, "missing or invalid global '" USERDATA "'");
1268 MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
1270 switch (field_name_to_type(fldnam, fldnamlen)) {
1271 case NAME: name = resource_names_check(L, -1); break;
1272 case ATTRIBUTES: attributes = attributes_check(L, -1); break;
1273 default: luaL_error(L, "bad field '%s'", fldnam); break;
1276 } /* MRP_LUA_FOREACH_FIELD */
1279 luaL_error(L, "missing or invalid name field");
1281 pa_murphyif_add_audio_resource(u, mir_input, name->playback);
1282 pa_murphyif_add_audio_resource(u, mir_output, name->recording);
1285 for (attr = attributes; attr->prop && attr->def.name; attr++) {
1286 switch (attr->def.type) {
1288 pa_murphyif_add_audio_attribute(u, attr->prop,
1291 attr->def.value.string);
1294 pa_murphyif_add_audio_attribute(u, attr->prop,
1297 attr->def.value.integer);
1300 pa_murphyif_add_audio_attribute(u, attr->prop,
1303 attr->def.value.unsignd);
1306 pa_murphyif_add_audio_attribute(u, attr->prop,
1309 attr->def.value.floating);
1312 luaL_error(L, "invalid audio resource attribute '%s'",
1319 res = (scripting_resource *)mrp_lua_create_object(L, RTGROUP_CLASS,
1324 res->attributes = attributes;
1329 static int resource_getfield(lua_State *L)
1331 scripting_resource *res;
1336 fld = field_check(L, 2, NULL);
1339 if (!(res = (scripting_resource*)mrp_lua_check_object(L,RESOURCE_CLASS,1)))
1344 case NAME: lua_pushstring(L, rtg->name); break;
1345 case ATTRIBUTES: lua_pushinteger(L, rtgs->type); break;
1346 default: lua_pushnil(L); break;
1356 static int resource_setfield(lua_State *L)
1362 f = luaL_checkstring(L, 2);
1363 luaL_error(L, "attempt to set '%s' field of read-only resource_class", f);
1368 static void resource_destroy(void *data)
1370 scripting_resource *res = (scripting_resource *)data;
1374 resource_names_destroy(res->name);
1375 attributes_destroy(res->attributes);
1378 res->attributes = NULL;
1380 MRP_LUA_LEAVE_NOARG;
1384 static int rtgroup_create(lua_State *L)
1390 scripting_rtgroup *rtgs;
1391 const char *name = NULL;
1392 mir_direction type = 0;
1393 mrp_funcbridge_t *accept = NULL;
1394 mrp_funcbridge_t *compare = NULL;
1399 lua_getglobal(L, USERDATA);
1400 if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
1401 luaL_error(L, "missing or invalid global '" USERDATA "'");
1405 MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
1407 switch (field_name_to_type(fldnam, fldnamlen)) {
1408 case NAME: name = luaL_checkstring(L, -1); break;
1409 case NODE_TYPE: type = luaL_checkint(L, -1); break;
1410 case ACCEPT: accept = mrp_funcbridge_create_luafunc(L, -1); break;
1411 case COMPARE: compare = mrp_funcbridge_create_luafunc(L, -1); break;
1412 default: luaL_error(L, "bad field '%s'", fldnam); break;
1415 } /* MRP_LUA_FOREACH_FIELD */
1418 luaL_error(L, "missing name field");
1419 if (type != mir_input && type != mir_output)
1420 luaL_error(L, "missing or invalid node_type");
1422 luaL_error(L, "missing or invalid accept field");
1424 luaL_error(L, "missing or invalid compare field");
1426 make_id(id,sizeof(id), "%s_%sput", name, (type == mir_input) ? "in":"out");
1428 rtgs = (scripting_rtgroup *)mrp_lua_create_object(L, RTGROUP_CLASS, id,0);
1430 rtg = mir_router_create_rtgroup(u, type, pa_xstrdup(name),
1431 rtgroup_accept, rtgroup_compare);
1433 luaL_error(L, "failed to create routing group '%s'", id);
1435 rtg->scripting = rtgs;
1440 rtgs->accept = accept;
1441 rtgs->compare = compare;
1446 static int rtgroup_getfield(lua_State *L)
1448 scripting_rtgroup *rtgs;
1454 fld = field_check(L, 2, NULL);
1457 if (!(rtgs = (scripting_rtgroup *)mrp_lua_check_object(L,RTGROUP_CLASS,1)))
1460 pa_assert_se((rtg = rtgs->rtg));
1463 case NAME: lua_pushstring(L, rtg->name); break;
1464 case NODE_TYPE: lua_pushinteger(L, rtgs->type); break;
1465 default: lua_pushnil(L); break;
1472 static int rtgroup_setfield(lua_State *L)
1478 f = luaL_checkstring(L, 2);
1479 luaL_error(L, "attempt to set '%s' field of read-only routing_group", f);
1484 static int rtgroup_tostring(lua_State *L)
1486 scripting_rtgroup *rtgs;
1491 rtgs = (scripting_rtgroup *)mrp_lua_check_object(L, RTGROUP_CLASS, 1);
1492 pa_assert_se((rtg = rtgs->rtg));
1494 lua_pushstring(L, rtg->name);
1499 static void rtgroup_destroy(void *data)
1501 scripting_rtgroup *rtgs = (scripting_rtgroup *)data;
1506 pa_assert_se((rtg = rtgs->rtg));
1507 pa_assert(rtgs == rtg->scripting);
1509 rtg->scripting = NULL;
1511 MRP_LUA_LEAVE_NOARG;
1515 static pa_bool_t rtgroup_accept(struct userdata *u,
1519 pa_scripting *scripting;
1521 scripting_rtgroup *rtgs;
1522 mrp_funcbridge_value_t args[2];
1524 mrp_funcbridge_value_t rv;
1528 pa_assert_se((scripting = u->scripting));
1529 pa_assert_se((L = scripting->L));
1531 pa_assert_se((rtgs = rtg->scripting));
1532 pa_assert(u == rtgs->userdata);
1533 pa_assert(rtgs->accept);
1538 if ((rtgs = rtg->scripting) && node->scripting) {
1540 args[0].pointer = rtgs;
1541 args[1].pointer = node->scripting;
1543 if (!mrp_funcbridge_call_from_c(L, rtgs->accept, "oo",args, &rt,&rv)) {
1544 if (rt != MRP_FUNCBRIDGE_STRING)
1545 pa_log("call to accept function failed");
1547 pa_log("call to accept function failed: %s", rv.string);
1548 mrp_free((void *)rv.string);
1552 if (rt != MRP_FUNCBRIDGE_BOOLEAN)
1553 pa_log("accept function returned invalid type");
1555 accept = rv.boolean;
1562 static int rtgroup_compare(struct userdata *u,
1567 pa_scripting *scripting;
1569 scripting_rtgroup *rtgs;
1570 mrp_funcbridge_value_t args[3];
1572 mrp_funcbridge_value_t rv;
1576 pa_assert_se((scripting = u->scripting));
1577 pa_assert_se((L = scripting->L));
1579 pa_assert_se((rtgs = rtg->scripting));
1580 pa_assert(u == rtgs->userdata);
1581 pa_assert(rtgs->compare);
1587 if ((rtgs = rtg->scripting) && node1->scripting && node2->scripting) {
1589 args[0].pointer = rtgs;
1590 args[1].pointer = node1->scripting;
1591 args[2].pointer = node2->scripting;
1593 if (!mrp_funcbridge_call_from_c(L, rtgs->compare, "ooo",args, &rt,&rv))
1594 pa_log("failed to call compare function");
1596 if (rt != MRP_FUNCBRIDGE_FLOATING)
1597 pa_log("compare function returned invalid type");
1599 result = rv.floating;
1607 static bool accept_bridge(lua_State *L, void *data,
1608 const char *signature, mrp_funcbridge_value_t *args,
1609 char *ret_type, mrp_funcbridge_value_t *ret_val)
1611 mir_rtgroup_accept_t accept;
1612 scripting_rtgroup *rtgs;
1621 pa_assert(signature);
1623 pa_assert(ret_type);
1626 pa_assert_se((accept = (mir_rtgroup_accept_t)data));
1628 if (strcmp(signature, "oo"))
1631 pa_assert_se((rtgs = args[0].pointer));
1632 pa_assert_se((u = rtgs->userdata));
1633 pa_assert_se((ns = args[1].pointer));
1635 if (!(rtg = rtgs->rtg) || !(node = ns->node))
1639 *ret_type = MRP_FUNCBRIDGE_BOOLEAN;
1640 ret_val->boolean = accept(u, rtg, node);
1648 static bool compare_bridge(lua_State *L, void *data,
1649 const char *signature, mrp_funcbridge_value_t *args,
1650 char *ret_type, mrp_funcbridge_value_t *ret_val)
1652 mir_rtgroup_compare_t compare;
1653 scripting_rtgroup *rtgs;
1654 scripting_node *ns1, *ns2;
1657 mir_node *node1, *node2;
1662 pa_assert(signature);
1664 pa_assert(ret_type);
1667 pa_assert_se((compare = (mir_rtgroup_compare_t)data));
1669 if (strcmp(signature, "ooo"))
1672 pa_assert_se((rtgs = args[0].pointer));
1673 pa_assert_se((u = rtgs->userdata));
1674 pa_assert_se((ns1 = args[1].pointer));
1675 pa_assert_se((ns2 = args[2].pointer));
1678 if (!(rtg = rtgs->rtg) || !(node1 = ns1->node) || !(node2 = ns2->node))
1682 *ret_type = MRP_FUNCBRIDGE_FLOATING;
1683 ret_val->floating = compare(u, rtg, node1, node2);
1691 static int apclass_create(lua_State *L)
1696 scripting_apclass *ac;
1698 const char *class = NULL;
1699 mir_node_type type = -1;
1701 route_t *route = NULL;
1702 map_t *roles = NULL;
1703 map_t *binaries = NULL;
1704 pa_bool_t needs_resource = FALSE;
1705 pa_nodeset_resdef *resdef;
1712 lua_getglobal(L, USERDATA);
1713 if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
1714 luaL_error(L, "missing or invalid global '" USERDATA "'");
1718 MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
1720 switch (field_name_to_type(fldnam, fldnamlen)) {
1721 case CLASS: class = luaL_checkstring(L, -1); break;
1722 case NODE_TYPE: type = luaL_checkint(L, -1); break;
1723 case PRIORITY: priority = luaL_checkint(L, -1); break;
1724 case ROUTE: route = route_check(L, -1); break;
1725 case ROLES: roles = map_check(L, -1); break;
1726 case BINARIES: binaries = map_check(L, -1); break;
1727 default: luaL_error(L, "bad field '%s'", fldnam); break;
1730 } /* MRP_LUA_FOREACH_FIELD */
1732 if (type < mir_application_class_begin ||
1733 type >= mir_application_class_end )
1734 luaL_error(L, "missing or invalid node_type %d", type);
1736 luaL_error(L, "missing or invalid priority field");
1738 luaL_error(L, "missing or invalid route field");
1739 if (!roles && !binaries)
1740 luaL_error(L, "missing roles or binaries");
1742 make_id(name, sizeof(name), "%s", mir_node_type_str(type));
1744 mir_router_assign_class_priority(u, type, priority);
1747 ir = !route->input ? TRUE : mir_router_assign_class_to_rtgroup(
1751 or = !route->output ? TRUE : mir_router_assign_class_to_rtgroup(
1757 ac = (scripting_apclass *)mrp_lua_create_object(L, APPLICATION_CLASS,
1760 if (/* !ir || !or || */ !ac)
1761 luaL_error(L, "failed to create application class '%s'", name);
1764 ac->name = pa_xstrdup(name);
1765 ac->class = class ? pa_xstrdup(class) : NULL;
1767 ac->priority = priority;
1770 ac->binaries = binaries;
1773 if (pa_nodeset_add_class(u, type, class)) {
1774 luaL_error(L, "node type '%s' is defined multiple times",
1775 mir_node_type_str(type));
1780 for (r = roles; r->name; r++) {
1781 resdef = r->needres ? &r->resource : NULL;
1783 if (pa_nodeset_add_role(u, r->name, type, resdef)) {
1784 luaL_error(L, "role '%s' is added to mutiple application "
1785 "classes", r->name);
1791 for (b = binaries; b->name; b++) {
1792 resdef = b->needres ? &b->resource : NULL;
1794 if (pa_nodeset_add_binary(u, b->name, type, resdef)) {
1795 luaL_error(L, "binary '%s' is added to multiple application "
1796 "classes", b->name);
1804 static int apclass_getfield(lua_State *L)
1806 scripting_apclass *ac;
1811 fld = field_check(L, 2, NULL);
1814 if (!(ac=(scripting_apclass *)mrp_lua_check_object(L,APPLICATION_CLASS,1)))
1818 case NAME: lua_pushstring(L, ac->name); break;
1819 case NODE_TYPE: lua_pushinteger(L, ac->type); break;
1820 case PRIORITY: lua_pushinteger(L, ac->priority); break;
1821 case ROUTE: route_push(L, ac->route); break;
1822 case ROLES: map_push(L, ac->roles); break;
1823 case BINARIES: map_push(L, ac->binaries); break;
1824 default: lua_pushnil(L); break;
1831 static int apclass_setfield(lua_State *L)
1837 f = luaL_checkstring(L, 2);
1838 luaL_error(L,"attempt to set '%s' field of read-only application class",f);
1843 static int apclass_tostring(lua_State *L)
1845 scripting_apclass *ac;
1849 ac = (scripting_apclass *)mrp_lua_check_object(L, APPLICATION_CLASS, 1);
1851 lua_pushstring(L, ac->name);
1856 static void apclass_destroy(void *data)
1858 scripting_apclass *ac = (scripting_apclass *)data;
1866 pa_assert_se((u = ac->userdata));
1868 route_destroy(ac->route);
1871 pa_xfree((void *)ac->name);
1874 pa_nodeset_delete_class(u, ac->type);
1875 pa_xfree((void *)ac->class);
1879 for (r = ac->roles; r->name; r++)
1880 pa_nodeset_delete_role(u, r->name);
1882 map_destroy(ac->roles);
1887 for (b = ac->binaries; b->name; b++)
1888 pa_nodeset_delete_binary(u, b->name);
1890 map_destroy(ac->binaries);
1891 ac->binaries = NULL;
1894 MRP_LUA_LEAVE_NOARG;
1897 static const char **route_definition_check(lua_State *L, int idx)
1900 const char *zonenam;
1901 scripting_zone *zone;
1902 scripting_rtgroup *rtgs;
1908 idx = (idx < 0) ? lua_gettop(L) + idx + 1 : idx;
1910 luaL_checktype(L, idx, LUA_TTABLE);
1912 defs = pa_xnew0(const char *, MRP_ZONE_MAX);
1915 MRP_LUA_FOREACH_FIELD(L, idx, zonenam, zonelen) {
1917 luaL_error(L, "invalid route definition");
1919 mrp_lua_find_object(L, ZONE_CLASS, zonenam);
1921 if (!(zone = mrp_lua_check_object(L, NULL, -1)))
1922 luaL_error(L, "can't find zone '%s'", zonenam);
1926 if (zone->index >= MRP_ZONE_MAX)
1927 luaL_error(L, "Internal error: zone index overflow");
1929 switch (lua_type(L, -1)) {
1931 rtgnam = lua_tostring(L, -1);
1934 rtgs = (scripting_rtgroup*)mrp_lua_check_object(L,RTGROUP_CLASS,-1);
1935 if (!rtgs || !(rtg = rtgs->rtg))
1946 luaL_error(L, "missing or invalid routing group");
1948 defs[zone->index] = pa_xstrdup(rtgnam);
1953 luaL_error(L, "empty definition");
1958 static int route_definition_push(lua_State *L, const char **defs)
1962 lua_createtable(L, MRP_ZONE_MAX, 0);
1964 for (i = 0; i < MRP_ZONE_MAX; i++) {
1971 static void route_definition_free(const char **defs)
1976 for (i = 0; i < MRP_ZONE_MAX; i++)
1977 pa_xfree((void *)defs[i]);
1978 pa_xfree((void *)defs);
1983 static route_t *route_check(lua_State *L, int idx)
1988 const char **input = NULL;
1989 const char **output = NULL;
1991 idx = (idx < 0) ? lua_gettop(L) + idx + 1 : idx;
1993 luaL_checktype(L, idx, LUA_TTABLE);
1995 MRP_LUA_FOREACH_FIELD(L, idx, fldnam, fldnamlen) {
1996 switch (field_name_to_type(fldnam, fldnamlen)) {
1997 case INPUT: input = route_definition_check(L, -1); break;
1998 case OUTPUT: output = route_definition_check(L, -1); break;
1999 default: luaL_error(L, "invalid field '%s'", fldnam); break;
2001 } /* MRP_LUA_FOREACH_FIELD */
2003 if (!input && !output)
2004 luaL_error(L, "neither input nor output routing group were specified");
2006 rt = pa_xmalloc(sizeof(route_t));
2008 rt->output = output;
2013 static int route_push(lua_State *L, route_t *rt)
2015 if (!rt || (!rt->input && !rt->output))
2018 lua_createtable(L, 0, 2);
2021 lua_pushstring(L, "input");
2022 route_definition_push(L, rt->input);
2023 lua_settable(L, -3);
2027 lua_pushstring(L, "output");
2028 route_definition_push(L, rt->output);
2029 lua_settable(L, -3);
2036 static void route_destroy(route_t *rt)
2039 pa_xfree((void *)rt->input);
2040 pa_xfree((void *)rt->output);
2041 pa_xfree((void *)rt);
2046 static int vollim_create(lua_State *L)
2048 static int min = mir_application_class_begin;
2049 static int max = mir_application_class_end;
2054 scripting_vollim *vlim;
2055 const char *name = NULL;
2056 vollim_type type = 0;
2057 limit_data_t *limit = NULL;
2058 mrp_funcbridge_t *calculate = NULL;
2059 intarray_t *classes = NULL;
2060 pa_bool_t suppress = FALSE;
2061 pa_bool_t correct = FALSE;
2065 uint32_t mask, clmask;
2070 lua_getglobal(L, USERDATA);
2071 if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
2072 luaL_error(L, "missing or invalid global '" USERDATA "'");
2076 MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
2078 switch (field_name_to_type(fldnam, fldnamlen)) {
2079 case NAME: name = luaL_checkstring(L, -1); break;
2080 case TYPE: type = luaL_checkint(L, -1); break;
2081 case NODE_TYPE: classes = intarray_check(L, -1, min, max); break;
2082 case LIMIT: limit = limit_data_check(L, -1); break;
2083 case CALCULATE: calculate = mrp_funcbridge_create_luafunc(L,-1); break;
2084 default: luaL_error(L, "bad field '%s'", fldnam); break;
2087 } /* MRP_LUA_FOREACH_FIELD */
2090 luaL_error(L, "missing name field");
2091 if (type != vollim_class && type != vollim_generic)
2092 luaL_error(L, "missing or invalid type");
2093 if (type == vollim_class && !classes)
2094 luaL_error(L, "missing or invalid node_type for class volume limit");
2095 if (type == vollim_generic && classes)
2096 luaL_error(L, "can't specify node_type for generic volume limit");
2098 luaL_error(L, "missing or invalid limit");
2100 luaL_error(L, "missing calculate field");
2101 if (calculate->type == MRP_C_FUNCTION) {
2102 if (strcmp(calculate->c.signature, "odo"))
2103 luaL_error(L, "invalid calculate field (mismatching signature)");
2104 if (calculate->c.data == mir_volume_suppress) {
2105 if (type != vollim_class)
2106 luaL_error(L, "attempt to make generic volume supression");
2108 arglgh = sizeof(mir_volume_suppress_arg);
2110 else if (calculate->c.data == mir_volume_correction) {
2111 if (type != vollim_generic)
2112 luaL_error(L, "attempt to make class based volume correction");
2114 arglgh = sizeof(double *);
2117 luaL_error(L, "invalid builtin.method for calculate");
2121 make_id(id, sizeof(id), "%s", name);
2123 (VOLLIM_CLASS)->userdata_size = sizeof(scripting_vollim) + arglgh;
2124 vlim = (scripting_vollim *)mrp_lua_create_object(L, VOLLIM_CLASS, id,0);
2125 (VOLLIM_CLASS)->userdata_size = sizeof(scripting_vollim);
2128 vlim->name = pa_xstrdup(name);
2130 vlim->classes = classes;
2131 vlim->limit = limit;
2132 vlim->calculate = calculate;
2135 mir_volume_suppress_arg *args = (mir_volume_suppress_arg *)vlim->args;
2136 size_t size = sizeof(int) * classes->nint;
2137 size_t n = mir_application_class_end - mir_application_class_begin;
2139 for (i = 0, clmask = 0; i < classes->nint; i++) {
2140 class = classes->ints[i];
2142 if (class <= mir_application_class_begin ||
2143 class > mir_application_class_end )
2145 pa_log("invalid triggering class id %d", class);
2147 classes->nint = n = 0;
2151 mask = ((uint32_t)1) << (class - mir_application_class_begin);
2153 if (!(clmask & mask) && n > 0)
2159 args->attenuation = limit->value;
2160 args->trigger.nclass = classes->nint;
2161 args->trigger.classes = pa_xmalloc(size);
2162 args->trigger.clmask = clmask;
2164 memcpy(args->trigger.classes, classes->ints, size);
2166 if (n > classes->nint)
2167 classes->ints = pa_xrealloc(classes->ints, sizeof(int) * n);
2170 for (i = mir_application_class_begin, n = 0;
2171 i < mir_application_class_end;
2174 if (!(clmask & (((uint32_t)1) << (i-mir_application_class_begin))))
2175 classes->ints[n++] = i;
2179 /* *(double **)vlim->args = limit->value; */
2181 memcpy(vlim->args, &limit->value, sizeof(limit->value));
2184 if (type == vollim_generic)
2185 mir_volume_add_generic_limit(u, vollim_calculate, vlim->args);
2187 for (i = 0; i < classes->nint; i++) {
2188 mir_volume_add_class_limit(u, classes->ints[i], vollim_calculate,
2196 static int vollim_getfield(lua_State *L)
2198 scripting_vollim *vlim;
2203 fld = field_check(L, 2, NULL);
2206 if (!(vlim = (scripting_vollim *)mrp_lua_check_object(L, VOLLIM_CLASS, 1)))
2210 case NAME: lua_pushstring(L, vlim->name); break;
2211 case TYPE: lua_pushinteger(L, vlim->type); break;
2212 case NODE_TYPE: intarray_push(L, vlim->classes); break;
2213 case LIMIT: lua_pushnumber(L, *vlim->limit->value); break;
2214 default: lua_pushnil(L); break;
2221 static int vollim_setfield(lua_State *L)
2227 f = luaL_checkstring(L, 2);
2228 luaL_error(L, "attempt to set '%s' field of read-only volume_limit", f);
2233 static int vollim_tostring(lua_State *L)
2235 scripting_vollim *vlim;
2239 vlim = (scripting_vollim *)mrp_lua_check_object(L, VOLLIM_CLASS, 1);
2241 lua_pushstring(L, vlim->name);
2246 static void vollim_destroy(void *data)
2248 scripting_vollim *vlim = (scripting_vollim *)data;
2252 pa_xfree((void *)vlim->name);
2253 intarray_destroy(vlim->classes);
2254 limit_data_destroy(vlim->limit);
2256 MRP_LUA_LEAVE_NOARG;
2260 static double vollim_calculate(struct userdata *u, int class, mir_node *node,
2263 static int offset = ((scripting_vollim *)0)->args - (char *)0;
2265 pa_scripting *scripting;
2267 scripting_vollim *vlim;
2268 mrp_funcbridge_value_t args[3];
2270 mrp_funcbridge_value_t rv;
2274 pa_assert_se((scripting = u->scripting));
2275 pa_assert_se((L = scripting->L));
2276 pa_assert(!class || (class >= mir_application_class_begin &&
2277 class < mir_application_class_end) );
2280 vlim = (scripting_vollim *)(data - offset);
2282 pa_assert(u == vlim->userdata);
2286 if (node->scripting) {
2288 args[0].pointer = vlim;
2289 args[1].integer = class;
2290 args[2].pointer = node->scripting;
2292 if (!mrp_funcbridge_call_from_c(L,vlim->calculate,"odo",args,&rt,&rv))
2293 pa_log("failed to call calculate function");
2295 if (rt != MRP_FUNCBRIDGE_FLOATING)
2296 pa_log("accept function returned invalid type");
2298 limit = rv.floating;
2305 static bool calculate_bridge(lua_State *L, void *data, const char *signature,
2306 mrp_funcbridge_value_t *args,
2307 char *ret_type, mrp_funcbridge_value_t *ret_val)
2309 mir_volume_func_t calculate;
2310 scripting_vollim *vlim;
2319 pa_assert(signature);
2321 pa_assert(ret_type);
2324 pa_assert_se((calculate = (mir_volume_func_t)data));
2326 if (strcmp(signature, "odo"))
2329 pa_assert_se((vlim = args[0].pointer));
2330 pa_assert_se((u = vlim->userdata));
2331 pa_assert_se((ns = args[2].pointer));
2333 class = args[1].integer;
2335 pa_assert(!class || (class >= mir_application_class_begin &&
2336 class < mir_application_class_end));
2338 if (!(node = ns->node))
2342 *ret_type = MRP_FUNCBRIDGE_FLOATING;
2343 ret_val->floating = calculate(u, class, node, vlim->args);
2350 static limit_data_t *limit_data_check(lua_State *L, int idx)
2352 static double nolimit = 0.0;
2358 switch (lua_type(L, idx)) {
2360 if ((value = lua_tonumber(L, idx)) > 0.0)
2361 luaL_error(L, "volume limit is in dB and can't be positive");
2363 ld = pa_xnew0(limit_data_t, 1);
2365 ld->value = pa_xnew0(double, 1);
2369 case LUA_TLIGHTUSERDATA:
2370 if (!(v = lua_touserdata(L, idx)) || v->type < 0)
2371 luaL_error(L, "broken link for volume limit value");
2373 ld = pa_xnew0(limit_data_t, 1);
2374 ld->mallocd = FALSE;
2375 ld->value = &v->floating;
2379 ld->mallocd = FALSE;
2380 ld->value = &nolimit;
2388 static int limit_data_push(lua_State *L, limit_data_t *ld)
2391 lua_pushnumber(L, *ld->value);
2399 static void limit_data_destroy(limit_data_t *ld)
2403 pa_xfree(ld->value);
2409 static intarray_t *intarray_check(lua_State *L, int idx, int min, int max)
2417 idx = (idx < 0) ? lua_gettop(L) + idx + 1 : idx;
2419 luaL_checktype(L, idx, LUA_TTABLE);
2421 if ((len = luaL_getn(L, idx)) < 1)
2424 size = sizeof(intarray_t) + sizeof(int) * len;
2425 arr = pa_xmalloc0(sizeof(intarray_t));
2428 arr->ints = pa_xmalloc0(size);
2430 for (i = 0; i < len; i++) {
2431 lua_pushnumber(L, (int)(i+1));
2432 lua_gettable(L, idx);
2434 val = luaL_checkint(L, -1);
2438 if (val < min || val >= max)
2439 luaL_error(L, "array [%u]: out of range value (%d)", i, val);
2448 static int intarray_push(lua_State *L, intarray_t *arr)
2455 lua_createtable(L, arr->nint, 0);
2457 for (i = 0; i < arr->nint; i++) {
2458 lua_pushinteger(L, (int)(i+1));
2459 lua_pushinteger(L, arr->ints[i]);
2460 lua_settable(L, -3);
2467 static void intarray_destroy(intarray_t *arr)
2470 pa_xfree(arr->ints);
2475 static resource_name_t *resource_names_check(lua_State *L, int tbl)
2477 resource_name_t *name;
2482 tbl = (tbl < 0) ? lua_gettop(L) + tbl + 1 : tbl;
2484 luaL_checktype(L, tbl, LUA_TTABLE);
2486 name = pa_xnew0(resource_name_t, 1);
2488 MRP_LUA_FOREACH_FIELD(L, tbl, fldnam, fldnamlen) {
2489 value = luaL_checkstring(L, -1);
2491 if (!strcmp(fldnam, "recording"))
2492 name->recording = pa_xstrdup(value);
2493 else if (!strcmp(fldnam, "playback"))
2494 name->playback = pa_xstrdup(value);
2496 luaL_error(L, "invalid field '%s' in resource name definition",
2504 static void resource_names_destroy(resource_name_t *name)
2507 pa_xfree((void *)name->recording);
2508 pa_xfree((void *)name->playback);
2513 static attribute_t *attributes_check(lua_State *L, int tbl)
2518 attribute_t *attr, *attrs = NULL;
2520 mrp_attr_value_t *v;
2523 tbl = (tbl < 0) ? lua_gettop(L) + tbl + 1 : tbl;
2525 luaL_checktype(L, tbl, LUA_TTABLE);
2527 MRP_LUA_FOREACH_FIELD(L, tbl, fldnam, fldnamlen) {
2529 luaL_error(L, "invalid attribute definition");
2531 attrs = pa_xrealloc(attrs, sizeof(attribute_t) * (nattr + 2));
2532 memset(attrs + nattr, 0, sizeof(attribute_t) * 2);
2534 attr = attrs + nattr++;
2535 v = &attr->def.value;
2536 def = lua_gettop(L);
2538 attr->def.name = pa_xstrdup(fldnam);
2540 if ((len = luaL_getn(L, def)) != 3)
2541 luaL_error(L, "invalid attribute definition '%s'", fldnam);
2543 for (i = 0; i < len; i++) {
2544 lua_pushnumber(L, (int)(i+1));
2545 lua_gettable(L, def);
2548 case 0: attr->prop = pa_xstrdup(luaL_checkstring(L,-1)); break;
2549 case 1: attr->def.type = luaL_checkint(L,-1); break;
2551 switch (attr->def.type) {
2552 case mqi_string: v->string = luaL_checkstring(L,-1); break;
2553 case mqi_integer: v->integer = luaL_checkint(L,-1); break;
2554 case mqi_unsignd: v->integer = luaL_checkint(L,-1); break;
2555 case mqi_floating: v->floating = luaL_checknumber(L,-1); break;
2556 default: memset(v, 0, sizeof(*v)); break;
2564 luaL_error(L, "missing property name definition from '%s'",fldnam);
2565 if (attr->def.type != mqi_string && attr->def.type != mqi_integer &&
2566 attr->def.type != mqi_unsignd && attr->def.type != mqi_floating)
2568 luaL_error(L, "invalid attribute type %d for '%s'",
2569 attr->def.type, fldnam);
2571 if (attr->def.type == mqi_unsignd && attr->def.value.integer < 0) {
2572 luaL_error(L, "attempt to give negative value (%d) for field '%s'",
2573 attr->def.value.integer, fldnam);
2580 static void attributes_destroy(attribute_t *attrs)
2585 for (attr = attrs; attr->prop && attr->def.name; attr++) {
2586 pa_xfree((void *)attr->prop);
2587 pa_xfree((void *)attr->def.name);
2588 if (attr->def.type == mqi_string)
2589 pa_xfree((void *)attr->def.value.string);
2595 static map_t *map_check(lua_State *L, int tbl)
2601 map_t *m, *map = NULL;
2605 pa_nodeset_resdef *rd;
2607 tbl = (tbl < 0) ? lua_gettop(L) + tbl + 1 : tbl;
2609 luaL_checktype(L, tbl, LUA_TTABLE);
2611 MRP_LUA_FOREACH_FIELD(L, tbl, name, namlen) {
2613 luaL_error(L, "invalid role or binary definition");
2615 map = pa_xrealloc(map, sizeof(map_t) * (n + 2));
2616 memset(map + n, 0, sizeof(map_t) * 2);
2619 def = lua_gettop(L);
2621 m->name = pa_xstrdup(name);
2623 switch (lua_type(L, -1)) {
2632 if ((len = luaL_getn(L, def)) < 1)
2633 luaL_error(L, "invalid resource definition '%s'", name);
2635 for (i = 1; i <= len; i++) {
2636 lua_pushnumber(L, (int)i);
2637 lua_gettable(L, def);
2640 priority = luaL_checkint(L, -1);
2642 if (priority < 0 || priority > 7) {
2643 luaL_error(L, "invalid priority %d for '%s'",
2647 m->resource.priority = priority;
2650 flag = luaL_checkstring(L, -1);
2653 if (pa_streq(flag, "autorelease"))
2654 rd->flags.rset |= RESPROTO_RSETFLAG_AUTORELEASE;
2655 else if (pa_streq(flag, "mandatory"))
2656 rd->flags.audio |= RESPROTO_RESFLAG_MANDATORY;
2657 else if (pa_streq(flag, "shared"))
2658 rd->flags.audio |= RESPROTO_RESFLAG_SHARED;
2659 else if (!pa_streq(flag, "optional") &&
2660 !pa_streq(flag, "exclusive") )
2662 luaL_error(L, "invalid flag '%s' for '%s'", flag,name);
2672 luaL_error(L, "invalid resource specification. "
2673 "Should be either 'no_resource' or a table");
2676 } /* FOREACH_FIELD */
2681 static int map_push(lua_State *L, map_t *map)
2690 for (m = map; m->name; m++) {
2692 lua_pushnumber(L, 0);
2695 lua_pushinteger(L, m->resource.priority);
2696 if (m->resource.flags.rset & RESPROTO_RSETFLAG_AUTORELEASE)
2697 lua_pushstring(L, "autorelease");
2698 if (m->resource.flags.audio & RESPROTO_RESFLAG_MANDATORY)
2699 lua_pushstring(L, "mandatory");
2701 lua_pushstring(L, "optional");
2702 if (m->resource.flags.audio & RESPROTO_RESFLAG_SHARED)
2703 lua_pushstring(L, "shared");
2705 lua_pushstring(L, "exclusive");
2707 lua_setfield(L, -2, m->name);
2714 static void map_destroy(map_t *map)
2719 for (m = map; m->name; m++) {
2720 pa_xfree((void *)m->name);
2727 static field_t field_check(lua_State *L, int idx, const char **ret_fldnam)
2733 if (!(fldnam = lua_tolstring(L, idx, &fldnamlen)))
2736 fldtyp = field_name_to_type(fldnam, fldnamlen);
2739 *ret_fldnam = fldnam;
2744 static field_t field_name_to_type(const char *name, size_t len)
2751 if (!strcmp(name, "name"))
2755 if (!strcmp(name, "type"))
2759 if (!strcmp(name, "zone"))
2770 if (!strcmp(name, "class"))
2774 if (!strcmp(name, "input"))
2778 if (!strcmp(name, "limit"))
2782 if (!strcmp(name, "route"))
2784 if (!strcmp(name, "roles"))
2788 if (!strcmp(name, "table"))
2799 if (!strcmp(name, "accept"))
2803 if (!strcmp(name, "maxrow"))
2807 if (!strcmp(name, "output"))
2811 if (!strcmp(name, "tables"))
2815 if (!strcmp(name, "update"))
2826 if (!strcmp(name, "compare"))
2828 if (!strcmp(name, "columns"))
2832 if (!strcmp(name, "privacy"))
2843 if (!strcmp(name, "binaries"))
2847 if (!strcmp(name, "channels"))
2851 if (!strcmp(name, "location"))
2855 if (!strcmp(name, "priority"))
2866 if (!strcmp(name, "available"))
2870 if (!strcmp(name, "calculate"))
2872 if (!strcmp(name, "condition"))
2876 if (!strcmp(name, "direction"))
2880 if (!strcmp(name, "implement"))
2884 if (!strcmp(name, "node_type"))
2893 if (!strcmp(name, "attributes"))
2898 if (!strcmp(name, "autorelease"))
2900 if (!strcmp(name, "description"))
2911 static int make_id(char *buf, size_t len, const char *fmt, ...)
2918 l = vsnprintf(buf, len, fmt, ap);
2921 for (p = buf; (c = *p); p++) {
2924 else if (!isdigit(c))
2933 static void setup_murphy_interface(struct userdata *u)
2935 pa_scripting *scripting;
2936 scripting_import *imp;
2940 pa_bool_t need_domainctl;
2942 const char *columns;
2949 pa_assert_se((scripting = u->scripting));
2950 pa_assert_se((L = scripting->L));
2952 top = lua_gettop(L);
2954 mrp_lua_get_class_table(L, IMPORT_CLASS);
2955 class = lua_gettop(L);
2957 if (!lua_istable(L, class)){
2958 luaL_error(L, "internal error: failed to find '%s' table",
2959 (IMPORT_CLASS)->constructor);
2962 need_domainctl = FALSE;
2965 while (lua_next(L, class)) {
2966 if (lua_isstring(L, -2)) {
2967 if ((imp = mrp_lua_to_object(L, IMPORT_CLASS, -1))) {
2968 key = lua_tostring(L, -2);
2970 pa_assert(!strcmp(key, imp->table));
2971 pa_assert_se((values = imp->values));
2973 pa_log_debug("adding import '%s'", imp->table);
2975 need_domainctl = TRUE;
2976 columns = comma_separated_list(imp->columns, buf,sizeof(buf));
2978 pa_murphyif_add_watch(u, imp->table, columns, imp->condition,
2986 pa_murphyif_setup_domainctl(u, import_data_changed);
2990 MRP_LUA_LEAVE_NOARG;
2994 static char *comma_separated_list(mrp_lua_strarray_t *arr, char *buf, int len)
3003 for (i = 0, e = (p = buf) + len; i < arr->nstring && p < e; i++)
3004 p += snprintf(p, e-p, "%s%s", (p == buf ? "" : ","), arr->strings[i]);
3006 return (p < e) ? buf : NULL;
3010 static bool define_constants(lua_State *L)
3012 static const_def_t mdb_const[] = {
3013 { "string" , mqi_string },
3014 { "integer" , mqi_integer },
3015 { "unsigned" , mqi_unsignd },
3016 { "floating" , mqi_floating },
3020 static const_def_t node_const[] = {
3021 { "input" , mir_input },
3022 { "output" , mir_output },
3023 { "device" , mir_device },
3024 { "stream" , mir_stream },
3025 { "internal" , mir_internal },
3026 { "external" , mir_external },
3027 { "radio" , mir_radio },
3028 { "player" , mir_player },
3029 { "navigator" , mir_navigator },
3030 { "game" , mir_game },
3031 { "browser" , mir_browser },
3032 { "camera" , mir_camera },
3033 { "phone" , mir_phone },
3034 { "alert" , mir_alert },
3035 { "event" , mir_event },
3036 { "system" , mir_system },
3037 { "speakers" , mir_speakers },
3038 { "microphone" , mir_microphone },
3039 { "jack" , mir_jack },
3040 { "spdif" , mir_spdif },
3041 { "hdmi" , mir_hdmi },
3042 { "wired_headset" , mir_wired_headset },
3043 { "wired_headphone" , mir_wired_headphone },
3044 { "usb_headset" , mir_usb_headset },
3045 { "usb_headphone" , mir_usb_headphone },
3046 { "bluetooth_sco" , mir_bluetooth_sco },
3047 { "bluetooth_a2dp" , mir_bluetooth_a2dp },
3048 { "bluetooth_carkit" , mir_bluetooth_carkit },
3049 { "bluetooth_source" , mir_bluetooth_source },
3050 { "bluetooth_sink" , mir_bluetooth_sink },
3054 static const_def_t vollim_const[] = {
3055 { "class" , vollim_class },
3056 { "generic" , vollim_generic },
3061 bool success = true;
3064 lua_getglobal(L, "mdb");
3066 if (!lua_istable(L, -1))
3069 for (cd = mdb_const; cd->name; cd++) {
3070 lua_pushstring(L, cd->name);
3071 lua_pushinteger(L, cd->value);
3079 lua_getglobal(L, "node");
3081 if (!lua_istable(L, -1))
3084 for (cd = node_const; cd->name; cd++) {
3085 lua_pushstring(L, cd->name);
3086 lua_pushinteger(L, cd->value);
3093 lua_getglobal(L, "volume_limit");
3095 if (!lua_istable(L, -1))
3098 for (cd = vollim_const; cd->name; cd++) {
3099 lua_pushstring(L, cd->name);
3100 lua_pushinteger(L, cd->value);
3106 lua_pushnumber(L, 0);
3107 lua_setglobal(L, "no_resource");
3113 static bool register_methods(lua_State *L)
3115 static funcbridge_def_t funcbridge_defs[] = {
3116 {"make_routes" ,"o" , update_bridge ,mir_router_make_routing },
3117 {"make_volumes" ,"o" , update_bridge ,mir_volume_make_limiting },
3118 {"accept_default" ,"oo" , accept_bridge ,mir_router_default_accept },
3119 {"compare_default","ooo", compare_bridge ,mir_router_default_compare},
3120 {"accept_phone" ,"oo" , accept_bridge ,mir_router_phone_accept },
3121 {"compare_phone" ,"ooo", compare_bridge ,mir_router_phone_compare },
3122 {"volume_supress" ,"odo", calculate_bridge,mir_volume_suppress },
3123 {"volume_correct" ,"odo", calculate_bridge,mir_volume_correction },
3124 { NULL , NULL, NULL , NULL }
3127 funcbridge_def_t *d;
3128 bool success = true;
3130 for (d = funcbridge_defs; d->name; d++) {
3131 if (!mrp_funcbridge_create_cfunc(L,d->name,d->sign,d->func,d->data)) {
3132 pa_log("%s: failed to register builtin function '%s'",
3143 static void *alloc(void *ud, void *ptr, size_t osize, size_t nsize)
3151 mem = pa_xrealloc(ptr, nsize);
3160 static int panic(lua_State *L)
3164 pa_log("PANIC: unprotected error in call to Lua API (%s)",
3165 lua_tostring(L,-1));
3174 * indent-tabs-mode: nil