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) {
2114 if (calculate->type == MRP_C_FUNCTION) {
2115 if (strcmp(calculate->c.signature, "odo"))
2116 luaL_error(L,"invalid calculate field (mismatching signature)");
2117 if (calculate->c.data == mir_volume_suppress) {
2118 if (type != vollim_class)
2119 luaL_error(L, "attempt to make generic volume supression");
2121 arglgh = sizeof(mir_volume_suppress_arg);
2123 else if (calculate->c.data == mir_volume_correction) {
2124 if (type != vollim_generic) {
2125 luaL_error(L, "attempt to make class based volume"
2129 arglgh = sizeof(double *);
2132 luaL_error(L, "invalid builtin.method for calculate");
2139 arglgh = sizeof(mir_volume_suppress_arg);
2141 case vollim_generic:
2143 arglgh = sizeof(double *);
2151 make_id(id, sizeof(id), "%s", name);
2153 (VOLLIM_CLASS)->userdata_size = sizeof(scripting_vollim) + arglgh;
2154 vlim = (scripting_vollim *)mrp_lua_create_object(L, VOLLIM_CLASS, id,0);
2155 (VOLLIM_CLASS)->userdata_size = sizeof(scripting_vollim);
2158 vlim->name = pa_xstrdup(name);
2160 vlim->classes = classes;
2161 vlim->limit = limit;
2162 vlim->calculate = calculate;
2165 mir_volume_suppress_arg *args = (mir_volume_suppress_arg *)vlim->args;
2166 size_t size = sizeof(int) * classes->nint;
2167 size_t n = mir_application_class_end - mir_application_class_begin;
2169 for (i = 0, clmask = 0; i < classes->nint; i++) {
2170 class = classes->ints[i];
2172 if (class <= mir_application_class_begin ||
2173 class > mir_application_class_end )
2175 pa_log("invalid triggering class id %d", class);
2177 classes->nint = n = 0;
2181 mask = ((uint32_t)1) << (class - mir_application_class_begin);
2183 if (!(clmask & mask) && n > 0)
2189 args->attenuation = limit->value;
2190 args->trigger.nclass = classes->nint;
2191 args->trigger.classes = pa_xmalloc(size);
2192 args->trigger.clmask = clmask;
2194 memcpy(args->trigger.classes, classes->ints, size);
2196 if (n > classes->nint)
2197 classes->ints = pa_xrealloc(classes->ints, sizeof(int) * n);
2200 for (i = mir_application_class_begin, n = 0;
2201 i < mir_application_class_end;
2204 if (!(clmask & (((uint32_t)1) << (i-mir_application_class_begin))))
2205 classes->ints[n++] = i;
2209 /* *(double **)vlim->args = limit->value; */
2211 memcpy(vlim->args, &limit->value, sizeof(limit->value));
2215 case vollim_generic:
2216 mir_volume_add_generic_limit(u, vollim_calculate, vlim->args);
2219 for (i = 0; i < classes->nint; i++) {
2220 mir_volume_add_class_limit(u, classes->ints[i], vollim_calculate,
2224 case vollim_maximum:
2225 mir_volume_add_maximum_limit(u, *(vlim->limit->value),
2226 classes->nint, classes->ints);
2235 static int vollim_getfield(lua_State *L)
2237 scripting_vollim *vlim;
2242 fld = field_check(L, 2, NULL);
2245 if (!(vlim = (scripting_vollim *)mrp_lua_check_object(L, VOLLIM_CLASS, 1)))
2249 case NAME: lua_pushstring(L, vlim->name); break;
2250 case TYPE: lua_pushinteger(L, vlim->type); break;
2251 case NODE_TYPE: intarray_push(L, vlim->classes); break;
2252 case LIMIT: lua_pushnumber(L, *vlim->limit->value); break;
2253 default: lua_pushnil(L); break;
2260 static int vollim_setfield(lua_State *L)
2266 f = luaL_checkstring(L, 2);
2267 luaL_error(L, "attempt to set '%s' field of read-only volume_limit", f);
2272 static int vollim_tostring(lua_State *L)
2274 scripting_vollim *vlim;
2278 vlim = (scripting_vollim *)mrp_lua_check_object(L, VOLLIM_CLASS, 1);
2280 lua_pushstring(L, vlim->name);
2285 static void vollim_destroy(void *data)
2287 scripting_vollim *vlim = (scripting_vollim *)data;
2291 pa_xfree((void *)vlim->name);
2292 intarray_destroy(vlim->classes);
2293 limit_data_destroy(vlim->limit);
2295 MRP_LUA_LEAVE_NOARG;
2299 static double vollim_calculate(struct userdata *u, int class, mir_node *node,
2302 static int offset = ((scripting_vollim *)0)->args - (char *)0;
2304 pa_scripting *scripting;
2306 scripting_vollim *vlim;
2307 mrp_funcbridge_value_t args[3];
2309 mrp_funcbridge_value_t rv;
2313 pa_assert_se((scripting = u->scripting));
2314 pa_assert_se((L = scripting->L));
2315 pa_assert(!class || (class >= mir_application_class_begin &&
2316 class < mir_application_class_end) );
2319 vlim = (scripting_vollim *)(data - offset);
2321 pa_assert(u == vlim->userdata);
2325 if (node->scripting) {
2327 args[0].pointer = vlim;
2328 args[1].integer = class;
2329 args[2].pointer = node->scripting;
2331 if (!mrp_funcbridge_call_from_c(L,vlim->calculate,"odo",args,&rt,&rv))
2332 pa_log("failed to call calculate function");
2334 if (rt != MRP_FUNCBRIDGE_FLOATING)
2335 pa_log("accept function returned invalid type");
2337 limit = rv.floating;
2344 static bool calculate_bridge(lua_State *L, void *data, const char *signature,
2345 mrp_funcbridge_value_t *args,
2346 char *ret_type, mrp_funcbridge_value_t *ret_val)
2348 mir_volume_func_t calculate;
2349 scripting_vollim *vlim;
2358 pa_assert(signature);
2360 pa_assert(ret_type);
2363 pa_assert_se((calculate = (mir_volume_func_t)data));
2365 if (strcmp(signature, "odo"))
2368 pa_assert_se((vlim = args[0].pointer));
2369 pa_assert_se((u = vlim->userdata));
2370 pa_assert_se((ns = args[2].pointer));
2372 class = args[1].integer;
2374 pa_assert(!class || (class >= mir_application_class_begin &&
2375 class < mir_application_class_end));
2377 if (!(node = ns->node))
2381 *ret_type = MRP_FUNCBRIDGE_FLOATING;
2382 /* TODO: check the vollim type vs. c function */
2383 ret_val->floating = calculate(u, class, node, vlim->args);
2390 static limit_data_t *limit_data_check(lua_State *L, int idx)
2392 static double nolimit = 0.0;
2398 switch (lua_type(L, idx)) {
2400 if ((value = lua_tonumber(L, idx)) > 0.0)
2401 luaL_error(L, "volume limit is in dB and can't be positive");
2403 ld = pa_xnew0(limit_data_t, 1);
2405 ld->value = pa_xnew0(double, 1);
2409 case LUA_TLIGHTUSERDATA:
2410 if (!(v = lua_touserdata(L, idx)) || v->type < 0)
2411 luaL_error(L, "broken link for volume limit value");
2413 ld = pa_xnew0(limit_data_t, 1);
2414 ld->mallocd = false;
2415 ld->value = &v->floating;
2419 ld->mallocd = false;
2420 ld->value = &nolimit;
2428 static int limit_data_push(lua_State *L, limit_data_t *ld)
2431 lua_pushnumber(L, *ld->value);
2439 static void limit_data_destroy(limit_data_t *ld)
2443 pa_xfree(ld->value);
2449 static intarray_t *intarray_check(lua_State *L, int idx, int min, int max)
2457 idx = (idx < 0) ? lua_gettop(L) + idx + 1 : idx;
2459 luaL_checktype(L, idx, LUA_TTABLE);
2461 if ((len = luaL_getn(L, idx)) < 1)
2464 size = sizeof(intarray_t) + sizeof(int) * len;
2465 arr = pa_xmalloc0(sizeof(intarray_t));
2468 arr->ints = pa_xmalloc0(size);
2470 for (i = 0; i < len; i++) {
2471 lua_pushnumber(L, (int)(i+1));
2472 lua_gettable(L, idx);
2474 val = luaL_checkint(L, -1);
2478 if (val < min || val >= max)
2479 luaL_error(L, "array [%u]: out of range value (%d)", i, val);
2488 static int intarray_push(lua_State *L, intarray_t *arr)
2495 lua_createtable(L, arr->nint, 0);
2497 for (i = 0; i < arr->nint; i++) {
2498 lua_pushinteger(L, (int)(i+1));
2499 lua_pushinteger(L, arr->ints[i]);
2500 lua_settable(L, -3);
2507 static void intarray_destroy(intarray_t *arr)
2510 pa_xfree(arr->ints);
2515 static resource_name_t *resource_names_check(lua_State *L, int tbl)
2517 resource_name_t *name;
2522 tbl = (tbl < 0) ? lua_gettop(L) + tbl + 1 : tbl;
2524 luaL_checktype(L, tbl, LUA_TTABLE);
2526 name = pa_xnew0(resource_name_t, 1);
2528 MRP_LUA_FOREACH_FIELD(L, tbl, fldnam, fldnamlen) {
2529 value = luaL_checkstring(L, -1);
2531 if (!strcmp(fldnam, "recording"))
2532 name->recording = pa_xstrdup(value);
2533 else if (!strcmp(fldnam, "playback"))
2534 name->playback = pa_xstrdup(value);
2536 luaL_error(L, "invalid field '%s' in resource name definition",
2544 static void resource_names_destroy(resource_name_t *name)
2547 pa_xfree((void *)name->recording);
2548 pa_xfree((void *)name->playback);
2553 static attribute_t *attributes_check(lua_State *L, int tbl)
2558 attribute_t *attr, *attrs = NULL;
2560 mrp_attr_value_t *v;
2563 tbl = (tbl < 0) ? lua_gettop(L) + tbl + 1 : tbl;
2565 luaL_checktype(L, tbl, LUA_TTABLE);
2567 MRP_LUA_FOREACH_FIELD(L, tbl, fldnam, fldnamlen) {
2569 luaL_error(L, "invalid attribute definition");
2571 attrs = pa_xrealloc(attrs, sizeof(attribute_t) * (nattr + 2));
2572 memset(attrs + nattr, 0, sizeof(attribute_t) * 2);
2574 attr = attrs + nattr++;
2575 v = &attr->def.value;
2576 def = lua_gettop(L);
2578 attr->def.name = pa_xstrdup(fldnam);
2580 if ((len = luaL_getn(L, def)) != 3)
2581 luaL_error(L, "invalid attribute definition '%s'", fldnam);
2583 for (i = 0; i < len; i++) {
2584 lua_pushnumber(L, (int)(i+1));
2585 lua_gettable(L, def);
2588 case 0: attr->prop = pa_xstrdup(luaL_checkstring(L,-1)); break;
2589 case 1: attr->def.type = luaL_checkint(L,-1); break;
2591 switch (attr->def.type) {
2592 case mqi_string: v->string = luaL_checkstring(L,-1); break;
2593 case mqi_integer: v->integer = luaL_checkint(L,-1); break;
2594 case mqi_unsignd: v->integer = luaL_checkint(L,-1); break;
2595 case mqi_floating: v->floating = luaL_checknumber(L,-1); break;
2596 default: memset(v, 0, sizeof(*v)); break;
2604 luaL_error(L, "missing property name definition from '%s'",fldnam);
2605 if (attr->def.type != mqi_string && attr->def.type != mqi_integer &&
2606 attr->def.type != mqi_unsignd && attr->def.type != mqi_floating)
2608 luaL_error(L, "invalid attribute type %d for '%s'",
2609 attr->def.type, fldnam);
2611 if (attr->def.type == mqi_unsignd && attr->def.value.integer < 0) {
2612 luaL_error(L, "attempt to give negative value (%d) for field '%s'",
2613 attr->def.value.integer, fldnam);
2620 static void attributes_destroy(attribute_t *attrs)
2625 for (attr = attrs; attr->prop && attr->def.name; attr++) {
2626 pa_xfree((void *)attr->prop);
2627 pa_xfree((void *)attr->def.name);
2628 if (attr->def.type == mqi_string)
2629 pa_xfree((void *)attr->def.value.string);
2635 static map_t *map_check(lua_State *L, int tbl)
2642 map_t *m, *map = NULL;
2646 pa_nodeset_resdef *rd;
2648 tbl = (tbl < 0) ? lua_gettop(L) + tbl + 1 : tbl;
2650 luaL_checktype(L, tbl, LUA_TTABLE);
2652 MRP_LUA_FOREACH_FIELD(L, tbl, name, namlen) {
2654 luaL_error(L, "invalid role or binary definition");
2656 map = pa_xrealloc(map, sizeof(map_t) * (n + 2));
2657 memset(map + n, 0, sizeof(map_t) * 2);
2660 def = lua_gettop(L);
2662 m->name = pa_xstrdup(name);
2664 switch (lua_type(L, -1)) {
2672 m->role = mrp_strdup(lua_tostring(L, def));
2678 if ((len = luaL_getn(L, def)) < 1)
2679 luaL_error(L, "invalid resource definition '%s'", name);
2681 for (i = 1; i <= len; i++) {
2682 lua_pushnumber(L, (int)i);
2683 lua_gettable(L, def);
2686 priority = luaL_checkint(L, -1);
2688 if (priority < 0 || priority > 7) {
2689 luaL_error(L, "invalid priority %d for '%s'",
2693 m->resource.priority = priority;
2696 option = luaL_checkstring(L, -1);
2699 if (pa_streq(option, "autorelease"))
2700 rd->flags.rset |= RESPROTO_RSETFLAG_AUTORELEASE;
2701 else if (pa_streq(option, "mandatory"))
2702 rd->flags.audio |= RESPROTO_RESFLAG_MANDATORY;
2703 else if (pa_streq(option, "shared"))
2704 rd->flags.audio |= RESPROTO_RESFLAG_SHARED;
2705 else if (!pa_streq(option, "optional") &&
2706 !pa_streq(option, "exclusive") )
2709 m->role = pa_xstrdup(option);
2711 luaL_error(L, "multiple role definition '%s','%s'",
2723 luaL_error(L, "invalid resource specification. "
2724 "Should be either 'no_resource' or a table");
2727 } /* FOREACH_FIELD */
2732 static int map_push(lua_State *L, map_t *map)
2741 for (m = map; m->name; m++) {
2744 lua_pushstring(L, m->role);
2746 lua_pushnumber(L, 0);
2750 lua_pushinteger(L, m->resource.priority);
2752 lua_pushstring(L, m->role);
2753 if (m->resource.flags.rset & RESPROTO_RSETFLAG_AUTORELEASE)
2754 lua_pushstring(L, "autorelease");
2755 if (m->resource.flags.audio & RESPROTO_RESFLAG_MANDATORY)
2756 lua_pushstring(L, "mandatory");
2758 lua_pushstring(L, "optional");
2759 if (m->resource.flags.audio & RESPROTO_RESFLAG_SHARED)
2760 lua_pushstring(L, "shared");
2762 lua_pushstring(L, "exclusive");
2764 lua_setfield(L, -2, m->name);
2771 static void map_destroy(map_t *map)
2776 for (m = map; m->name; m++) {
2777 pa_xfree((void *)m->name);
2778 pa_xfree((void *)m->role);
2785 static field_t field_check(lua_State *L, int idx, const char **ret_fldnam)
2791 if (!(fldnam = lua_tolstring(L, idx, &fldnamlen)))
2794 fldtyp = field_name_to_type(fldnam, fldnamlen);
2797 *ret_fldnam = fldnam;
2802 static field_t field_name_to_type(const char *name, size_t len)
2809 if (!strcmp(name, "name"))
2813 if (!strcmp(name, "type"))
2817 if (!strcmp(name, "zone"))
2828 if (!strcmp(name, "class"))
2832 if (!strcmp(name, "input"))
2836 if (!strcmp(name, "limit"))
2840 if (!strcmp(name, "route"))
2842 if (!strcmp(name, "roles"))
2846 if (!strcmp(name, "table"))
2857 if (!strcmp(name, "accept"))
2861 if (!strcmp(name, "maxrow"))
2865 if (!strcmp(name, "output"))
2869 if (!strcmp(name, "tables"))
2873 if (!strcmp(name, "update"))
2884 if (!strcmp(name, "compare"))
2886 if (!strcmp(name, "columns"))
2890 if (!strcmp(name, "privacy"))
2901 if (!strcmp(name, "binaries"))
2905 if (!strcmp(name, "channels"))
2909 if (!strcmp(name, "location"))
2913 if (!strcmp(name, "priority"))
2924 if (!strcmp(name, "available"))
2928 if (!strcmp(name, "calculate"))
2930 if (!strcmp(name, "condition"))
2934 if (!strcmp(name, "direction"))
2938 if (!strcmp(name, "implement"))
2942 if (!strcmp(name, "node_type"))
2951 if (!strcmp(name, "attributes"))
2956 if (!strcmp(name, "autorelease"))
2958 if (!strcmp(name, "description"))
2969 static int make_id(char *buf, size_t len, const char *fmt, ...)
2976 l = vsnprintf(buf, len, fmt, ap);
2979 for (p = buf; (c = *p); p++) {
2982 else if (!isdigit(c))
2991 static void setup_murphy_interface(struct userdata *u)
2993 pa_scripting *scripting;
2994 scripting_import *imp;
2998 bool need_domainctl;
3000 const char *columns;
3007 pa_assert_se((scripting = u->scripting));
3008 pa_assert_se((L = scripting->L));
3010 top = lua_gettop(L);
3012 mrp_lua_get_class_table(L, IMPORT_CLASS);
3013 class = lua_gettop(L);
3015 if (!lua_istable(L, class)){
3016 luaL_error(L, "internal error: failed to find '%s' table",
3017 (IMPORT_CLASS)->constructor);
3020 need_domainctl = false;
3023 while (lua_next(L, class)) {
3024 if (lua_isstring(L, -2)) {
3025 if ((imp = mrp_lua_to_object(L, IMPORT_CLASS, -1))) {
3026 key = lua_tostring(L, -2);
3028 pa_assert(!strcmp(key, imp->table));
3029 pa_assert_se((values = imp->values));
3031 pa_log_debug("adding import '%s'", imp->table);
3033 need_domainctl = true;
3034 columns = comma_separated_list(imp->columns, buf,sizeof(buf));
3036 pa_murphyif_add_watch(u, imp->table, columns, imp->condition,
3044 pa_murphyif_setup_domainctl(u, import_data_changed);
3048 MRP_LUA_LEAVE_NOARG;
3052 static char *comma_separated_list(mrp_lua_strarray_t *arr, char *buf, int len)
3061 for (i = 0, e = (p = buf) + len; i < arr->nstring && p < e; i++)
3062 p += snprintf(p, e-p, "%s%s", (p == buf ? "" : ","), arr->strings[i]);
3064 return (p < e) ? buf : NULL;
3068 static bool define_constants(lua_State *L)
3070 static const_def_t mdb_const[] = {
3071 { "string" , mqi_string },
3072 { "integer" , mqi_integer },
3073 { "unsigned" , mqi_unsignd },
3074 { "floating" , mqi_floating },
3078 static const_def_t node_const[] = {
3079 { "input" , mir_input },
3080 { "output" , mir_output },
3081 { "device" , mir_device },
3082 { "stream" , mir_stream },
3083 { "internal" , mir_internal },
3084 { "external" , mir_external },
3085 { "radio" , mir_radio },
3086 { "player" , mir_player },
3087 { "navigator" , mir_navigator },
3088 { "game" , mir_game },
3089 { "browser" , mir_browser },
3090 { "camera" , mir_camera },
3091 { "phone" , mir_phone },
3092 { "alert" , mir_alert },
3093 { "event" , mir_event },
3094 { "system" , mir_system },
3095 { "speakers" , mir_speakers },
3096 { "microphone" , mir_microphone },
3097 { "jack" , mir_jack },
3098 { "spdif" , mir_spdif },
3099 { "hdmi" , mir_hdmi },
3100 { "wired_headset" , mir_wired_headset },
3101 { "wired_headphone" , mir_wired_headphone },
3102 { "usb_headset" , mir_usb_headset },
3103 { "usb_headphone" , mir_usb_headphone },
3104 { "bluetooth_sco" , mir_bluetooth_sco },
3105 { "bluetooth_a2dp" , mir_bluetooth_a2dp },
3106 { "bluetooth_carkit" , mir_bluetooth_carkit },
3107 { "bluetooth_source" , mir_bluetooth_source },
3108 { "bluetooth_sink" , mir_bluetooth_sink },
3112 static const_def_t vollim_const[] = {
3113 { "class" , vollim_class },
3114 { "generic" , vollim_generic },
3115 { "maximum" , vollim_maximum },
3120 bool success = true;
3123 lua_getglobal(L, "mdb");
3125 if (!lua_istable(L, -1))
3128 for (cd = mdb_const; cd->name; cd++) {
3129 lua_pushstring(L, cd->name);
3130 lua_pushinteger(L, cd->value);
3138 lua_getglobal(L, "node");
3140 if (!lua_istable(L, -1))
3143 for (cd = node_const; cd->name; cd++) {
3144 lua_pushstring(L, cd->name);
3145 lua_pushinteger(L, cd->value);
3152 lua_getglobal(L, "volume_limit");
3154 if (!lua_istable(L, -1))
3157 for (cd = vollim_const; cd->name; cd++) {
3158 lua_pushstring(L, cd->name);
3159 lua_pushinteger(L, cd->value);
3165 lua_pushnumber(L, 0);
3166 lua_setglobal(L, "no_resource");
3172 static bool register_methods(lua_State *L)
3174 static funcbridge_def_t funcbridge_defs[] = {
3175 {"make_routes" ,"o" , update_bridge ,mir_router_make_routing },
3176 {"make_volumes" ,"o" , update_bridge ,mir_volume_make_limiting },
3177 {"accept_default" ,"oo" , accept_bridge ,mir_router_default_accept },
3178 {"compare_default","ooo", compare_bridge ,mir_router_default_compare},
3179 {"accept_phone" ,"oo" , accept_bridge ,mir_router_phone_accept },
3180 {"compare_phone" ,"ooo", compare_bridge ,mir_router_phone_compare },
3181 {"volume_supress" ,"odo", calculate_bridge,mir_volume_suppress },
3182 {"volume_correct" ,"odo", calculate_bridge,mir_volume_correction },
3183 { NULL , NULL, NULL , NULL }
3186 funcbridge_def_t *d;
3187 bool success = true;
3189 for (d = funcbridge_defs; d->name; d++) {
3190 if (!mrp_funcbridge_create_cfunc(L,d->name,d->sign,d->func,d->data)) {
3191 pa_log("%s: failed to register builtin function '%s'",
3202 static void *alloc(void *ud, void *ptr, size_t osize, size_t nsize)
3210 mem = pa_xrealloc(ptr, nsize);
3219 static int panic(lua_State *L)
3223 pa_log("PANIC: unprotected error in call to Lua API (%s)",
3224 lua_tostring(L,-1));
3233 * indent-tabs-mode: nil