2 * Module-murphy-ivi -- PulseAudio module for providing audio routing support
3 * Copyright (c) 2012, Intel Corporation.
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU Lesser General Public License,
7 * version 2.1, as published by the Free Software Foundation.
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.
12 * See the GNU Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this program; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St - Fifth Floor, Boston,
26 #include <pulsecore/pulsecore-config.h>
27 #include <pulsecore/core-util.h>
29 #include <murphy/common/macros.h>
30 #include <murphy/common/mm.h>
31 #include <murphy/core/lua-utils/object.h>
32 #include <murphy/core/lua-utils/funcbridge.h>
33 #include <murphy/core/lua-utils/strarray.h>
34 #include <murphy/core/lua-utils/funcbridge.h>
35 #include <murphy/domain-control/client.h>
36 #include <murphy/resource/data-types.h>
37 #include <murphy/resource/protocol.h>
39 #include "scripting.h"
45 #include "murphy-config.h"
47 #define IMPORT_CLASS MRP_LUA_CLASS(mdb, import)
48 #define NODE_CLASS MRP_LUA_CLASS(node, instance)
49 #define ZONE_CLASS MRP_LUA_CLASS_SIMPLE(zone)
50 #define RESOURCE_CLASS MRP_LUA_CLASS_SIMPLE(audio_resource)
51 #define RTGROUP_CLASS MRP_LUA_CLASS_SIMPLE(routing_group)
52 #define APPLICATION_CLASS MRP_LUA_CLASS_SIMPLE(application_class)
53 #define VOLLIM_CLASS MRP_LUA_CLASS_SIMPLE(volume_limit)
55 #define ARRAY_CLASSID MRP_LUA_CLASSID_ROOT "mdb_array"
57 #define USERDATA "murphy_ivi_userdata"
60 #define MRP_LUA_ENTER \
61 pa_log_debug("%s() enter", __FUNCTION__)
64 #define MRP_LUA_LEAVE(_v) \
66 pa_log_debug("%s() leave (%d)", __FUNCTION__, (_v)); \
70 #undef MRP_LUA_LEAVE_NOARG
71 #define MRP_LUA_LEAVE_NOARG \
72 pa_log_debug("%s() leave", __FUNCTION__)
74 typedef void (*update_func_t)(struct userdata *);
81 struct scripting_import {
82 struct userdata *userdata;
84 mrp_lua_strarray_t *columns;
85 const char *condition;
87 mrp_funcbridge_t *update;
90 struct scripting_node {
91 struct userdata *userdata;
97 const char *recording;
107 struct scripting_zone {
108 struct userdata *userdata;
113 struct scripting_resource {
114 struct userdata *userdata;
115 resource_name_t *name;
116 attribute_t *attributes;
119 struct scripting_rtgroup {
120 struct userdata *userdata;
123 mrp_funcbridge_t *accept;
124 mrp_funcbridge_t *compare;
136 pa_nodeset_resdef resource;
139 struct scripting_apclass {
140 struct userdata *userdata;
169 struct scripting_vollim {
170 struct userdata *userdata;
175 mrp_funcbridge_t *calculate;
188 mrp_funcbridge_cfunc_t func;
225 static int import_create(lua_State *);
226 static int import_getfield(lua_State *);
227 static int import_setfield(lua_State *);
228 static int import_tostring(lua_State *);
229 static void import_destroy(void *);
231 static int import_link(lua_State *);
233 static void import_data_changed(struct userdata *, const char *,
234 int, mrp_domctl_value_t **);
235 static bool update_bridge(lua_State *, void *, const char *,
236 mrp_funcbridge_value_t *, char *,
237 mrp_funcbridge_value_t *);
239 static void array_class_create(lua_State *);
240 static pa_value *array_create(lua_State *, int, mrp_lua_strarray_t *);
241 static int array_getfield(lua_State *);
242 static int array_setfield(lua_State *);
243 static int array_getlength(lua_State *);
246 static void array_destroy(void *);
249 static int node_create(lua_State *);
250 static int node_getfield(lua_State *);
251 static int node_setfield(lua_State *);
252 static int node_tostring(lua_State *);
253 static void node_destroy(void *);
255 static int zone_create(lua_State *);
256 static int zone_getfield(lua_State *);
257 static int zone_setfield(lua_State *);
258 static void zone_destroy(void *);
260 static int resource_create(lua_State *);
261 static int resource_getfield(lua_State *);
262 static int resource_setfield(lua_State *);
263 static void resource_destroy(void *);
265 static int rtgroup_create(lua_State *);
266 static int rtgroup_getfield(lua_State *);
267 static int rtgroup_setfield(lua_State *);
268 static int rtgroup_tostring(lua_State *);
269 static void rtgroup_destroy(void *);
271 static bool rtgroup_accept(struct userdata *, mir_rtgroup *, mir_node *);
272 static int rtgroup_compare(struct userdata *, mir_rtgroup *,
273 mir_node *, mir_node *);
275 static bool accept_bridge(lua_State *, void *, const char *,
276 mrp_funcbridge_value_t *, char *,
277 mrp_funcbridge_value_t *);
278 static bool compare_bridge(lua_State *, void *, const char *,
279 mrp_funcbridge_value_t *, char *,
280 mrp_funcbridge_value_t *);
282 static int apclass_create(lua_State *);
283 static int apclass_getfield(lua_State *);
284 static int apclass_setfield(lua_State *);
285 static int apclass_tostring(lua_State *);
286 static void apclass_destroy(void *);
288 static route_t *route_check(lua_State *, int);
289 static int route_push(lua_State *, route_t *);
290 static void route_destroy(route_t *);
292 static int vollim_create(lua_State *);
293 static int vollim_getfield(lua_State *);
294 static int vollim_setfield(lua_State *);
295 static int vollim_tostring(lua_State *);
296 static void vollim_destroy(void *);
298 static double vollim_calculate(struct userdata *, int, mir_node *, void *);
299 static bool calculate_bridge(lua_State *, void *, const char *,
300 mrp_funcbridge_value_t *, char *,
301 mrp_funcbridge_value_t *);
303 static limit_data_t *limit_data_check(lua_State *, int);
306 static int limit_data_push(lua_State *, limit_data_t *);
309 static void limit_data_destroy(limit_data_t *);
311 static intarray_t *intarray_check(lua_State *, int, int, int);
312 static int intarray_push(lua_State *, intarray_t *);
313 static void intarray_destroy(intarray_t *);
315 static resource_name_t *resource_names_check(lua_State *, int);
316 static void resource_names_destroy(resource_name_t *);
318 static attribute_t *attributes_check(lua_State *, int);
319 static void attributes_destroy(attribute_t *);
321 static map_t *map_check(lua_State *, int);
322 static int map_push(lua_State *, map_t *);
323 static void map_destroy(map_t *);
325 static field_t field_check(lua_State *, int, const char **);
326 static field_t field_name_to_type(const char *, size_t);
327 static int make_id(char *buf, size_t len, const char *fmt, ...);
329 static void setup_murphy_interface(struct userdata *);
330 static char *comma_separated_list(mrp_lua_strarray_t *, char *, int);
332 static bool define_constants(lua_State *);
333 static bool register_methods(lua_State *);
335 static void *alloc(void *, void *, size_t, size_t);
336 static int panic(lua_State *);
339 MRP_LUA_METHOD_LIST_TABLE (
340 import_methods, /* methodlist name */
341 MRP_LUA_METHOD_CONSTRUCTOR (import_create)
342 MRP_LUA_METHOD (link, import_link )
345 MRP_LUA_METHOD_LIST_TABLE (
346 node_methods, /* methodlist name */
347 MRP_LUA_METHOD_CONSTRUCTOR (node_create)
351 MRP_LUA_METHOD_LIST_TABLE (
352 import_overrides, /* methodlist_name */
353 MRP_LUA_OVERRIDE_CALL (import_create)
354 MRP_LUA_OVERRIDE_GETFIELD (import_getfield)
355 MRP_LUA_OVERRIDE_SETFIELD (import_setfield)
356 MRP_LUA_OVERRIDE_STRINGIFY (import_tostring)
359 MRP_LUA_METHOD_LIST_TABLE (
360 array_overrides, /* methodlist_name */
361 MRP_LUA_OVERRIDE_GETFIELD (array_getfield)
362 MRP_LUA_OVERRIDE_SETFIELD (array_setfield)
363 MRP_LUA_OVERRIDE_GETLENGTH (array_getlength)
366 MRP_LUA_METHOD_LIST_TABLE (
367 node_overrides, /* methodlist name */
368 MRP_LUA_OVERRIDE_CALL (node_create)
369 MRP_LUA_OVERRIDE_GETFIELD (node_getfield)
370 MRP_LUA_OVERRIDE_SETFIELD (node_setfield)
371 MRP_LUA_OVERRIDE_STRINGIFY (node_tostring)
376 mdb, /* class name */
377 import, /* constructor name */
378 scripting_import, /* userdata type */
379 import_destroy, /* userdata destructor */
380 import_methods, /* class methods */
381 import_overrides /* override methods */
385 node, /* class name */
386 instance, /* constructor name */
387 scripting_node, /* userdata type */
388 node_destroy, /* userdata destructor */
389 node_methods, /* class methods */
390 node_overrides /* override methods */
393 MRP_LUA_CLASS_DEF_SIMPLE (
394 zone, /* class name */
395 scripting_zone, /* userdata type */
396 zone_destroy, /* userdata destructor */
397 MRP_LUA_METHOD_LIST ( /* methods */
398 MRP_LUA_METHOD_CONSTRUCTOR (zone_create)
400 MRP_LUA_METHOD_LIST ( /* overrides */
401 MRP_LUA_OVERRIDE_CALL (zone_create)
402 MRP_LUA_OVERRIDE_GETFIELD (zone_getfield)
403 MRP_LUA_OVERRIDE_SETFIELD (zone_setfield)
407 MRP_LUA_CLASS_DEF_SIMPLE (
408 audio_resource, /* class name */
409 scripting_resource, /* userdata type */
410 resource_destroy, /* userdata destructor */
411 MRP_LUA_METHOD_LIST ( /* methods */
412 MRP_LUA_METHOD_CONSTRUCTOR (resource_create)
414 MRP_LUA_METHOD_LIST ( /* overrides */
415 MRP_LUA_OVERRIDE_CALL (resource_create)
416 MRP_LUA_OVERRIDE_GETFIELD (resource_getfield)
417 MRP_LUA_OVERRIDE_SETFIELD (resource_setfield)
421 MRP_LUA_CLASS_DEF_SIMPLE (
422 routing_group, /* class name */
423 scripting_rtgroup, /* userdata type */
424 rtgroup_destroy, /* userdata destructor */
425 MRP_LUA_METHOD_LIST ( /* methods */
426 MRP_LUA_METHOD_CONSTRUCTOR (rtgroup_create)
428 MRP_LUA_METHOD_LIST ( /* overrides */
429 MRP_LUA_OVERRIDE_CALL (rtgroup_create)
430 MRP_LUA_OVERRIDE_GETFIELD (rtgroup_getfield)
431 MRP_LUA_OVERRIDE_SETFIELD (rtgroup_setfield)
432 MRP_LUA_OVERRIDE_STRINGIFY (rtgroup_tostring)
436 MRP_LUA_CLASS_DEF_SIMPLE (
437 application_class, /* class name */
438 scripting_apclass, /* userdata type */
439 apclass_destroy, /* userdata destructor */
440 MRP_LUA_METHOD_LIST ( /* methods */
441 MRP_LUA_METHOD_CONSTRUCTOR (apclass_create)
443 MRP_LUA_METHOD_LIST ( /* overrides */
444 MRP_LUA_OVERRIDE_CALL (apclass_create)
445 MRP_LUA_OVERRIDE_GETFIELD (apclass_getfield)
446 MRP_LUA_OVERRIDE_SETFIELD (apclass_setfield)
447 MRP_LUA_OVERRIDE_STRINGIFY (apclass_tostring)
451 MRP_LUA_CLASS_DEF_SIMPLE (
452 volume_limit, /* class name */
453 scripting_vollim, /* userdata type */
454 vollim_destroy, /* userdata destructor */
455 MRP_LUA_METHOD_LIST ( /* methods */
456 MRP_LUA_METHOD_CONSTRUCTOR (vollim_create)
458 MRP_LUA_METHOD_LIST ( /* overrides */
459 MRP_LUA_OVERRIDE_CALL (vollim_create)
460 MRP_LUA_OVERRIDE_GETFIELD (vollim_getfield)
461 MRP_LUA_OVERRIDE_SETFIELD (vollim_setfield)
462 MRP_LUA_OVERRIDE_STRINGIFY (vollim_tostring)
467 pa_scripting *pa_scripting_init(struct userdata *u)
469 pa_scripting *scripting;
474 scripting = pa_xnew0(pa_scripting, 1);
476 if (!(L = lua_newstate(alloc, u)))
477 pa_log("failed to initialize Lua");
479 lua_atpanic(L, &panic);
482 mrp_create_funcbridge_class(L);
483 mrp_lua_create_object_class(L, IMPORT_CLASS);
484 mrp_lua_create_object_class(L, NODE_CLASS);
485 mrp_lua_create_object_class(L, ZONE_CLASS);
486 mrp_lua_create_object_class(L, RESOURCE_CLASS);
487 mrp_lua_create_object_class(L, RTGROUP_CLASS);
488 mrp_lua_create_object_class(L, APPLICATION_CLASS);
489 mrp_lua_create_object_class(L, VOLLIM_CLASS);
491 array_class_create(L);
496 lua_pushlightuserdata(L, u);
497 lua_setglobal(L, USERDATA);
500 scripting->configured = false;
506 void pa_scripting_done(struct userdata *u)
508 pa_scripting *scripting;
510 if (u && (scripting = u->scripting)) {
516 bool pa_scripting_dofile(struct userdata *u, const char *file)
518 pa_scripting *scripting;
525 pa_assert_se((scripting = u->scripting));
526 pa_assert_se((L = scripting->L));
528 if (luaL_loadfile(L, file) || lua_pcall(L, 0, 0, 0)) {
530 pa_log("%s", lua_tostring(L, -1));
535 scripting->configured = true;
536 setup_murphy_interface(u);
537 pa_zoneset_update_module_property(u);
543 static int import_create(lua_State *L)
546 pa_scripting *scripting;
549 scripting_import *imp;
550 const char *table = NULL;
551 mrp_lua_strarray_t *columns = NULL;
552 const char *condition = NULL;
554 mrp_funcbridge_t *update = NULL;
565 lua_getglobal(L, USERDATA);
566 if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
567 luaL_error(L, "missing or invalid global '" USERDATA "'");
569 pa_assert_se((scripting = u->scripting));
571 MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
573 switch (field_name_to_type(fldnam, fldnamlen)) {
574 case TABLE: table = luaL_checkstring(L, -1); break;
575 case COLUMNS: columns = mrp_lua_check_strarray(L, -1); break;
576 case CONDITION: condition = luaL_checkstring(L, -1); break;
577 case MAXROW: maxrow = luaL_checkint(L, -1); break;
578 case UPDATE: update = mrp_funcbridge_create_luafunc(L, -1); break;
579 default: luaL_error(L, "bad field '%s'", fldnam); break;
582 } /* MRP_LUA_FOREACH_FIELD */
587 luaL_error(L, "missing table field");
589 luaL_error(L, "missing columns field");
590 if (maxrow < 1 || maxrow >= MQI_QUERY_RESULT_MAX)
591 luaL_error(L, "missing or invalid maxrow field");
593 luaL_error(L, "missing update function");
595 maxcol = columns->nstring;
597 if (maxcol >= MQI_COLUMN_MAX)
598 luaL_error(L, "too many columns (max %d allowed)", MQI_COLUMN_MAX);
600 if (scripting->configured)
601 luaL_error(L, "refuse to import '%s' after configuration phase",table);
603 imp = (scripting_import *)mrp_lua_create_object(L, IMPORT_CLASS, table,0);
606 imp->table = pa_xstrdup(table);
607 imp->columns = columns;
608 imp->condition = condition;
609 imp->values = array_create(L, maxrow, NULL);
610 imp->update = update;
612 for (i = 0, rows = imp->values->array; i < maxrow; i++) {
613 cols = (rows[i] = array_create(L, maxcol, columns))->array;
614 lua_rawseti(L, -3, i+1); /* we add this to the import */
615 for (j = 0; j < maxcol; j++)
616 cols[j] = pa_xnew0(pa_value, 1);
619 lua_rawseti(L, -2, MQI_QUERY_RESULT_MAX);
624 static int import_getfield(lua_State *L)
626 scripting_import *imp;
633 if (!(imp = (scripting_import *)mrp_lua_check_object(L, IMPORT_CLASS, 1)))
636 pa_assert_se((values = imp->values));
638 if (lua_type(L, 2) == LUA_TNUMBER) {
639 colidx = lua_tointeger(L, 2);
641 if (colidx < 1 || colidx > -values->type)
644 lua_rawgeti(L, 1, colidx);
647 fld = field_check(L, 2, NULL);
651 case TABLE: lua_pushstring(L, imp->table); break;
652 case COLUMNS: mrp_lua_push_strarray(L, imp->columns); break;
653 case CONDITION: lua_pushstring(L, imp->condition); break;
654 case MAXROW: lua_pushinteger(L, -imp->values->type); break;
655 default: lua_pushnil(L); break;
663 static int import_setfield(lua_State *L)
669 f = luaL_checkstring(L, 2);
670 luaL_error(L, "attempt to set '%s' field of read-only mdb.import", f);
675 static int import_tostring(lua_State *L)
677 scripting_import *imp;
681 imp = (scripting_import *)mrp_lua_check_object(L, IMPORT_CLASS, 1);
683 lua_pushstring(L, imp->table);
688 static void import_destroy(void *data)
690 scripting_import *imp = (scripting_import *)data;
694 pa_xfree((void *)imp->table);
695 mrp_lua_free_strarray(imp->columns);
696 pa_xfree((void *)imp->condition);
701 static int import_link(lua_State *L)
703 scripting_import *imp;
704 mrp_lua_strarray_t *columns;
714 imp = (scripting_import *)mrp_lua_check_object(L, IMPORT_CLASS, 1);
715 rowidx = luaL_checkint(L, 2) - 1;
716 colnam = luaL_checkstring(L, 3);
719 pa_assert_se((columns = imp->columns));
723 if (rowidx >= 0 && rowidx < -imp->values->type) {
724 for (colidx = 0; colidx < columns->nstring; colidx++) {
725 if (!strcmp(colnam, columns->strings[colidx])) {
726 pa_assert_se((values = imp->values));
727 pa_assert_se((row = values->array[rowidx]));
728 pa_assert(colidx < (size_t)-row->type);
729 pa_assert_se((col = row->array[colidx]));
735 pa_log_debug("userdata: type:%d", col->type);
737 lua_pushlightuserdata(L, col);
742 static void import_data_changed(struct userdata *u,
745 mrp_domctl_value_t **mval)
747 static mrp_domctl_value_t empty;
749 pa_scripting *scripting;
751 scripting_import *imp;
752 mrp_domctl_value_t *mrow;
753 mrp_domctl_value_t *mcol;
754 pa_value *ptval, *prval, *pcval;
759 mrp_funcbridge_value_t arg;
760 mrp_funcbridge_value_t ret;
766 pa_assert(mval || nrow == 0);
767 pa_assert_se((scripting = u->scripting));
768 pa_assert_se((L = scripting->L));
770 pa_log_debug("table '%s' data changed: got %d rows", table, nrow);
772 mrp_lua_get_class_table(L, IMPORT_CLASS);
774 if (!lua_istable(L, -1)){
775 luaL_error(L, "internal error: failed to find '%s' table",
776 (IMPORT_CLASS)->constructor);
779 lua_pushstring(L, table);
782 if (!(imp = mrp_lua_to_object(L, IMPORT_CLASS, -1)))
783 pa_log("can't find import '%s'", table);
785 pa_assert(!strcmp(table, imp->table));
786 pa_assert(imp->columns);
787 pa_assert(imp->update);
788 pa_assert_se((ptval = imp->values));
789 pa_assert_se((prow = ptval->array));
791 maxrow = -ptval->type;
792 maxcol = imp->columns->nstring;
794 pa_assert(maxrow >= 0);
795 pa_assert(nrow <= maxrow);
797 pa_log_debug("import '%s' found", imp->table);
799 for (i = 0; i < maxrow; i++) {
800 pa_assert_se((prval = prow[i]));
801 pa_assert_se((pcol = prval->array));
802 pa_assert(prval->type < 0);
803 pa_assert(maxcol == -prval->type);
805 mrow = (i < nrow) ? mval[i] : NULL;
807 for (j = 0; j < maxcol; j++) {
809 mcol = mrow ? mrow + j : ∅
811 switch (mcol->type) {
812 case MRP_DOMCTL_STRING:
813 pa_assert(!pcval->type || pcval->type == pa_value_string);
814 pa_xfree((void *)pcval->string);
815 pcval->type = pa_value_string;
816 pcval->string = pa_xstrdup(mcol->str);
818 case MRP_DOMCTL_INTEGER:
819 pa_assert(!pcval->type || pcval->type == pa_value_integer);
820 pcval->type = pa_value_integer;
821 pcval->integer = mcol->s32;
823 case MRP_DOMCTL_UNSIGNED:
824 pa_assert(!pcval->type || pcval->type == pa_value_unsignd);
825 pcval->type = pa_value_unsignd;
826 pcval->unsignd = mcol->u32;
828 case MRP_DOMCTL_DOUBLE:
829 pa_assert(!pcval->type || pcval->type ==pa_value_floating);
830 pcval->type = pa_value_floating;
831 pcval->floating = mcol->dbl;
834 if (pcval->type == pa_value_string)
835 pa_xfree((void *)pcval->string);
836 memset(pcval, 0, sizeof(pa_value));
844 if (!mrp_funcbridge_call_from_c(L, imp->update, "o", &arg, &t, &ret)) {
845 pa_log("failed to call %s:update method (%s)",
846 imp->table, ret.string);
847 pa_xfree((void *)ret.string);
855 static bool update_bridge(lua_State *L, void *data, const char *signature,
856 mrp_funcbridge_value_t *args,
857 char *ret_type, mrp_funcbridge_value_t *ret_val)
859 update_func_t update;
860 scripting_import *imp;
866 pa_assert(signature);
871 pa_assert_se((update = (update_func_t)data));
873 if (strcmp(signature, "o"))
876 pa_assert_se((imp = args[0].pointer));
877 pa_assert_se((u = imp->userdata));
880 *ret_type = MRP_FUNCBRIDGE_NO_DATA;
881 memset(ret_val, 0, sizeof(mrp_funcbridge_value_t));
890 static void array_class_create(lua_State *L)
892 /* create a metatable for row's */
893 luaL_newmetatable(L, ARRAY_CLASSID);
894 lua_pushliteral(L, "__index");
895 lua_pushvalue(L, -2);
896 lua_settable(L, -3); /* metatable.__index = metatable */
897 luaL_openlib(L, NULL, array_overrides, 0);
901 static pa_value *array_create(lua_State *L, int dimension,
902 mrp_lua_strarray_t *names)
908 pa_assert(dimension >= 0);
909 pa_assert(dimension < MQI_QUERY_RESULT_MAX);
911 array = pa_xnew0(pa_value *, dimension + 1);
912 value = lua_newuserdata(L, sizeof(pa_value));
913 value->type = -dimension;
914 value->array = array;
916 array[dimension] = (pa_value *)names;
918 luaL_getmetatable(L, ARRAY_CLASSID);
919 lua_setmetatable(L, -2);
924 static int array_getfield(lua_State *L)
926 pa_value *arr, *value;
930 mrp_lua_strarray_t *names;
938 arr = (pa_value *)luaL_checkudata(L, 1, ARRAY_CLASSID);
940 pa_assert(arr->type < 0);
942 dimension = -arr->type;
943 key_type = lua_type(L, 2);
947 idx = lua_tointeger(L, 2) - 1;
951 if ((names = (mrp_lua_strarray_t *)arr->array[dimension])) {
952 pa_assert(dimension == names->nstring);
953 key = lua_tostring(L, 2);
955 for (i = 0; i < dimension; i++) {
956 if (!strcmp(key, names->strings[i])) {
969 if (idx < 0 || idx >= dimension || !(value = arr->array[idx]))
971 else if (value->type < 0)
972 lua_rawgeti(L, 1, 1 - value->type);
974 switch (value->type) {
975 case pa_value_string: lua_pushstring(L, value->string); break;
976 case pa_value_integer: lua_pushinteger(L, value->integer); break;
977 case pa_value_unsignd: lua_pushinteger(L, value->unsignd); break;
978 case pa_value_floating: lua_pushnumber(L, value->floating); break;
979 default: lua_pushnil(L); break;
986 static int array_setfield(lua_State *L)
992 luaL_error(L, "attempt to write to a read-only object");
997 static int array_getlength(lua_State *L)
1007 static void array_destroy(void *data)
1009 pa_value *value = (pa_value *)data;
1014 pa_assert(value->type < 0);
1015 pa_xfree(value->array);
1018 MRP_LUA_LEAVE_NOARG;
1022 scripting_node *pa_scripting_node_create(struct userdata *u, mir_node *node)
1024 pa_scripting *scripting;
1031 pa_assert(node->amname);
1033 pa_assert_se((scripting = u->scripting));
1034 pa_assert_se((L = scripting->L));
1036 make_id(id, sizeof(id), "%s_%d", node->amname, node->index);
1038 if ((sn = (scripting_node *)mrp_lua_create_object(L, NODE_CLASS, id,0))) {
1040 sn->id = pa_xstrdup(id);
1047 void pa_scripting_node_destroy(struct userdata *u, mir_node *node)
1049 pa_scripting *scripting;
1058 pa_assert_se((scripting = u->scripting));
1059 pa_assert_se((L = scripting->L));
1061 if ((sn = node->scripting)) {
1062 mrp_lua_destroy_object(L, sn->id,0, sn);
1064 node->scripting = NULL;
1067 MRP_LUA_LEAVE_NOARG;
1070 static int node_create(lua_State *L)
1079 static int node_getfield(lua_State *L)
1087 fld = field_check(L, 2, NULL);
1090 if (!(sn = (scripting_node *)mrp_lua_check_object(L, NODE_CLASS, 1)))
1093 pa_assert_se((node = sn->node));
1096 case NAME: lua_pushstring(L, node->amname); break;
1097 case DESCRIPTION: lua_pushstring(L, node->amdescr); break;
1098 case DIRECTION: lua_pushinteger(L, node->direction); break;
1099 case IMPLEMENT: lua_pushinteger(L, node->implement); break;
1100 case CHANNELS: lua_pushinteger(L, node->channels); break;
1101 case LOCATION: lua_pushinteger(L, node->location); break;
1102 case PRIVACY: lua_pushinteger(L, node->privacy); break;
1103 case ZONE: lua_pushstring(L, node->zone); break;
1104 case TYPE: lua_pushinteger(L, node->type); break;
1105 case AVAILABLE: lua_pushboolean(L, node->available); break;
1106 default: lua_pushnil(L); break;
1113 static int node_setfield(lua_State *L)
1119 f = luaL_checkstring(L, 2);
1120 luaL_error(L, "attempt to set '%s' field of read-only node", f);
1125 static int node_tostring(lua_State *L)
1131 sn = (scripting_node *)mrp_lua_check_object(L, NODE_CLASS, 1);
1133 lua_pushstring(L, (sn && sn->id) ? sn->id : "<unknown node>");
1138 static void node_destroy(void *data)
1140 scripting_node *sn = (scripting_node *)data;
1145 if ((node = sn->node) && sn == node->scripting)
1146 node->scripting = NULL;
1148 pa_xfree((void *)sn->id);
1150 MRP_LUA_LEAVE_NOARG;
1154 static int zone_create(lua_State *L)
1156 static uint32_t index;
1161 scripting_zone *zone;
1162 const char *name = NULL;
1163 attribute_t *attributes = NULL;
1167 lua_getglobal(L, USERDATA);
1168 if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
1169 luaL_error(L, "missing or invalid global '" USERDATA "'");
1173 MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
1175 switch (field_name_to_type(fldnam, fldnamlen)) {
1176 case NAME: name = luaL_checkstring(L, -1); break;
1177 case ATTRIBUTES: attributes = attributes_check(L, -1); break;
1178 default: luaL_error(L, "bad field '%s'", fldnam); break;
1181 } /* MRP_LUA_FOREACH_FIELD */
1184 luaL_error(L, "missing or invalid name field");
1186 if (pa_zoneset_add_zone(u, name, index+1))
1187 luaL_error(L, "attempt to define zone '%s' multiple times", name);
1189 zone = (scripting_zone *)mrp_lua_create_object(L, ZONE_CLASS, name, 0);
1192 zone->name = pa_xstrdup(name);
1193 zone->index = ++index;
1199 static int zone_getfield(lua_State *L)
1201 scripting_zone *zone;
1206 fld = field_check(L, 2, NULL);
1209 if (!(zone = (scripting_zone *)mrp_lua_check_object(L, ZONE_CLASS, 1)))
1213 case NAME: lua_pushstring(L, zone->name); break;
1215 case ATTRIBUTES: lua_pushinteger(L, rtgs->type); break;
1217 default: lua_pushnil(L); break;
1224 static int zone_setfield(lua_State *L)
1230 f = luaL_checkstring(L, 2);
1231 luaL_error(L, "attempt to set '%s' field of read-only zone", f);
1236 static void zone_destroy(void *data)
1238 scripting_zone *zone = (scripting_zone *)data;
1242 pa_xfree((void *)zone->name);
1246 MRP_LUA_LEAVE_NOARG;
1250 static int resource_create(lua_State *L)
1256 scripting_resource *res;
1257 resource_name_t *name = NULL;
1258 attribute_t *attributes = NULL;
1263 lua_getglobal(L, USERDATA);
1264 if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
1265 luaL_error(L, "missing or invalid global '" USERDATA "'");
1269 MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
1271 switch (field_name_to_type(fldnam, fldnamlen)) {
1272 case NAME: name = resource_names_check(L, -1); break;
1273 case ATTRIBUTES: attributes = attributes_check(L, -1); break;
1274 default: luaL_error(L, "bad field '%s'", fldnam); break;
1277 } /* MRP_LUA_FOREACH_FIELD */
1280 luaL_error(L, "missing or invalid name field");
1282 pa_murphyif_add_audio_resource(u, mir_input, name->playback);
1283 pa_murphyif_add_audio_resource(u, mir_output, name->recording);
1286 for (attr = attributes; attr->prop && attr->def.name; attr++) {
1287 switch (attr->def.type) {
1289 pa_murphyif_add_audio_attribute(u, attr->prop,
1292 attr->def.value.string);
1295 pa_murphyif_add_audio_attribute(u, attr->prop,
1298 attr->def.value.integer);
1301 pa_murphyif_add_audio_attribute(u, attr->prop,
1304 attr->def.value.unsignd);
1307 pa_murphyif_add_audio_attribute(u, attr->prop,
1310 attr->def.value.floating);
1313 luaL_error(L, "invalid audio resource attribute '%s'",
1320 res = (scripting_resource *)mrp_lua_create_object(L, RTGROUP_CLASS,
1325 res->attributes = attributes;
1330 static int resource_getfield(lua_State *L)
1332 scripting_resource *res;
1337 fld = field_check(L, 2, NULL);
1340 if (!(res = (scripting_resource*)mrp_lua_check_object(L,RESOURCE_CLASS,1)))
1345 case NAME: lua_pushstring(L, rtg->name); break;
1346 case ATTRIBUTES: lua_pushinteger(L, rtgs->type); break;
1347 default: lua_pushnil(L); break;
1357 static int resource_setfield(lua_State *L)
1363 f = luaL_checkstring(L, 2);
1364 luaL_error(L, "attempt to set '%s' field of read-only resource_class", f);
1369 static void resource_destroy(void *data)
1371 scripting_resource *res = (scripting_resource *)data;
1375 resource_names_destroy(res->name);
1376 attributes_destroy(res->attributes);
1379 res->attributes = NULL;
1381 MRP_LUA_LEAVE_NOARG;
1385 static int rtgroup_create(lua_State *L)
1391 scripting_rtgroup *rtgs;
1392 const char *name = NULL;
1393 mir_direction type = 0;
1394 mrp_funcbridge_t *accept = NULL;
1395 mrp_funcbridge_t *compare = NULL;
1400 lua_getglobal(L, USERDATA);
1401 if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
1402 luaL_error(L, "missing or invalid global '" USERDATA "'");
1406 MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
1408 switch (field_name_to_type(fldnam, fldnamlen)) {
1409 case NAME: name = luaL_checkstring(L, -1); break;
1410 case NODE_TYPE: type = luaL_checkint(L, -1); break;
1411 case ACCEPT: accept = mrp_funcbridge_create_luafunc(L, -1); break;
1412 case COMPARE: compare = mrp_funcbridge_create_luafunc(L, -1); break;
1413 default: luaL_error(L, "bad field '%s'", fldnam); break;
1416 } /* MRP_LUA_FOREACH_FIELD */
1419 luaL_error(L, "missing name field");
1420 if (type != mir_input && type != mir_output)
1421 luaL_error(L, "missing or invalid node_type");
1423 luaL_error(L, "missing or invalid accept field");
1425 luaL_error(L, "missing or invalid compare field");
1427 make_id(id,sizeof(id), "%s_%sput", name, (type == mir_input) ? "in":"out");
1429 rtgs = (scripting_rtgroup *)mrp_lua_create_object(L, RTGROUP_CLASS, id,0);
1431 rtg = mir_router_create_rtgroup(u, type, pa_xstrdup(name),
1432 rtgroup_accept, rtgroup_compare);
1434 luaL_error(L, "failed to create routing group '%s'", id);
1436 rtg->scripting = rtgs;
1441 rtgs->accept = accept;
1442 rtgs->compare = compare;
1447 static int rtgroup_getfield(lua_State *L)
1449 scripting_rtgroup *rtgs;
1455 fld = field_check(L, 2, NULL);
1458 if (!(rtgs = (scripting_rtgroup *)mrp_lua_check_object(L,RTGROUP_CLASS,1)))
1461 pa_assert_se((rtg = rtgs->rtg));
1464 case NAME: lua_pushstring(L, rtg->name); break;
1465 case NODE_TYPE: lua_pushinteger(L, rtgs->type); break;
1466 default: lua_pushnil(L); break;
1473 static int rtgroup_setfield(lua_State *L)
1479 f = luaL_checkstring(L, 2);
1480 luaL_error(L, "attempt to set '%s' field of read-only routing_group", f);
1485 static int rtgroup_tostring(lua_State *L)
1487 scripting_rtgroup *rtgs;
1492 rtgs = (scripting_rtgroup *)mrp_lua_check_object(L, RTGROUP_CLASS, 1);
1493 pa_assert_se((rtg = rtgs->rtg));
1495 lua_pushstring(L, rtg->name);
1500 static void rtgroup_destroy(void *data)
1502 scripting_rtgroup *rtgs = (scripting_rtgroup *)data;
1507 pa_assert_se((rtg = rtgs->rtg));
1508 pa_assert(rtgs == rtg->scripting);
1510 rtg->scripting = NULL;
1512 MRP_LUA_LEAVE_NOARG;
1516 static bool rtgroup_accept(struct userdata *u,
1520 pa_scripting *scripting;
1522 scripting_rtgroup *rtgs;
1523 mrp_funcbridge_value_t args[2];
1525 mrp_funcbridge_value_t rv;
1529 pa_assert_se((scripting = u->scripting));
1530 pa_assert_se((L = scripting->L));
1532 pa_assert_se((rtgs = rtg->scripting));
1533 pa_assert(u == rtgs->userdata);
1534 pa_assert(rtgs->accept);
1539 if ((rtgs = rtg->scripting) && node->scripting) {
1541 args[0].pointer = rtgs;
1542 args[1].pointer = node->scripting;
1544 if (!mrp_funcbridge_call_from_c(L, rtgs->accept, "oo",args, &rt,&rv)) {
1545 if (rt != MRP_FUNCBRIDGE_STRING)
1546 pa_log("call to accept function failed");
1548 pa_log("call to accept function failed: %s", rv.string);
1549 mrp_free((void *)rv.string);
1553 if (rt != MRP_FUNCBRIDGE_BOOLEAN)
1554 pa_log("accept function returned invalid type");
1556 accept = rv.boolean;
1563 static int rtgroup_compare(struct userdata *u,
1568 pa_scripting *scripting;
1570 scripting_rtgroup *rtgs;
1571 mrp_funcbridge_value_t args[3];
1573 mrp_funcbridge_value_t rv;
1577 pa_assert_se((scripting = u->scripting));
1578 pa_assert_se((L = scripting->L));
1580 pa_assert_se((rtgs = rtg->scripting));
1581 pa_assert(u == rtgs->userdata);
1582 pa_assert(rtgs->compare);
1588 if ((rtgs = rtg->scripting) && node1->scripting && node2->scripting) {
1590 args[0].pointer = rtgs;
1591 args[1].pointer = node1->scripting;
1592 args[2].pointer = node2->scripting;
1594 if (!mrp_funcbridge_call_from_c(L, rtgs->compare, "ooo",args, &rt,&rv))
1595 pa_log("failed to call compare function");
1597 if (rt != MRP_FUNCBRIDGE_FLOATING)
1598 pa_log("compare function returned invalid type");
1600 result = rv.floating;
1608 static bool accept_bridge(lua_State *L, void *data,
1609 const char *signature, mrp_funcbridge_value_t *args,
1610 char *ret_type, mrp_funcbridge_value_t *ret_val)
1612 mir_rtgroup_accept_t accept;
1613 scripting_rtgroup *rtgs;
1622 pa_assert(signature);
1624 pa_assert(ret_type);
1627 pa_assert_se((accept = (mir_rtgroup_accept_t)data));
1629 if (strcmp(signature, "oo"))
1632 pa_assert_se((rtgs = args[0].pointer));
1633 pa_assert_se((u = rtgs->userdata));
1634 pa_assert_se((ns = args[1].pointer));
1636 if (!(rtg = rtgs->rtg) || !(node = ns->node))
1640 *ret_type = MRP_FUNCBRIDGE_BOOLEAN;
1641 ret_val->boolean = accept(u, rtg, node);
1649 static bool compare_bridge(lua_State *L, void *data,
1650 const char *signature, mrp_funcbridge_value_t *args,
1651 char *ret_type, mrp_funcbridge_value_t *ret_val)
1653 mir_rtgroup_compare_t compare;
1654 scripting_rtgroup *rtgs;
1655 scripting_node *ns1, *ns2;
1658 mir_node *node1, *node2;
1663 pa_assert(signature);
1665 pa_assert(ret_type);
1668 pa_assert_se((compare = (mir_rtgroup_compare_t)data));
1670 if (strcmp(signature, "ooo"))
1673 pa_assert_se((rtgs = args[0].pointer));
1674 pa_assert_se((u = rtgs->userdata));
1675 pa_assert_se((ns1 = args[1].pointer));
1676 pa_assert_se((ns2 = args[2].pointer));
1679 if (!(rtg = rtgs->rtg) || !(node1 = ns1->node) || !(node2 = ns2->node))
1683 *ret_type = MRP_FUNCBRIDGE_FLOATING;
1684 ret_val->floating = compare(u, rtg, node1, node2);
1692 static int apclass_create(lua_State *L)
1697 scripting_apclass *ac;
1699 const char *class = NULL;
1700 mir_node_type type = -1;
1702 route_t *route = NULL;
1703 map_t *roles = NULL;
1704 map_t *binaries = NULL;
1705 bool needs_resource = false;
1706 pa_nodeset_resdef *resdef;
1714 lua_getglobal(L, USERDATA);
1715 if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
1716 luaL_error(L, "missing or invalid global '" USERDATA "'");
1720 MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
1722 switch (field_name_to_type(fldnam, fldnamlen)) {
1723 case CLASS: class = luaL_checkstring(L, -1); break;
1724 case NODE_TYPE: type = luaL_checkint(L, -1); break;
1725 case PRIORITY: priority = luaL_checkint(L, -1); break;
1726 case ROUTE: route = route_check(L, -1); break;
1727 case ROLES: roles = map_check(L, -1); break;
1728 case BINARIES: binaries = map_check(L, -1); break;
1729 default: luaL_error(L, "bad field '%s'", fldnam); break;
1732 } /* MRP_LUA_FOREACH_FIELD */
1734 if (type < mir_application_class_begin ||
1735 type >= mir_application_class_end )
1736 luaL_error(L, "missing or invalid node_type %d", type);
1738 luaL_error(L, "missing or invalid priority field");
1740 luaL_error(L, "missing or invalid route field");
1741 if (!roles && !binaries)
1742 luaL_error(L, "missing roles or binaries");
1744 make_id(name, sizeof(name), "%s", mir_node_type_str(type));
1746 mir_router_assign_class_priority(u, type, priority);
1751 for (i = 0; i < MRP_ZONE_MAX; i++) {
1752 if ((n = route->input[i]))
1753 ir &= mir_router_assign_class_to_rtgroup(u,type,i,mir_input,n);
1757 if (route->output) {
1758 for (i = 0; i < MRP_ZONE_MAX; i++) {
1759 if ((n = route->output[i]))
1760 or &= mir_router_assign_class_to_rtgroup(u,type,i,mir_output,n);
1764 ac = (scripting_apclass *)mrp_lua_create_object(L, APPLICATION_CLASS,
1767 if (!ir || !or || !ac)
1768 luaL_error(L, "failed to create application class '%s'", name);
1771 ac->name = pa_xstrdup(name);
1772 ac->class = class ? pa_xstrdup(class) : NULL;
1774 ac->priority = priority;
1777 ac->binaries = binaries;
1780 if (pa_nodeset_add_class(u, type, class)) {
1781 luaL_error(L, "node type '%s' is defined multiple times",
1782 mir_node_type_str(type));
1787 for (r = roles; r->name; r++) {
1788 resdef = r->needres ? &r->resource : NULL;
1790 if (r->role && strcmp(r->role, r->name)) {
1791 luaL_error(L, "conflicting roles in role definition '%s' (%s)",
1795 if (pa_nodeset_add_role(u, r->name, type, resdef)) {
1796 luaL_error(L, "role '%s' is added to mutiple application "
1797 "classes", r->name);
1803 for (b = binaries; b->name; b++) {
1804 resdef = b->needres ? &b->resource : NULL;
1806 if (pa_nodeset_add_binary(u, b->name, type, b->role, resdef)) {
1807 luaL_error(L, "binary '%s' is added to multiple application "
1808 "classes", b->name);
1816 static int apclass_getfield(lua_State *L)
1818 scripting_apclass *ac;
1823 fld = field_check(L, 2, NULL);
1826 if (!(ac=(scripting_apclass *)mrp_lua_check_object(L,APPLICATION_CLASS,1)))
1830 case NAME: lua_pushstring(L, ac->name); break;
1831 case NODE_TYPE: lua_pushinteger(L, ac->type); break;
1832 case PRIORITY: lua_pushinteger(L, ac->priority); break;
1833 case ROUTE: route_push(L, ac->route); break;
1834 case ROLES: map_push(L, ac->roles); break;
1835 case BINARIES: map_push(L, ac->binaries); break;
1836 default: lua_pushnil(L); break;
1843 static int apclass_setfield(lua_State *L)
1849 f = luaL_checkstring(L, 2);
1850 luaL_error(L,"attempt to set '%s' field of read-only application class",f);
1855 static int apclass_tostring(lua_State *L)
1857 scripting_apclass *ac;
1861 ac = (scripting_apclass *)mrp_lua_check_object(L, APPLICATION_CLASS, 1);
1863 lua_pushstring(L, ac->name);
1868 static void apclass_destroy(void *data)
1870 scripting_apclass *ac = (scripting_apclass *)data;
1878 pa_assert_se((u = ac->userdata));
1880 route_destroy(ac->route);
1883 pa_xfree((void *)ac->name);
1886 pa_nodeset_delete_class(u, ac->type);
1887 pa_xfree((void *)ac->class);
1891 for (r = ac->roles; r->name; r++)
1892 pa_nodeset_delete_role(u, r->name);
1894 map_destroy(ac->roles);
1899 for (b = ac->binaries; b->name; b++)
1900 pa_nodeset_delete_binary(u, b->name);
1902 map_destroy(ac->binaries);
1903 ac->binaries = NULL;
1906 MRP_LUA_LEAVE_NOARG;
1909 static const char **route_definition_check(lua_State *L, int idx)
1912 const char *zonenam;
1913 scripting_zone *zone;
1914 scripting_rtgroup *rtgs;
1920 idx = (idx < 0) ? lua_gettop(L) + idx + 1 : idx;
1922 luaL_checktype(L, idx, LUA_TTABLE);
1924 defs = pa_xnew0(const char *, MRP_ZONE_MAX);
1927 MRP_LUA_FOREACH_FIELD(L, idx, zonenam, zonelen) {
1929 luaL_error(L, "invalid route definition");
1931 mrp_lua_find_object(L, ZONE_CLASS, zonenam);
1933 if (!(zone = mrp_lua_check_object(L, NULL, -1)))
1934 luaL_error(L, "can't find zone '%s'", zonenam);
1938 if (zone->index >= MRP_ZONE_MAX)
1939 luaL_error(L, "Internal error: zone index overflow");
1941 switch (lua_type(L, -1)) {
1943 rtgnam = lua_tostring(L, -1);
1946 rtgs = (scripting_rtgroup*)mrp_lua_check_object(L,RTGROUP_CLASS,-1);
1947 if (!rtgs || !(rtg = rtgs->rtg))
1958 luaL_error(L, "missing or invalid routing group");
1960 defs[zone->index] = pa_xstrdup(rtgnam);
1965 luaL_error(L, "empty definition");
1970 static int route_definition_push(lua_State *L, const char **defs)
1974 lua_createtable(L, MRP_ZONE_MAX, 0);
1976 for (i = 0; i < MRP_ZONE_MAX; i++) {
1983 static void route_definition_free(const char **defs)
1988 for (i = 0; i < MRP_ZONE_MAX; i++)
1989 pa_xfree((void *)defs[i]);
1990 pa_xfree((void *)defs);
1995 static route_t *route_check(lua_State *L, int idx)
2000 const char **input = NULL;
2001 const char **output = NULL;
2003 idx = (idx < 0) ? lua_gettop(L) + idx + 1 : idx;
2005 luaL_checktype(L, idx, LUA_TTABLE);
2007 MRP_LUA_FOREACH_FIELD(L, idx, fldnam, fldnamlen) {
2008 switch (field_name_to_type(fldnam, fldnamlen)) {
2009 case INPUT: input = route_definition_check(L, -1); break;
2010 case OUTPUT: output = route_definition_check(L, -1); break;
2011 default: luaL_error(L, "invalid field '%s'", fldnam); break;
2013 } /* MRP_LUA_FOREACH_FIELD */
2015 if (!input && !output)
2016 luaL_error(L, "neither input nor output routing group were specified");
2018 rt = pa_xmalloc(sizeof(route_t));
2020 rt->output = output;
2025 static int route_push(lua_State *L, route_t *rt)
2027 if (!rt || (!rt->input && !rt->output))
2030 lua_createtable(L, 0, 2);
2033 lua_pushstring(L, "input");
2034 route_definition_push(L, rt->input);
2035 lua_settable(L, -3);
2039 lua_pushstring(L, "output");
2040 route_definition_push(L, rt->output);
2041 lua_settable(L, -3);
2048 static void route_destroy(route_t *rt)
2051 pa_xfree((void *)rt->input);
2052 pa_xfree((void *)rt->output);
2053 pa_xfree((void *)rt);
2058 static int vollim_create(lua_State *L)
2060 static int min = mir_application_class_begin;
2061 static int max = mir_application_class_end;
2066 scripting_vollim *vlim;
2067 const char *name = NULL;
2068 vollim_type type = 0;
2069 limit_data_t *limit = NULL;
2070 mrp_funcbridge_t *calculate = NULL;
2071 intarray_t *classes = NULL;
2072 bool suppress = false;
2073 bool correct = false;
2077 uint32_t mask, clmask;
2082 lua_getglobal(L, USERDATA);
2083 if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
2084 luaL_error(L, "missing or invalid global '" USERDATA "'");
2088 MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
2090 switch (field_name_to_type(fldnam, fldnamlen)) {
2091 case NAME: name = luaL_checkstring(L, -1); break;
2092 case TYPE: type = luaL_checkint(L, -1); break;
2093 case NODE_TYPE: classes = intarray_check(L, -1, min, max); break;
2094 case LIMIT: limit = limit_data_check(L, -1); break;
2095 case CALCULATE: calculate = mrp_funcbridge_create_luafunc(L,-1); break;
2096 default: luaL_error(L, "bad field '%s'", fldnam); break;
2099 } /* MRP_LUA_FOREACH_FIELD */
2102 luaL_error(L, "missing name field");
2103 if (type != vollim_class && type != vollim_generic && type != vollim_maximum)
2104 luaL_error(L, "missing or invalid type");
2105 if ((type == vollim_class || type == vollim_maximum) && !classes)
2106 luaL_error(L, "missing or invalid node_type for class/maximum limit");
2107 if (type == vollim_generic && classes)
2108 luaL_error(L, "can't specify node_type for generic volume limit");
2110 luaL_error(L, "missing or invalid limit");
2111 if (type != vollim_maximum && !calculate)
2112 luaL_error(L, "missing calculate field");
2113 if (type != vollim_maximum && calculate->type == MRP_C_FUNCTION) {
2114 if (strcmp(calculate->c.signature, "odo"))
2115 luaL_error(L, "invalid calculate field (mismatching signature)");
2116 if (calculate->c.data == mir_volume_suppress) {
2117 if (type != vollim_class)
2118 luaL_error(L, "attempt to make generic volume supression");
2120 arglgh = sizeof(mir_volume_suppress_arg);
2122 else if (calculate->c.data == mir_volume_correction) {
2123 if (type != vollim_generic)
2124 luaL_error(L, "attempt to make class based volume correction");
2126 arglgh = sizeof(double *);
2129 luaL_error(L, "invalid builtin.method for calculate");
2133 make_id(id, sizeof(id), "%s", name);
2135 (VOLLIM_CLASS)->userdata_size = sizeof(scripting_vollim) + arglgh;
2136 vlim = (scripting_vollim *)mrp_lua_create_object(L, VOLLIM_CLASS, id,0);
2137 (VOLLIM_CLASS)->userdata_size = sizeof(scripting_vollim);
2140 vlim->name = pa_xstrdup(name);
2142 vlim->classes = classes;
2143 vlim->limit = limit;
2144 vlim->calculate = calculate;
2147 mir_volume_suppress_arg *args = (mir_volume_suppress_arg *)vlim->args;
2148 size_t size = sizeof(int) * classes->nint;
2149 size_t n = mir_application_class_end - mir_application_class_begin;
2151 for (i = 0, clmask = 0; i < classes->nint; i++) {
2152 class = classes->ints[i];
2154 if (class <= mir_application_class_begin ||
2155 class > mir_application_class_end )
2157 pa_log("invalid triggering class id %d", class);
2159 classes->nint = n = 0;
2163 mask = ((uint32_t)1) << (class - mir_application_class_begin);
2165 if (!(clmask & mask) && n > 0)
2171 args->attenuation = limit->value;
2172 args->trigger.nclass = classes->nint;
2173 args->trigger.classes = pa_xmalloc(size);
2174 args->trigger.clmask = clmask;
2176 memcpy(args->trigger.classes, classes->ints, size);
2178 if (n > classes->nint)
2179 classes->ints = pa_xrealloc(classes->ints, sizeof(int) * n);
2182 for (i = mir_application_class_begin, n = 0;
2183 i < mir_application_class_end;
2186 if (!(clmask & (((uint32_t)1) << (i-mir_application_class_begin))))
2187 classes->ints[n++] = i;
2191 /* *(double **)vlim->args = limit->value; */
2193 memcpy(vlim->args, &limit->value, sizeof(limit->value));
2197 case vollim_generic:
2198 mir_volume_add_generic_limit(u, vollim_calculate, vlim->args);
2201 for (i = 0; i < classes->nint; i++) {
2202 mir_volume_add_class_limit(u, classes->ints[i], vollim_calculate,
2206 case vollim_maximum:
2207 mir_volume_add_maximum_limit(u, *(vlim->limit->value),
2208 classes->nint, classes->ints);
2217 static int vollim_getfield(lua_State *L)
2219 scripting_vollim *vlim;
2224 fld = field_check(L, 2, NULL);
2227 if (!(vlim = (scripting_vollim *)mrp_lua_check_object(L, VOLLIM_CLASS, 1)))
2231 case NAME: lua_pushstring(L, vlim->name); break;
2232 case TYPE: lua_pushinteger(L, vlim->type); break;
2233 case NODE_TYPE: intarray_push(L, vlim->classes); break;
2234 case LIMIT: lua_pushnumber(L, *vlim->limit->value); break;
2235 default: lua_pushnil(L); break;
2242 static int vollim_setfield(lua_State *L)
2248 f = luaL_checkstring(L, 2);
2249 luaL_error(L, "attempt to set '%s' field of read-only volume_limit", f);
2254 static int vollim_tostring(lua_State *L)
2256 scripting_vollim *vlim;
2260 vlim = (scripting_vollim *)mrp_lua_check_object(L, VOLLIM_CLASS, 1);
2262 lua_pushstring(L, vlim->name);
2267 static void vollim_destroy(void *data)
2269 scripting_vollim *vlim = (scripting_vollim *)data;
2273 pa_xfree((void *)vlim->name);
2274 intarray_destroy(vlim->classes);
2275 limit_data_destroy(vlim->limit);
2277 MRP_LUA_LEAVE_NOARG;
2281 static double vollim_calculate(struct userdata *u, int class, mir_node *node,
2284 static int offset = ((scripting_vollim *)0)->args - (char *)0;
2286 pa_scripting *scripting;
2288 scripting_vollim *vlim;
2289 mrp_funcbridge_value_t args[3];
2291 mrp_funcbridge_value_t rv;
2295 pa_assert_se((scripting = u->scripting));
2296 pa_assert_se((L = scripting->L));
2297 pa_assert(!class || (class >= mir_application_class_begin &&
2298 class < mir_application_class_end) );
2301 vlim = (scripting_vollim *)(data - offset);
2303 pa_assert(u == vlim->userdata);
2307 if (node->scripting) {
2309 args[0].pointer = vlim;
2310 args[1].integer = class;
2311 args[2].pointer = node->scripting;
2313 if (!mrp_funcbridge_call_from_c(L,vlim->calculate,"odo",args,&rt,&rv))
2314 pa_log("failed to call calculate function");
2316 if (rt != MRP_FUNCBRIDGE_FLOATING)
2317 pa_log("accept function returned invalid type");
2319 limit = rv.floating;
2326 static bool calculate_bridge(lua_State *L, void *data, const char *signature,
2327 mrp_funcbridge_value_t *args,
2328 char *ret_type, mrp_funcbridge_value_t *ret_val)
2330 mir_volume_func_t calculate;
2331 scripting_vollim *vlim;
2340 pa_assert(signature);
2342 pa_assert(ret_type);
2345 pa_assert_se((calculate = (mir_volume_func_t)data));
2347 if (strcmp(signature, "odo"))
2350 pa_assert_se((vlim = args[0].pointer));
2351 pa_assert_se((u = vlim->userdata));
2352 pa_assert_se((ns = args[2].pointer));
2354 class = args[1].integer;
2356 pa_assert(!class || (class >= mir_application_class_begin &&
2357 class < mir_application_class_end));
2359 if (!(node = ns->node))
2363 *ret_type = MRP_FUNCBRIDGE_FLOATING;
2364 ret_val->floating = calculate(u, class, node, vlim->args);
2371 static limit_data_t *limit_data_check(lua_State *L, int idx)
2373 static double nolimit = 0.0;
2379 switch (lua_type(L, idx)) {
2381 if ((value = lua_tonumber(L, idx)) > 0.0)
2382 luaL_error(L, "volume limit is in dB and can't be positive");
2384 ld = pa_xnew0(limit_data_t, 1);
2386 ld->value = pa_xnew0(double, 1);
2390 case LUA_TLIGHTUSERDATA:
2391 if (!(v = lua_touserdata(L, idx)) || v->type < 0)
2392 luaL_error(L, "broken link for volume limit value");
2394 ld = pa_xnew0(limit_data_t, 1);
2395 ld->mallocd = false;
2396 ld->value = &v->floating;
2400 ld->mallocd = false;
2401 ld->value = &nolimit;
2409 static int limit_data_push(lua_State *L, limit_data_t *ld)
2412 lua_pushnumber(L, *ld->value);
2420 static void limit_data_destroy(limit_data_t *ld)
2424 pa_xfree(ld->value);
2430 static intarray_t *intarray_check(lua_State *L, int idx, int min, int max)
2438 idx = (idx < 0) ? lua_gettop(L) + idx + 1 : idx;
2440 luaL_checktype(L, idx, LUA_TTABLE);
2442 if ((len = luaL_getn(L, idx)) < 1)
2445 size = sizeof(intarray_t) + sizeof(int) * len;
2446 arr = pa_xmalloc0(sizeof(intarray_t));
2449 arr->ints = pa_xmalloc0(size);
2451 for (i = 0; i < len; i++) {
2452 lua_pushnumber(L, (int)(i+1));
2453 lua_gettable(L, idx);
2455 val = luaL_checkint(L, -1);
2459 if (val < min || val >= max)
2460 luaL_error(L, "array [%u]: out of range value (%d)", i, val);
2469 static int intarray_push(lua_State *L, intarray_t *arr)
2476 lua_createtable(L, arr->nint, 0);
2478 for (i = 0; i < arr->nint; i++) {
2479 lua_pushinteger(L, (int)(i+1));
2480 lua_pushinteger(L, arr->ints[i]);
2481 lua_settable(L, -3);
2488 static void intarray_destroy(intarray_t *arr)
2491 pa_xfree(arr->ints);
2496 static resource_name_t *resource_names_check(lua_State *L, int tbl)
2498 resource_name_t *name;
2503 tbl = (tbl < 0) ? lua_gettop(L) + tbl + 1 : tbl;
2505 luaL_checktype(L, tbl, LUA_TTABLE);
2507 name = pa_xnew0(resource_name_t, 1);
2509 MRP_LUA_FOREACH_FIELD(L, tbl, fldnam, fldnamlen) {
2510 value = luaL_checkstring(L, -1);
2512 if (!strcmp(fldnam, "recording"))
2513 name->recording = pa_xstrdup(value);
2514 else if (!strcmp(fldnam, "playback"))
2515 name->playback = pa_xstrdup(value);
2517 luaL_error(L, "invalid field '%s' in resource name definition",
2525 static void resource_names_destroy(resource_name_t *name)
2528 pa_xfree((void *)name->recording);
2529 pa_xfree((void *)name->playback);
2534 static attribute_t *attributes_check(lua_State *L, int tbl)
2539 attribute_t *attr, *attrs = NULL;
2541 mrp_attr_value_t *v;
2544 tbl = (tbl < 0) ? lua_gettop(L) + tbl + 1 : tbl;
2546 luaL_checktype(L, tbl, LUA_TTABLE);
2548 MRP_LUA_FOREACH_FIELD(L, tbl, fldnam, fldnamlen) {
2550 luaL_error(L, "invalid attribute definition");
2552 attrs = pa_xrealloc(attrs, sizeof(attribute_t) * (nattr + 2));
2553 memset(attrs + nattr, 0, sizeof(attribute_t) * 2);
2555 attr = attrs + nattr++;
2556 v = &attr->def.value;
2557 def = lua_gettop(L);
2559 attr->def.name = pa_xstrdup(fldnam);
2561 if ((len = luaL_getn(L, def)) != 3)
2562 luaL_error(L, "invalid attribute definition '%s'", fldnam);
2564 for (i = 0; i < len; i++) {
2565 lua_pushnumber(L, (int)(i+1));
2566 lua_gettable(L, def);
2569 case 0: attr->prop = pa_xstrdup(luaL_checkstring(L,-1)); break;
2570 case 1: attr->def.type = luaL_checkint(L,-1); break;
2572 switch (attr->def.type) {
2573 case mqi_string: v->string = luaL_checkstring(L,-1); break;
2574 case mqi_integer: v->integer = luaL_checkint(L,-1); break;
2575 case mqi_unsignd: v->integer = luaL_checkint(L,-1); break;
2576 case mqi_floating: v->floating = luaL_checknumber(L,-1); break;
2577 default: memset(v, 0, sizeof(*v)); break;
2585 luaL_error(L, "missing property name definition from '%s'",fldnam);
2586 if (attr->def.type != mqi_string && attr->def.type != mqi_integer &&
2587 attr->def.type != mqi_unsignd && attr->def.type != mqi_floating)
2589 luaL_error(L, "invalid attribute type %d for '%s'",
2590 attr->def.type, fldnam);
2592 if (attr->def.type == mqi_unsignd && attr->def.value.integer < 0) {
2593 luaL_error(L, "attempt to give negative value (%d) for field '%s'",
2594 attr->def.value.integer, fldnam);
2601 static void attributes_destroy(attribute_t *attrs)
2606 for (attr = attrs; attr->prop && attr->def.name; attr++) {
2607 pa_xfree((void *)attr->prop);
2608 pa_xfree((void *)attr->def.name);
2609 if (attr->def.type == mqi_string)
2610 pa_xfree((void *)attr->def.value.string);
2616 static map_t *map_check(lua_State *L, int tbl)
2623 map_t *m, *map = NULL;
2627 pa_nodeset_resdef *rd;
2629 tbl = (tbl < 0) ? lua_gettop(L) + tbl + 1 : tbl;
2631 luaL_checktype(L, tbl, LUA_TTABLE);
2633 MRP_LUA_FOREACH_FIELD(L, tbl, name, namlen) {
2635 luaL_error(L, "invalid role or binary definition");
2637 map = pa_xrealloc(map, sizeof(map_t) * (n + 2));
2638 memset(map + n, 0, sizeof(map_t) * 2);
2641 def = lua_gettop(L);
2643 m->name = pa_xstrdup(name);
2645 switch (lua_type(L, -1)) {
2653 m->role = mrp_strdup(lua_tostring(L, def));
2659 if ((len = luaL_getn(L, def)) < 1)
2660 luaL_error(L, "invalid resource definition '%s'", name);
2662 for (i = 1; i <= len; i++) {
2663 lua_pushnumber(L, (int)i);
2664 lua_gettable(L, def);
2667 priority = luaL_checkint(L, -1);
2669 if (priority < 0 || priority > 7) {
2670 luaL_error(L, "invalid priority %d for '%s'",
2674 m->resource.priority = priority;
2677 option = luaL_checkstring(L, -1);
2680 if (pa_streq(option, "autorelease"))
2681 rd->flags.rset |= RESPROTO_RSETFLAG_AUTORELEASE;
2682 else if (pa_streq(option, "mandatory"))
2683 rd->flags.audio |= RESPROTO_RESFLAG_MANDATORY;
2684 else if (pa_streq(option, "shared"))
2685 rd->flags.audio |= RESPROTO_RESFLAG_SHARED;
2686 else if (!pa_streq(option, "optional") &&
2687 !pa_streq(option, "exclusive") )
2690 m->role = pa_xstrdup(option);
2692 luaL_error(L, "multiple role definition '%s','%s'",
2704 luaL_error(L, "invalid resource specification. "
2705 "Should be either 'no_resource' or a table");
2708 } /* FOREACH_FIELD */
2713 static int map_push(lua_State *L, map_t *map)
2722 for (m = map; m->name; m++) {
2725 lua_pushstring(L, m->role);
2727 lua_pushnumber(L, 0);
2731 lua_pushinteger(L, m->resource.priority);
2733 lua_pushstring(L, m->role);
2734 if (m->resource.flags.rset & RESPROTO_RSETFLAG_AUTORELEASE)
2735 lua_pushstring(L, "autorelease");
2736 if (m->resource.flags.audio & RESPROTO_RESFLAG_MANDATORY)
2737 lua_pushstring(L, "mandatory");
2739 lua_pushstring(L, "optional");
2740 if (m->resource.flags.audio & RESPROTO_RESFLAG_SHARED)
2741 lua_pushstring(L, "shared");
2743 lua_pushstring(L, "exclusive");
2745 lua_setfield(L, -2, m->name);
2752 static void map_destroy(map_t *map)
2757 for (m = map; m->name; m++) {
2758 pa_xfree((void *)m->name);
2759 pa_xfree((void *)m->role);
2766 static field_t field_check(lua_State *L, int idx, const char **ret_fldnam)
2772 if (!(fldnam = lua_tolstring(L, idx, &fldnamlen)))
2775 fldtyp = field_name_to_type(fldnam, fldnamlen);
2778 *ret_fldnam = fldnam;
2783 static field_t field_name_to_type(const char *name, size_t len)
2790 if (!strcmp(name, "name"))
2794 if (!strcmp(name, "type"))
2798 if (!strcmp(name, "zone"))
2809 if (!strcmp(name, "class"))
2813 if (!strcmp(name, "input"))
2817 if (!strcmp(name, "limit"))
2821 if (!strcmp(name, "route"))
2823 if (!strcmp(name, "roles"))
2827 if (!strcmp(name, "table"))
2838 if (!strcmp(name, "accept"))
2842 if (!strcmp(name, "maxrow"))
2846 if (!strcmp(name, "output"))
2850 if (!strcmp(name, "tables"))
2854 if (!strcmp(name, "update"))
2865 if (!strcmp(name, "compare"))
2867 if (!strcmp(name, "columns"))
2871 if (!strcmp(name, "privacy"))
2882 if (!strcmp(name, "binaries"))
2886 if (!strcmp(name, "channels"))
2890 if (!strcmp(name, "location"))
2894 if (!strcmp(name, "priority"))
2905 if (!strcmp(name, "available"))
2909 if (!strcmp(name, "calculate"))
2911 if (!strcmp(name, "condition"))
2915 if (!strcmp(name, "direction"))
2919 if (!strcmp(name, "implement"))
2923 if (!strcmp(name, "node_type"))
2932 if (!strcmp(name, "attributes"))
2937 if (!strcmp(name, "autorelease"))
2939 if (!strcmp(name, "description"))
2950 static int make_id(char *buf, size_t len, const char *fmt, ...)
2957 l = vsnprintf(buf, len, fmt, ap);
2960 for (p = buf; (c = *p); p++) {
2963 else if (!isdigit(c))
2972 static void setup_murphy_interface(struct userdata *u)
2974 pa_scripting *scripting;
2975 scripting_import *imp;
2979 bool need_domainctl;
2981 const char *columns;
2988 pa_assert_se((scripting = u->scripting));
2989 pa_assert_se((L = scripting->L));
2991 top = lua_gettop(L);
2993 mrp_lua_get_class_table(L, IMPORT_CLASS);
2994 class = lua_gettop(L);
2996 if (!lua_istable(L, class)){
2997 luaL_error(L, "internal error: failed to find '%s' table",
2998 (IMPORT_CLASS)->constructor);
3001 need_domainctl = false;
3004 while (lua_next(L, class)) {
3005 if (lua_isstring(L, -2)) {
3006 if ((imp = mrp_lua_to_object(L, IMPORT_CLASS, -1))) {
3007 key = lua_tostring(L, -2);
3009 pa_assert(!strcmp(key, imp->table));
3010 pa_assert_se((values = imp->values));
3012 pa_log_debug("adding import '%s'", imp->table);
3014 need_domainctl = true;
3015 columns = comma_separated_list(imp->columns, buf,sizeof(buf));
3017 pa_murphyif_add_watch(u, imp->table, columns, imp->condition,
3025 pa_murphyif_setup_domainctl(u, import_data_changed);
3029 MRP_LUA_LEAVE_NOARG;
3033 static char *comma_separated_list(mrp_lua_strarray_t *arr, char *buf, int len)
3042 for (i = 0, e = (p = buf) + len; i < arr->nstring && p < e; i++)
3043 p += snprintf(p, e-p, "%s%s", (p == buf ? "" : ","), arr->strings[i]);
3045 return (p < e) ? buf : NULL;
3049 static bool define_constants(lua_State *L)
3051 static const_def_t mdb_const[] = {
3052 { "string" , mqi_string },
3053 { "integer" , mqi_integer },
3054 { "unsigned" , mqi_unsignd },
3055 { "floating" , mqi_floating },
3059 static const_def_t node_const[] = {
3060 { "input" , mir_input },
3061 { "output" , mir_output },
3062 { "device" , mir_device },
3063 { "stream" , mir_stream },
3064 { "internal" , mir_internal },
3065 { "external" , mir_external },
3066 { "radio" , mir_radio },
3067 { "player" , mir_player },
3068 { "navigator" , mir_navigator },
3069 { "game" , mir_game },
3070 { "browser" , mir_browser },
3071 { "camera" , mir_camera },
3072 { "phone" , mir_phone },
3073 { "alert" , mir_alert },
3074 { "event" , mir_event },
3075 { "system" , mir_system },
3076 { "speakers" , mir_speakers },
3077 { "microphone" , mir_microphone },
3078 { "jack" , mir_jack },
3079 { "spdif" , mir_spdif },
3080 { "hdmi" , mir_hdmi },
3081 { "wired_headset" , mir_wired_headset },
3082 { "wired_headphone" , mir_wired_headphone },
3083 { "usb_headset" , mir_usb_headset },
3084 { "usb_headphone" , mir_usb_headphone },
3085 { "bluetooth_sco" , mir_bluetooth_sco },
3086 { "bluetooth_a2dp" , mir_bluetooth_a2dp },
3087 { "bluetooth_carkit" , mir_bluetooth_carkit },
3088 { "bluetooth_source" , mir_bluetooth_source },
3089 { "bluetooth_sink" , mir_bluetooth_sink },
3093 static const_def_t vollim_const[] = {
3094 { "class" , vollim_class },
3095 { "generic" , vollim_generic },
3096 { "maximum" , vollim_maximum },
3101 bool success = true;
3104 lua_getglobal(L, "mdb");
3106 if (!lua_istable(L, -1))
3109 for (cd = mdb_const; cd->name; cd++) {
3110 lua_pushstring(L, cd->name);
3111 lua_pushinteger(L, cd->value);
3119 lua_getglobal(L, "node");
3121 if (!lua_istable(L, -1))
3124 for (cd = node_const; cd->name; cd++) {
3125 lua_pushstring(L, cd->name);
3126 lua_pushinteger(L, cd->value);
3133 lua_getglobal(L, "volume_limit");
3135 if (!lua_istable(L, -1))
3138 for (cd = vollim_const; cd->name; cd++) {
3139 lua_pushstring(L, cd->name);
3140 lua_pushinteger(L, cd->value);
3146 lua_pushnumber(L, 0);
3147 lua_setglobal(L, "no_resource");
3153 static bool register_methods(lua_State *L)
3155 static funcbridge_def_t funcbridge_defs[] = {
3156 {"make_routes" ,"o" , update_bridge ,mir_router_make_routing },
3157 {"make_volumes" ,"o" , update_bridge ,mir_volume_make_limiting },
3158 {"accept_default" ,"oo" , accept_bridge ,mir_router_default_accept },
3159 {"compare_default","ooo", compare_bridge ,mir_router_default_compare},
3160 {"accept_phone" ,"oo" , accept_bridge ,mir_router_phone_accept },
3161 {"compare_phone" ,"ooo", compare_bridge ,mir_router_phone_compare },
3162 {"volume_supress" ,"odo", calculate_bridge,mir_volume_suppress },
3163 {"volume_correct" ,"odo", calculate_bridge,mir_volume_correction },
3164 { NULL , NULL, NULL , NULL }
3167 funcbridge_def_t *d;
3168 bool success = true;
3170 for (d = funcbridge_defs; d->name; d++) {
3171 if (!mrp_funcbridge_create_cfunc(L,d->name,d->sign,d->func,d->data)) {
3172 pa_log("%s: failed to register builtin function '%s'",
3183 static void *alloc(void *ud, void *ptr, size_t osize, size_t nsize)
3191 mem = pa_xrealloc(ptr, nsize);
3200 static int panic(lua_State *L)
3204 pa_log("PANIC: unprotected error in call to Lua API (%s)",
3205 lua_tostring(L,-1));
3214 * indent-tabs-mode: nil