fix callig volume limit from lua
[profile/ivi/pulseaudio-module-murphy-ivi.git] / murphy / scripting.c
1 /*
2  * Module-murphy-ivi -- PulseAudio module for providing audio routing support
3  * Copyright (c) 2012, Intel Corporation.
4  *
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.
8  *
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.
13  *
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,
17  * MA 02110-1301 USA.
18  *
19  */
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdarg.h>
23 #include <ctype.h>
24 #include <errno.h>
25
26 #include <pulsecore/pulsecore-config.h>
27 #include <pulsecore/core-util.h>
28
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>
38
39 #include "scripting.h"
40 #include "zone.h"
41 #include "node.h"
42 #include "router.h"
43 #include "volume.h"
44 #include "murphyif.h"
45 #include "murphy-config.h"
46
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)
54
55 #define ARRAY_CLASSID      MRP_LUA_CLASSID_ROOT "mdb_array"
56
57 #define USERDATA           "murphy_ivi_userdata"
58
59 #undef  MRP_LUA_ENTER
60 #define MRP_LUA_ENTER                                           \
61     pa_log_debug("%s() enter", __FUNCTION__)
62
63 #undef  MRP_LUA_LEAVE
64 #define MRP_LUA_LEAVE(_v)                                       \
65     do {                                                        \
66         pa_log_debug("%s() leave (%d)", __FUNCTION__, (_v));    \
67         return (_v);                                            \
68     } while (0)
69
70 #undef  MRP_LUA_LEAVE_NOARG
71 #define MRP_LUA_LEAVE_NOARG                                     \
72     pa_log_debug("%s() leave", __FUNCTION__)
73
74 typedef void (*update_func_t)(struct userdata *);
75
76 struct pa_scripting {
77     lua_State *L;
78     bool configured;
79 };
80
81 struct scripting_import {
82     struct userdata    *userdata;
83     const char         *table;
84     mrp_lua_strarray_t *columns;
85     const char         *condition;
86     pa_value           *values;
87     mrp_funcbridge_t   *update;
88 };
89
90 struct scripting_node {
91     struct userdata    *userdata;
92     const char         *id;
93     mir_node           *node;
94 };
95
96 typedef struct {
97     const char         *recording;
98     const char         *playback;
99 } resource_name_t;
100
101 typedef struct {
102     const char         *prop;
103     mrp_attr_t          def;
104 } attribute_t;
105
106
107 struct scripting_zone {
108     struct userdata    *userdata;
109     const char         *name;
110     uint32_t            index;
111 };
112
113 struct scripting_resource {
114     struct userdata    *userdata;
115     resource_name_t    *name;
116     attribute_t        *attributes;
117 };
118
119 struct scripting_rtgroup {
120     struct userdata    *userdata;
121     mir_rtgroup        *rtg;
122     mir_direction       type;
123     mrp_funcbridge_t   *accept;
124     mrp_funcbridge_t   *compare;
125 };
126
127 typedef struct {
128     const char        **input;
129     const char        **output;
130 } route_t;
131
132 typedef struct {
133     const char         *name;
134     bool                needres;
135     const char         *role;
136     pa_nodeset_resdef   resource;
137 } map_t;
138
139 struct scripting_apclass {
140     struct userdata    *userdata;
141     const char         *name;
142     const char         *class;
143     mir_node_type       type;
144     int                 priority;
145     route_t            *route;
146     map_t              *roles;
147     map_t              *binaries;
148     struct {
149         bool resource;
150     }                   needs;
151 };
152
153 typedef enum {
154     vollim_class = 1,
155     vollim_generic,
156     vollim_maximum
157 } vollim_type;
158
159 typedef struct {
160     size_t      nint;
161     int        *ints;
162 } intarray_t;
163
164 typedef struct {
165     bool   mallocd;
166     double     *value;
167 } limit_data_t;
168
169 struct scripting_vollim {
170     struct userdata  *userdata;
171     const char       *name;
172     vollim_type       type;
173     intarray_t       *classes;
174     limit_data_t     *limit;
175     mrp_funcbridge_t *calculate;
176     char              args[0];
177 };
178
179
180 typedef struct {
181     const char *name;
182     int value;
183 } const_def_t;
184
185 typedef struct {
186     const char *name;
187     const char *sign;
188     mrp_funcbridge_cfunc_t func;
189     void *data;
190 } funcbridge_def_t;
191
192 typedef enum {
193     NAME = 1,
194     TYPE,
195     ZONE,
196     CLASS,
197     INPUT,
198     LIMIT,
199     ROUTE,
200     ROLES,
201     TABLE,
202     ACCEPT,
203     MAXROW,
204     OUTPUT,
205     TABLES,
206     UPDATE,
207     COMPARE,
208     COLUMNS,
209     PRIVACY,
210     BINARIES,
211     CHANNELS,
212     LOCATION,
213     PRIORITY,
214     AVAILABLE,
215     CALCULATE,
216     CONDITION,
217     DIRECTION,
218     IMPLEMENT,
219     NODE_TYPE,
220     ATTRIBUTES,
221     AUTORELEASE,
222     DESCRIPTION,
223 } field_t;
224
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 *);
230
231 static int  import_link(lua_State *);
232
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 *);
238
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 *);
244
245 #if 0
246 static void array_destroy(void *);
247 #endif
248
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 *);
254
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 *);
259
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 *);
264
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 *);
270
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 *);
274
275 static bool accept_bridge(lua_State *, void *, const char *,
276                           mrp_funcbridge_value_t *, char *,
277                           mrp_funcbridge_value_t *);
278 static bool compare_bridge(lua_State *, void *, const char *,
279                            mrp_funcbridge_value_t *, char *,
280                            mrp_funcbridge_value_t *);
281
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 *);
287
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 *);
291
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 *);
297
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 *);
302
303 static limit_data_t *limit_data_check(lua_State *, int);
304
305 #if 0
306 static int limit_data_push(lua_State *, limit_data_t *);
307 #endif
308
309 static void limit_data_destroy(limit_data_t *);
310
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 *);
314
315 static resource_name_t *resource_names_check(lua_State *, int);
316 static void resource_names_destroy(resource_name_t *);
317
318 static attribute_t *attributes_check(lua_State *, int);
319 static void attributes_destroy(attribute_t *);
320
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 *);
324
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, ...);
328
329 static void setup_murphy_interface(struct userdata *);
330 static char *comma_separated_list(mrp_lua_strarray_t *, char *, int);
331
332 static bool define_constants(lua_State *);
333 static bool register_methods(lua_State *);
334
335 static void *alloc(void *, void *, size_t, size_t);
336 static int panic(lua_State *);
337
338
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  )
343 );
344
345 MRP_LUA_METHOD_LIST_TABLE (
346     node_methods,             /* methodlist name */
347     MRP_LUA_METHOD_CONSTRUCTOR  (node_create)
348 );
349
350
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)
357 );
358
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)
364 );
365
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)
372 );
373
374
375 MRP_LUA_CLASS_DEF (
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 */
382 );
383
384 MRP_LUA_CLASS_DEF (
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 */
391 );
392
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)
399    ),
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)
404    )
405 );
406
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)
413    ),
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)
418    )
419 );
420
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)
427    ),
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)
433    )
434 );
435
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)
442    ),
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)
448    )
449 );
450
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)
457    ),
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)
463    )
464 );
465
466
467 pa_scripting *pa_scripting_init(struct userdata *u)
468 {
469     pa_scripting *scripting;
470     lua_State *L;
471
472     pa_assert(u);
473
474     scripting = pa_xnew0(pa_scripting, 1);
475
476     if (!(L = lua_newstate(alloc, u)))
477         pa_log("failed to initialize Lua");
478     else {
479         lua_atpanic(L, &panic);
480         luaL_openlibs(L);
481
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);
490
491         array_class_create(L);
492
493         define_constants(L);
494         register_methods(L);
495
496         lua_pushlightuserdata(L, u);
497         lua_setglobal(L, USERDATA);
498
499         scripting->L = L;
500         scripting->configured = false;
501     }
502
503     return scripting;
504 }
505
506 void pa_scripting_done(struct userdata *u)
507 {
508     pa_scripting *scripting;
509
510     if (u && (scripting = u->scripting)) {
511         pa_xfree(scripting);
512         u->scripting = NULL;
513     }
514 }
515
516 bool pa_scripting_dofile(struct userdata *u, const char *file)
517 {
518     pa_scripting *scripting;
519     lua_State *L;
520     bool success;
521
522     pa_assert(u);
523     pa_assert(file);
524
525     pa_assert_se((scripting = u->scripting));
526     pa_assert_se((L = scripting->L));
527
528     if (luaL_loadfile(L, file) || lua_pcall(L, 0, 0, 0)) {
529         success = false;
530         pa_log("%s", lua_tostring(L, -1));
531         lua_pop(L, 1);
532     }
533     else {
534         success =true;
535         scripting->configured = true;
536         setup_murphy_interface(u);
537         pa_zoneset_update_module_property(u);
538     }
539
540     return success;
541 }
542
543 static int import_create(lua_State *L)
544 {
545     struct userdata *u;
546     pa_scripting *scripting;
547     size_t fldnamlen;
548     const char *fldnam;
549     scripting_import *imp;
550     const char *table = NULL;
551     mrp_lua_strarray_t *columns = NULL;
552     const char *condition = NULL;
553     int maxrow = 0;
554     mrp_funcbridge_t *update = NULL;
555     size_t maxcol;
556     pa_value **rows;
557     pa_value **cols;
558     int i,j;
559     int top;
560
561     MRP_LUA_ENTER;
562
563     top = lua_gettop(L);
564
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 "'");
568
569     pa_assert_se((scripting = u->scripting));
570
571     MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
572
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;
580         }
581
582     } /* MRP_LUA_FOREACH_FIELD */
583
584     lua_settop(L, top);
585
586     if (!table)
587         luaL_error(L, "missing table field");
588     if (!columns)
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");
592     if (!update)
593         luaL_error(L, "missing update function");
594
595     maxcol = columns->nstring;
596
597     if (maxcol >= MQI_COLUMN_MAX)
598         luaL_error(L, "too many columns (max %d allowed)", MQI_COLUMN_MAX);
599
600     if (scripting->configured)
601         luaL_error(L, "refuse to import '%s' after configuration phase",table);
602
603     imp = (scripting_import *)mrp_lua_create_object(L, IMPORT_CLASS, table,0);
604
605     imp->userdata = u;
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;
611
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);
617     }
618
619     lua_rawseti(L, -2, MQI_QUERY_RESULT_MAX);
620
621     MRP_LUA_LEAVE(1);
622 }
623
624 static int import_getfield(lua_State *L)
625 {
626     scripting_import *imp;
627     pa_value *values;
628     int colidx;
629     field_t fld;
630
631     MRP_LUA_ENTER;
632
633     if (!(imp = (scripting_import *)mrp_lua_check_object(L, IMPORT_CLASS, 1)))
634         lua_pushnil(L);
635     else {
636         pa_assert_se((values = imp->values));
637
638         if (lua_type(L, 2) == LUA_TNUMBER) {
639             colidx = lua_tointeger(L, 2);
640
641             if (colidx < 1 || colidx > -values->type)
642                 lua_pushnil(L);
643             else
644                 lua_rawgeti(L, 1, colidx);
645         }
646         else {
647             fld = field_check(L, 2, NULL);
648             lua_pop(L, 1);
649
650             switch (fld) {
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;
656             }
657         }
658     }
659
660     MRP_LUA_LEAVE(1);
661 }
662
663 static int import_setfield(lua_State *L)
664 {
665     const char *f;
666
667     MRP_LUA_ENTER;
668
669     f = luaL_checkstring(L, 2);
670     luaL_error(L, "attempt to set '%s' field of read-only mdb.import", f);
671     
672     MRP_LUA_LEAVE(0);
673 }
674
675 static int import_tostring(lua_State *L)
676 {
677     scripting_import *imp;
678
679     MRP_LUA_ENTER;
680
681     imp = (scripting_import *)mrp_lua_check_object(L, IMPORT_CLASS, 1);
682
683     lua_pushstring(L, imp->table);
684
685     MRP_LUA_LEAVE(1);
686 }
687
688 static void import_destroy(void *data)
689 {
690     scripting_import *imp = (scripting_import *)data;
691
692     MRP_LUA_ENTER;
693
694     pa_xfree((void *)imp->table);
695     mrp_lua_free_strarray(imp->columns);
696     pa_xfree((void *)imp->condition);
697
698     MRP_LUA_LEAVE_NOARG;
699 }
700
701 static int import_link(lua_State *L)
702 {
703     scripting_import *imp;
704     mrp_lua_strarray_t *columns;
705     pa_value *values;
706     const char *colnam;
707     int rowidx;
708     size_t colidx;
709     pa_value *row;
710     pa_value *col;
711
712     MRP_LUA_ENTER;
713
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);
717
718     pa_assert(imp);
719     pa_assert_se((columns = imp->columns));
720
721     col = NULL;
722
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]));
730                 break;
731             }
732         }
733     }
734
735     pa_log_debug("userdata: type:%d", col->type);
736
737     lua_pushlightuserdata(L, col);
738
739     MRP_LUA_LEAVE(1);
740 }
741
742 static void import_data_changed(struct userdata *u,
743                                 const char *table,
744                                 int nrow,
745                                 mrp_domctl_value_t **mval)
746 {
747     static mrp_domctl_value_t empty;
748
749     pa_scripting *scripting;
750     lua_State *L;
751     scripting_import *imp;
752     mrp_domctl_value_t *mrow;
753     mrp_domctl_value_t *mcol;
754     pa_value *ptval, *prval, *pcval;
755     pa_value **prow;
756     pa_value **pcol;
757     int maxcol;
758     int maxrow;
759     mrp_funcbridge_value_t arg;
760     mrp_funcbridge_value_t ret;
761     char t;
762     int i,j;
763
764     pa_assert(u);
765     pa_assert(table);
766     pa_assert(mval || nrow == 0);
767     pa_assert_se((scripting = u->scripting));
768     pa_assert_se((L = scripting->L));
769
770     pa_log_debug("table '%s' data changed: got %d rows", table, nrow);
771
772     mrp_lua_get_class_table(L, IMPORT_CLASS);
773
774     if (!lua_istable(L, -1)){
775         luaL_error(L, "internal error: failed to find '%s' table",
776                    (IMPORT_CLASS)->constructor);
777     }
778
779     lua_pushstring(L, table);
780     lua_rawget(L, -2);
781
782     if (!(imp = mrp_lua_to_object(L, IMPORT_CLASS, -1)))
783         pa_log("can't find import '%s'", table);
784     else {
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));
790         
791         maxrow = -ptval->type;
792         maxcol = imp->columns->nstring;
793
794         pa_assert(maxrow >= 0);
795         pa_assert(nrow <= maxrow);
796
797         pa_log_debug("import '%s' found", imp->table);
798
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);
804
805             mrow = (i < nrow) ? mval[i] : NULL;
806
807             for (j = 0;  j < maxcol;  j++) {
808                 pcval = pcol[j];
809                 mcol = mrow ? mrow + j : &empty;
810
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);
817                     break;
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;
822                     break;
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;
827                     break;
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;
832                     break;
833                 default:
834                     if (pcval->type == pa_value_string)
835                         pa_xfree((void *)pcval->string);
836                     memset(pcval, 0, sizeof(pa_value));
837                     break;
838                 }
839             }
840         }
841
842         arg.pointer = imp;
843
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);
848         }
849     }
850
851     lua_pop(L, 2);
852 }
853
854
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)
858 {
859     update_func_t update;
860     scripting_import *imp;
861     struct userdata *u;
862     bool success;
863
864     (void)L;
865
866     pa_assert(signature);
867     pa_assert(args);
868     pa_assert(ret_type);
869     pa_assert(ret_val);
870
871     pa_assert_se((update = (update_func_t)data));
872
873     if (strcmp(signature, "o"))
874         success = false;
875     else {
876         pa_assert_se((imp = args[0].pointer));
877         pa_assert_se((u = imp->userdata));
878
879         success = true;
880         *ret_type = MRP_FUNCBRIDGE_NO_DATA;
881         memset(ret_val, 0, sizeof(mrp_funcbridge_value_t));
882         update(u);
883     }
884
885     return success;
886 }
887
888
889
890 static void array_class_create(lua_State *L)
891 {
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);
898 }
899
900
901 static pa_value *array_create(lua_State *L, int dimension,
902                               mrp_lua_strarray_t *names)
903 {
904     pa_value  *value;
905     pa_value **array;
906
907     pa_assert(L);
908     pa_assert(dimension >= 0);
909     pa_assert(dimension < MQI_QUERY_RESULT_MAX);
910
911     array = pa_xnew0(pa_value *, dimension + 1);
912     value = lua_newuserdata(L, sizeof(pa_value));
913     value->type = -dimension;
914     value->array = array;
915
916     array[dimension] = (pa_value *)names;
917
918     luaL_getmetatable(L, ARRAY_CLASSID);
919     lua_setmetatable(L, -2);
920
921     return value;
922 }
923
924 static int array_getfield(lua_State *L)
925 {
926     pa_value *arr, *value;
927     int dimension;
928     int key_type;
929     const char *key;
930     mrp_lua_strarray_t *names;
931     int idx;
932     size_t i;
933
934     MRP_LUA_ENTER;
935
936     pa_assert(L);
937
938     arr = (pa_value *)luaL_checkudata(L, 1, ARRAY_CLASSID);
939
940     pa_assert(arr->type < 0);
941     
942     dimension = -arr->type;
943     key_type = lua_type(L, 2);
944     
945     switch (key_type) {
946     case LUA_TNUMBER:
947         idx = lua_tointeger(L, 2) - 1;
948         break;
949     case LUA_TSTRING:
950         idx = -1;
951         if ((names = (mrp_lua_strarray_t *)arr->array[dimension])) {
952             pa_assert(dimension == names->nstring);
953             key = lua_tostring(L, 2);
954             pa_assert(key);
955             for (i = 0;  i < dimension;  i++) {
956                 if (!strcmp(key, names->strings[i])) {
957                     idx = i;
958                     break;
959                 }
960             }
961         }
962         break;
963     default:
964         idx = -1;
965         break;
966     }
967
968
969     if (idx < 0 || idx >= dimension || !(value = arr->array[idx]))
970         lua_pushnil(L);
971     else if (value->type < 0)
972         lua_rawgeti(L, 1, 1 - value->type);
973     else {
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;
980         }
981     }
982
983     MRP_LUA_LEAVE(1);
984 }
985
986 static int array_setfield(lua_State *L)
987 {
988     MRP_LUA_ENTER;
989
990     pa_assert(L);
991
992     luaL_error(L, "attempt to write to a read-only object");
993
994     MRP_LUA_LEAVE(0);
995 }
996
997 static int array_getlength(lua_State *L)
998 {
999     MRP_LUA_ENTER;
1000
1001     pa_assert(L);
1002
1003     MRP_LUA_LEAVE(1);
1004 }
1005
1006 #if 0
1007 static void array_destroy(void *data)
1008 {
1009     pa_value *value = (pa_value *)data; 
1010
1011     MRP_LUA_ENTER;
1012
1013     if (value) {
1014         pa_assert(value->type < 0);
1015         pa_xfree(value->array);
1016     }
1017
1018     MRP_LUA_LEAVE_NOARG;
1019 }
1020 #endif
1021
1022 scripting_node *pa_scripting_node_create(struct userdata *u, mir_node *node)
1023 {
1024     pa_scripting *scripting;
1025     lua_State *L;
1026     scripting_node *sn;
1027     char id[256];
1028
1029     pa_assert(u);
1030     pa_assert(node);
1031     pa_assert(node->amname);
1032
1033     pa_assert_se((scripting = u->scripting));
1034     pa_assert_se((L = scripting->L));
1035
1036     make_id(id, sizeof(id), "%s_%d", node->amname, node->index);
1037
1038     if ((sn = (scripting_node *)mrp_lua_create_object(L, NODE_CLASS, id,0))) {
1039         sn->userdata = u;
1040         sn->id = pa_xstrdup(id);
1041         sn->node = node;
1042     }
1043
1044     return sn;
1045 }
1046
1047 void pa_scripting_node_destroy(struct userdata *u, mir_node *node)
1048 {
1049     pa_scripting *scripting;
1050     lua_State *L;
1051     scripting_node *sn;
1052
1053     MRP_LUA_ENTER;
1054
1055     pa_assert(u);
1056     pa_assert(node);
1057     
1058     pa_assert_se((scripting = u->scripting));
1059     pa_assert_se((L = scripting->L));
1060
1061     if ((sn = node->scripting)) {
1062         mrp_lua_destroy_object(L, sn->id,0, sn);
1063         sn->node = NULL;
1064         node->scripting = NULL;
1065     }
1066
1067     MRP_LUA_LEAVE_NOARG;
1068 }
1069
1070 static int node_create(lua_State *L)
1071 {
1072     MRP_LUA_ENTER;
1073
1074     lua_pushnil(L);
1075
1076     MRP_LUA_LEAVE(1);
1077 }
1078
1079 static int node_getfield(lua_State *L)
1080 {
1081     scripting_node *sn;
1082     mir_node *node;
1083     field_t fld;
1084
1085     MRP_LUA_ENTER;
1086
1087     fld = field_check(L, 2, NULL);
1088     lua_pop(L, 1);
1089
1090     if (!(sn = (scripting_node *)mrp_lua_check_object(L, NODE_CLASS, 1)))
1091         lua_pushnil(L);
1092     else {
1093         pa_assert_se((node = sn->node));
1094
1095         switch (fld) {
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;
1107         }
1108     }
1109
1110     MRP_LUA_LEAVE(1);
1111 }
1112
1113 static int node_setfield(lua_State *L)
1114 {
1115     const char *f;
1116
1117     MRP_LUA_ENTER;
1118     
1119     f = luaL_checkstring(L, 2);
1120     luaL_error(L, "attempt to set '%s' field of read-only node", f);
1121
1122     MRP_LUA_LEAVE(0);
1123 }
1124
1125 static int node_tostring(lua_State *L)
1126 {
1127     scripting_node *sn;
1128
1129     MRP_LUA_ENTER;
1130
1131     sn = (scripting_node *)mrp_lua_check_object(L, NODE_CLASS, 1);
1132
1133     lua_pushstring(L, (sn && sn->id) ? sn->id : "<unknown node>");
1134
1135     MRP_LUA_LEAVE(1);
1136 }
1137
1138 static void node_destroy(void *data)
1139 {
1140     scripting_node *sn = (scripting_node *)data;
1141     mir_node *node;
1142
1143     MRP_LUA_ENTER;
1144
1145     if ((node = sn->node) && sn == node->scripting)
1146         node->scripting = NULL;
1147
1148     pa_xfree((void *)sn->id);
1149
1150     MRP_LUA_LEAVE_NOARG;
1151 }
1152
1153
1154 static int zone_create(lua_State *L)
1155 {
1156     static uint32_t index;
1157
1158     struct userdata *u;
1159     size_t fldnamlen;
1160     const char *fldnam;
1161     scripting_zone *zone;
1162     const char *name = NULL;
1163     attribute_t *attributes = NULL;
1164
1165     MRP_LUA_ENTER;
1166
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 "'");
1170     lua_pop(L, 1);
1171
1172
1173     MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
1174
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;
1179         }
1180
1181     } /* MRP_LUA_FOREACH_FIELD */
1182
1183     if (!name)
1184         luaL_error(L, "missing or invalid name field");
1185
1186     if (pa_zoneset_add_zone(u, name, index+1))
1187         luaL_error(L, "attempt to define zone '%s' multiple times", name);
1188
1189     zone = (scripting_zone *)mrp_lua_create_object(L, ZONE_CLASS, name, 0);
1190
1191     zone->userdata = u;
1192     zone->name = pa_xstrdup(name);
1193     zone->index = ++index;
1194
1195
1196     MRP_LUA_LEAVE(1);
1197 }
1198
1199 static int zone_getfield(lua_State *L)
1200 {
1201     scripting_zone *zone;
1202     field_t fld;
1203
1204     MRP_LUA_ENTER;
1205
1206     fld = field_check(L, 2, NULL);
1207     lua_pop(L, 1);
1208
1209     if (!(zone = (scripting_zone *)mrp_lua_check_object(L, ZONE_CLASS, 1)))
1210         lua_pushnil(L);
1211     else {
1212         switch (fld) {
1213         case NAME:           lua_pushstring(L, zone->name);         break;
1214 #if 0
1215         case ATTRIBUTES:     lua_pushinteger(L, rtgs->type);       break;
1216 #endif
1217         default:             lua_pushnil(L);                       break;
1218         }
1219     }
1220
1221     MRP_LUA_LEAVE(1);
1222 }
1223
1224 static int zone_setfield(lua_State *L)
1225 {
1226     const char *f;
1227
1228     MRP_LUA_ENTER;
1229
1230     f = luaL_checkstring(L, 2);
1231     luaL_error(L, "attempt to set '%s' field of read-only zone", f);
1232     
1233     MRP_LUA_LEAVE(0);
1234 }
1235
1236 static void zone_destroy(void *data)
1237 {
1238     scripting_zone *zone = (scripting_zone *)data;
1239
1240     MRP_LUA_ENTER;
1241
1242     pa_xfree((void *)zone->name);
1243     
1244     zone->name = NULL;
1245
1246     MRP_LUA_LEAVE_NOARG;
1247 }
1248
1249
1250 static int resource_create(lua_State *L)
1251 {
1252     struct userdata *u;
1253     size_t fldnamlen;
1254     const char *fldnam;
1255     mir_rtgroup *rtg;
1256     scripting_resource *res;
1257     resource_name_t *name = NULL;
1258     attribute_t *attributes = NULL;
1259     attribute_t *attr;
1260
1261     MRP_LUA_ENTER;
1262
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 "'");
1266     lua_pop(L, 1);
1267
1268
1269     MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
1270
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;
1275         }
1276
1277     } /* MRP_LUA_FOREACH_FIELD */
1278
1279     if (!name)
1280         luaL_error(L, "missing or invalid name field");
1281
1282     pa_murphyif_add_audio_resource(u, mir_input,  name->playback);
1283     pa_murphyif_add_audio_resource(u, mir_output, name->recording);
1284
1285     if (attributes) {
1286         for (attr = attributes;   attr->prop && attr->def.name;   attr++) {
1287             switch (attr->def.type) {
1288             case mqi_string:
1289                 pa_murphyif_add_audio_attribute(u, attr->prop,
1290                                                 attr->def.name,
1291                                                 attr->def.type,
1292                                                 attr->def.value.string);
1293                 break;
1294             case mqi_integer:
1295                 pa_murphyif_add_audio_attribute(u, attr->prop,
1296                                                 attr->def.name,
1297                                                 attr->def.type,
1298                                                 attr->def.value.integer);
1299                 break;
1300             case mqi_unsignd:
1301                 pa_murphyif_add_audio_attribute(u, attr->prop,
1302                                                 attr->def.name,
1303                                                 attr->def.type,
1304                                                 attr->def.value.unsignd);
1305                 break;
1306             case mqi_floating:
1307                 pa_murphyif_add_audio_attribute(u, attr->prop,
1308                                                 attr->def.name,
1309                                                 attr->def.type,
1310                                                 attr->def.value.floating);
1311                 break;
1312             default:
1313                 luaL_error(L, "invalid audio resource attribute '%s'",
1314                            attr->def.name);
1315                 break;
1316             }
1317         }
1318     }
1319
1320     res = (scripting_resource *)mrp_lua_create_object(L, RTGROUP_CLASS,
1321                                                       "definition",0);
1322
1323     res->userdata = u;
1324     res->name = name;
1325     res->attributes = attributes;
1326
1327     MRP_LUA_LEAVE(1);
1328 }
1329
1330 static int resource_getfield(lua_State *L)
1331 {
1332     scripting_resource *res;
1333     field_t fld;
1334
1335     MRP_LUA_ENTER;
1336
1337     fld = field_check(L, 2, NULL);
1338     lua_pop(L, 1);
1339
1340     if (!(res = (scripting_resource*)mrp_lua_check_object(L,RESOURCE_CLASS,1)))
1341         lua_pushnil(L);
1342     else {
1343 #if 0
1344         switch (fld) {
1345         case NAME:           lua_pushstring(L, rtg->name);         break;
1346         case ATTRIBUTES:     lua_pushinteger(L, rtgs->type);       break;
1347         default:             lua_pushnil(L);                       break;
1348         }
1349 #else
1350         lua_pushnil(L);
1351 #endif
1352     }
1353
1354     MRP_LUA_LEAVE(1);
1355 }
1356
1357 static int resource_setfield(lua_State *L)
1358 {
1359     const char *f;
1360
1361     MRP_LUA_ENTER;
1362
1363     f = luaL_checkstring(L, 2);
1364     luaL_error(L, "attempt to set '%s' field of read-only resource_class", f);
1365     
1366     MRP_LUA_LEAVE(0);
1367 }
1368
1369 static void resource_destroy(void *data)
1370 {
1371     scripting_resource *res = (scripting_resource *)data;
1372
1373     MRP_LUA_ENTER;
1374
1375     resource_names_destroy(res->name);
1376     attributes_destroy(res->attributes);
1377     
1378     res->name = NULL;
1379     res->attributes = NULL;
1380
1381     MRP_LUA_LEAVE_NOARG;
1382 }
1383
1384
1385 static int rtgroup_create(lua_State *L)
1386 {
1387     struct userdata *u;
1388     size_t fldnamlen;
1389     const char *fldnam;
1390     mir_rtgroup *rtg;
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;
1396     char id[256];
1397
1398     MRP_LUA_ENTER;
1399
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 "'");
1403     lua_pop(L, 1);
1404
1405
1406     MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
1407
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;
1414         }
1415
1416     } /* MRP_LUA_FOREACH_FIELD */
1417
1418     if (!name)
1419         luaL_error(L, "missing name field");
1420     if (type != mir_input && type != mir_output)
1421         luaL_error(L, "missing or invalid node_type");
1422     if (!accept)
1423         luaL_error(L, "missing or invalid accept field");
1424     if (!compare)
1425         luaL_error(L, "missing or invalid compare field");
1426
1427     make_id(id,sizeof(id), "%s_%sput", name, (type == mir_input) ? "in":"out");
1428
1429     rtgs = (scripting_rtgroup *)mrp_lua_create_object(L, RTGROUP_CLASS, id,0);
1430
1431     rtg  = mir_router_create_rtgroup(u, type, pa_xstrdup(name),
1432                                      rtgroup_accept, rtgroup_compare);
1433     if (!rtgs || !rtg)
1434         luaL_error(L, "failed to create routing group '%s'", id);
1435
1436     rtg->scripting = rtgs;
1437
1438     rtgs->userdata = u;
1439     rtgs->rtg = rtg;
1440     rtgs->type = type;
1441     rtgs->accept = accept;
1442     rtgs->compare = compare;
1443
1444     MRP_LUA_LEAVE(1);
1445 }
1446
1447 static int rtgroup_getfield(lua_State *L)
1448 {
1449     scripting_rtgroup *rtgs;
1450     mir_rtgroup *rtg;
1451     field_t fld;
1452
1453     MRP_LUA_ENTER;
1454
1455     fld = field_check(L, 2, NULL);
1456     lua_pop(L, 1);
1457
1458     if (!(rtgs = (scripting_rtgroup *)mrp_lua_check_object(L,RTGROUP_CLASS,1)))
1459         lua_pushnil(L);
1460     else {
1461         pa_assert_se((rtg = rtgs->rtg));
1462
1463         switch (fld) {
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;
1467         }
1468     }
1469
1470     MRP_LUA_LEAVE(1);
1471 }
1472
1473 static int rtgroup_setfield(lua_State *L)
1474 {
1475     const char *f;
1476
1477     MRP_LUA_ENTER;
1478
1479     f = luaL_checkstring(L, 2);
1480     luaL_error(L, "attempt to set '%s' field of read-only routing_group", f);
1481     
1482     MRP_LUA_LEAVE(0);
1483 }
1484
1485 static int rtgroup_tostring(lua_State *L)
1486 {
1487     scripting_rtgroup *rtgs;
1488     mir_rtgroup *rtg;
1489
1490     MRP_LUA_ENTER;
1491
1492     rtgs = (scripting_rtgroup *)mrp_lua_check_object(L, RTGROUP_CLASS, 1);
1493     pa_assert_se((rtg = rtgs->rtg));
1494
1495     lua_pushstring(L, rtg->name);
1496
1497     MRP_LUA_LEAVE(1);
1498 }
1499
1500 static void rtgroup_destroy(void *data)
1501 {
1502     scripting_rtgroup *rtgs = (scripting_rtgroup *)data;
1503     mir_rtgroup *rtg;
1504
1505     MRP_LUA_ENTER;
1506
1507     pa_assert_se((rtg = rtgs->rtg));
1508     pa_assert(rtgs == rtg->scripting);
1509
1510     rtg->scripting = NULL;
1511
1512     MRP_LUA_LEAVE_NOARG;
1513 }
1514
1515
1516 static bool rtgroup_accept(struct userdata *u,
1517                                 mir_rtgroup *rtg,
1518                                 mir_node *node)
1519 {
1520     pa_scripting *scripting;
1521     lua_State *L;
1522     scripting_rtgroup *rtgs;
1523     mrp_funcbridge_value_t  args[2];
1524     char rt;
1525     mrp_funcbridge_value_t  rv;
1526     bool accept;
1527
1528     pa_assert(u);
1529     pa_assert_se((scripting = u->scripting));
1530     pa_assert_se((L = scripting->L));
1531     pa_assert(rtg);
1532     pa_assert_se((rtgs = rtg->scripting));
1533     pa_assert(u == rtgs->userdata);
1534     pa_assert(rtgs->accept);
1535     pa_assert(node);
1536
1537     accept = false;
1538
1539     if ((rtgs = rtg->scripting) && node->scripting) {
1540
1541         args[0].pointer = rtgs;
1542         args[1].pointer = node->scripting;
1543
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");
1547             else {
1548                 pa_log("call to accept function failed: %s", rv.string);
1549                 mrp_free((void *)rv.string);
1550             }
1551         }
1552         else {
1553             if (rt != MRP_FUNCBRIDGE_BOOLEAN)
1554                 pa_log("accept function returned invalid type");
1555             else
1556                 accept = rv.boolean;
1557         }
1558     }
1559
1560     return accept;
1561 }
1562
1563 static int rtgroup_compare(struct userdata *u,
1564                            mir_rtgroup *rtg,
1565                            mir_node *node1,
1566                            mir_node *node2)
1567 {
1568     pa_scripting *scripting;
1569     lua_State *L;
1570     scripting_rtgroup *rtgs;
1571     mrp_funcbridge_value_t  args[3];
1572     char rt;
1573     mrp_funcbridge_value_t  rv;
1574     int result;
1575
1576     pa_assert(u);
1577     pa_assert_se((scripting = u->scripting));
1578     pa_assert_se((L = scripting->L));
1579     pa_assert(rtg);
1580     pa_assert_se((rtgs = rtg->scripting));
1581     pa_assert(u == rtgs->userdata);
1582     pa_assert(rtgs->compare);
1583     pa_assert(node1);
1584     pa_assert(node2);
1585
1586     result = -1;
1587
1588     if ((rtgs = rtg->scripting) && node1->scripting && node2->scripting) {
1589
1590         args[0].pointer = rtgs;
1591         args[1].pointer = node1->scripting;
1592         args[2].pointer = node2->scripting;
1593
1594         if (!mrp_funcbridge_call_from_c(L, rtgs->compare, "ooo",args, &rt,&rv))
1595             pa_log("failed to call compare function");
1596         else {
1597             if (rt != MRP_FUNCBRIDGE_FLOATING)
1598                 pa_log("compare function returned invalid type");
1599             else
1600                 result = rv.floating;
1601         }
1602     }
1603
1604     return result;
1605 }
1606
1607
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)
1611 {
1612     mir_rtgroup_accept_t accept;
1613     scripting_rtgroup *rtgs;
1614     scripting_node *ns;
1615     struct userdata *u;
1616     mir_rtgroup *rtg;
1617     mir_node *node;
1618     bool success;
1619
1620     (void)L;
1621
1622     pa_assert(signature);
1623     pa_assert(args);
1624     pa_assert(ret_type);
1625     pa_assert(ret_val);
1626
1627     pa_assert_se((accept = (mir_rtgroup_accept_t)data));
1628
1629     if (strcmp(signature, "oo"))
1630         success = false;
1631     else {
1632         pa_assert_se((rtgs = args[0].pointer));
1633         pa_assert_se((u = rtgs->userdata));
1634         pa_assert_se((ns = args[1].pointer));
1635
1636         if (!(rtg = rtgs->rtg) || !(node = ns->node))
1637             success = false;
1638         else {
1639             success = true;
1640             *ret_type = MRP_FUNCBRIDGE_BOOLEAN;
1641             ret_val->boolean = accept(u, rtg, node);
1642         }
1643     }
1644
1645     return success;
1646 }
1647
1648
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)
1652 {
1653     mir_rtgroup_compare_t compare;
1654     scripting_rtgroup *rtgs;
1655     scripting_node *ns1, *ns2;
1656     struct userdata *u;
1657     mir_rtgroup *rtg;
1658     mir_node *node1, *node2;
1659     bool success;
1660
1661     (void)L;
1662
1663     pa_assert(signature);
1664     pa_assert(args);
1665     pa_assert(ret_type);
1666     pa_assert(ret_val);
1667
1668     pa_assert_se((compare = (mir_rtgroup_compare_t)data));
1669
1670     if (strcmp(signature, "ooo"))
1671         success = false;
1672     else {
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));
1677
1678
1679         if (!(rtg = rtgs->rtg) || !(node1 = ns1->node) || !(node2 = ns2->node))
1680             success = false;
1681         else {
1682             success = true;
1683             *ret_type = MRP_FUNCBRIDGE_FLOATING;
1684             ret_val->floating = compare(u, rtg, node1, node2);
1685         }
1686     }
1687
1688     return success;
1689 }
1690
1691
1692 static int apclass_create(lua_State *L)
1693 {
1694     struct userdata *u;
1695     size_t fldnamlen;
1696     const char *fldnam;
1697     scripting_apclass *ac;
1698     char name[256];
1699     const char *class = NULL;
1700     mir_node_type type = -1;
1701     int priority = -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;
1707     map_t *r, *b;
1708     size_t i;
1709     const char *n;
1710     bool ir, or;
1711
1712     MRP_LUA_ENTER;
1713
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 "'");
1717     lua_pop(L, 1);
1718
1719
1720     MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
1721
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;
1730         }
1731
1732     } /* MRP_LUA_FOREACH_FIELD */
1733
1734     if (type < mir_application_class_begin ||
1735         type >= mir_application_class_end    )
1736         luaL_error(L, "missing or invalid node_type %d", type);
1737     if (priority < 0)
1738         luaL_error(L, "missing or invalid priority field");
1739     if (!route)
1740         luaL_error(L, "missing or invalid route field");
1741     if (!roles && !binaries)
1742         luaL_error(L, "missing roles or binaries");
1743
1744     make_id(name, sizeof(name), "%s", mir_node_type_str(type));
1745
1746     mir_router_assign_class_priority(u, type, priority); 
1747
1748     ir = or = true;
1749
1750     if (route->input) {
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);
1754         }
1755     }
1756
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);
1761         }
1762     }
1763
1764     ac = (scripting_apclass *)mrp_lua_create_object(L, APPLICATION_CLASS,
1765                                                     name, 0);
1766
1767     if (!ir || !or || !ac)
1768         luaL_error(L, "failed to create application class '%s'", name);
1769
1770     ac->userdata = u;
1771     ac->name = pa_xstrdup(name);
1772     ac->class = class ? pa_xstrdup(class) : NULL;
1773     ac->type = type;
1774     ac->priority = priority;
1775     ac->route = route;
1776     ac->roles = roles;
1777     ac->binaries = binaries;
1778
1779     if (class) {
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));
1783         }
1784     }
1785
1786     if (roles) {
1787         for (r = roles;  r->name;  r++) {
1788             resdef = r->needres ? &r->resource : NULL;
1789
1790             if (r->role && strcmp(r->role, r->name)) {
1791                 luaL_error(L, "conflicting roles in role definition '%s' (%s)",
1792                            r->name, r->role);
1793             }
1794
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);
1798             }
1799         }
1800     }
1801
1802     if (binaries) {
1803         for (b = binaries;  b->name;  b++) {
1804             resdef = b->needres ? &b->resource : NULL;
1805
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);
1809             }
1810         }
1811     }
1812
1813     MRP_LUA_LEAVE(1);
1814 }
1815
1816 static int apclass_getfield(lua_State *L)
1817 {
1818     scripting_apclass *ac;
1819     field_t fld;
1820
1821     MRP_LUA_ENTER;
1822
1823     fld = field_check(L, 2, NULL);
1824     lua_pop(L, 1);
1825
1826     if (!(ac=(scripting_apclass *)mrp_lua_check_object(L,APPLICATION_CLASS,1)))
1827         lua_pushnil(L);
1828     else {
1829         switch (fld) {
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;
1837         }
1838     }
1839
1840     MRP_LUA_LEAVE(1);
1841 }
1842
1843 static int apclass_setfield(lua_State *L)
1844 {
1845     const char *f;
1846
1847     MRP_LUA_ENTER;
1848
1849     f = luaL_checkstring(L, 2);
1850     luaL_error(L,"attempt to set '%s' field of read-only application class",f);
1851     
1852     MRP_LUA_LEAVE(0);
1853 }
1854
1855 static int apclass_tostring(lua_State *L)
1856 {
1857     scripting_apclass *ac;
1858
1859     MRP_LUA_ENTER;
1860
1861     ac = (scripting_apclass *)mrp_lua_check_object(L, APPLICATION_CLASS, 1);
1862
1863     lua_pushstring(L, ac->name);
1864
1865     MRP_LUA_LEAVE(1);
1866 }
1867
1868 static void apclass_destroy(void *data)
1869 {
1870     scripting_apclass *ac = (scripting_apclass *)data;
1871     struct userdata *u;
1872     map_t *r, *b;
1873     size_t i;
1874
1875     MRP_LUA_ENTER;
1876
1877     pa_assert(ac);
1878     pa_assert_se((u = ac->userdata));
1879
1880     route_destroy(ac->route);
1881     ac->route = NULL;
1882
1883     pa_xfree((void *)ac->name);
1884     ac->name = NULL;
1885
1886     pa_nodeset_delete_class(u, ac->type);
1887     pa_xfree((void *)ac->class);
1888     ac->class = NULL;
1889
1890     if (ac->roles) {
1891         for (r = ac->roles;  r->name;  r++)
1892             pa_nodeset_delete_role(u, r->name);
1893
1894         map_destroy(ac->roles);
1895         ac->roles = NULL;
1896     }
1897
1898     if (ac->binaries) {
1899         for (b = ac->binaries;  b->name;  b++)
1900             pa_nodeset_delete_binary(u, b->name);
1901
1902         map_destroy(ac->binaries);
1903         ac->binaries = NULL;
1904     }
1905
1906     MRP_LUA_LEAVE_NOARG;
1907 }
1908
1909 static const char **route_definition_check(lua_State *L, int idx)
1910 {
1911     size_t zonelen;
1912     const char *zonenam;
1913     scripting_zone *zone;
1914     scripting_rtgroup *rtgs;
1915     mir_rtgroup *rtg;
1916     const char **defs;
1917     const char *rtgnam;
1918     int ndef;
1919
1920     idx = (idx < 0) ? lua_gettop(L) + idx + 1 : idx;
1921
1922     luaL_checktype(L, idx, LUA_TTABLE);
1923
1924     defs = pa_xnew0(const char *, MRP_ZONE_MAX);
1925     ndef = 0;
1926
1927     MRP_LUA_FOREACH_FIELD(L, idx, zonenam, zonelen) {
1928         if (!zonenam[0])
1929             luaL_error(L, "invalid route definition");
1930
1931         mrp_lua_find_object(L, ZONE_CLASS, zonenam);
1932
1933         if (!(zone = mrp_lua_check_object(L, NULL, -1)))
1934             luaL_error(L, "can't find zone '%s'", zonenam);
1935
1936         lua_pop(L, 1);
1937
1938         if (zone->index >= MRP_ZONE_MAX)
1939             luaL_error(L, "Internal error: zone index overflow");
1940
1941         switch (lua_type(L, -1)) {
1942         case LUA_TSTRING:
1943             rtgnam = lua_tostring(L, -1);
1944             break;
1945         case LUA_TTABLE:
1946             rtgs = (scripting_rtgroup*)mrp_lua_check_object(L,RTGROUP_CLASS,-1);
1947             if (!rtgs || !(rtg = rtgs->rtg))
1948                 rtgnam = NULL;
1949             else
1950                 rtgnam = rtg->name;
1951             break;
1952         default:
1953             rtgnam = NULL;
1954             break;
1955         }
1956
1957         if (!rtgnam)
1958             luaL_error(L, "missing or invalid routing group");
1959
1960         defs[zone->index] = pa_xstrdup(rtgnam);
1961         ndef++;
1962     }
1963
1964     if (!ndef)
1965         luaL_error(L, "empty definition");
1966
1967     return defs;
1968 }
1969
1970 static int route_definition_push(lua_State *L, const char **defs)
1971 {
1972     int i;
1973
1974     lua_createtable(L, MRP_ZONE_MAX, 0);
1975
1976     for (i = 0;  i < MRP_ZONE_MAX;  i++) {
1977     }
1978
1979     return 1;
1980 }
1981
1982
1983 static void route_definition_free(const char **defs)
1984 {
1985     int i;
1986
1987     if (defs) {
1988         for (i = 0;  i < MRP_ZONE_MAX;  i++)
1989             pa_xfree((void *)defs[i]);
1990         pa_xfree((void *)defs);
1991     }
1992 }
1993
1994
1995 static route_t *route_check(lua_State *L, int idx)
1996 {
1997     size_t fldnamlen;
1998     const char *fldnam;
1999     route_t *rt;
2000     const char **input = NULL;
2001     const char **output = NULL;
2002
2003     idx = (idx < 0) ? lua_gettop(L) + idx + 1 : idx;
2004
2005     luaL_checktype(L, idx, LUA_TTABLE);
2006
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;
2012         }
2013     } /* MRP_LUA_FOREACH_FIELD */
2014
2015     if (!input && !output)
2016         luaL_error(L, "neither input nor output routing group were specified");
2017
2018     rt = pa_xmalloc(sizeof(route_t));
2019     rt->input  = input;
2020     rt->output = output;
2021
2022     return rt;
2023 }
2024
2025 static int route_push(lua_State *L, route_t *rt)
2026 {
2027     if (!rt || (!rt->input && !rt->output))
2028         lua_pushnil(L);
2029     else {
2030         lua_createtable(L, 0, 2);
2031
2032         if (rt->input) {
2033             lua_pushstring(L, "input");
2034             route_definition_push(L, rt->input);
2035             lua_settable(L, -3);
2036         }
2037         
2038         if (rt->output) {
2039             lua_pushstring(L, "output");
2040             route_definition_push(L, rt->output);
2041             lua_settable(L, -3);
2042         }
2043     }
2044
2045     return 1;
2046 }
2047
2048 static void route_destroy(route_t *rt)
2049 {
2050     if (rt) {
2051         pa_xfree((void *)rt->input);
2052         pa_xfree((void *)rt->output);
2053         pa_xfree((void *)rt);
2054     }
2055 }
2056
2057
2058 static int vollim_create(lua_State *L)
2059 {
2060     static int min = mir_application_class_begin;
2061     static int max = mir_application_class_end;
2062
2063     struct userdata *u;
2064     size_t fldnamlen;
2065     const char *fldnam;
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;
2074     size_t arglgh = 0;
2075     size_t i;
2076     int class;
2077     uint32_t mask, clmask;
2078     char id[256];
2079
2080     MRP_LUA_ENTER;
2081
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 "'");
2085     lua_pop(L, 1);
2086
2087
2088     MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
2089
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;
2097         }
2098
2099     } /* MRP_LUA_FOREACH_FIELD */
2100
2101     if (!name)
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");
2109     if (!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");
2120                 suppress = true;
2121                 arglgh = sizeof(mir_volume_suppress_arg);
2122             }
2123             else if (calculate->c.data == mir_volume_correction) {
2124                 if (type != vollim_generic) {
2125                     luaL_error(L, "attempt to make class based volume"
2126                                "correction");
2127                 }
2128                 correct = true;
2129                 arglgh = sizeof(double *);
2130             }
2131             else {
2132                 luaL_error(L, "invalid builtin.method for calculate");
2133             }
2134         }
2135         else {
2136             switch (type) {
2137             case vollim_class:
2138                 suppress = true;
2139                 arglgh = sizeof(mir_volume_suppress_arg);
2140                 break;
2141             case vollim_generic:
2142                 correct = true;
2143                 arglgh = sizeof(double *);
2144                 break;
2145             default:
2146                 break;
2147             }
2148         }
2149     }
2150
2151     make_id(id, sizeof(id), "%s", name);
2152
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);
2156
2157     vlim->userdata = u;
2158     vlim->name = pa_xstrdup(name);
2159     vlim->type = type;
2160     vlim->classes = classes;
2161     vlim->limit = limit;
2162     vlim->calculate = calculate;
2163
2164     if (suppress) {
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;
2168
2169         for (i = 0, clmask = 0;   i < classes->nint;   i++) {
2170             class = classes->ints[i];
2171
2172             if (class <= mir_application_class_begin ||
2173                 class >  mir_application_class_end     )
2174             {
2175                 pa_log("invalid triggering class id %d", class);
2176                 clmask = 0;
2177                 classes->nint = n = 0;
2178                 break;
2179             }
2180
2181             mask = ((uint32_t)1) << (class - mir_application_class_begin);
2182
2183             if (!(clmask & mask) && n > 0)
2184                 n--;
2185
2186             clmask |= mask;
2187         }
2188
2189         args->attenuation = limit->value;
2190         args->trigger.nclass = classes->nint;
2191         args->trigger.classes = pa_xmalloc(size);
2192         args->trigger.clmask = clmask;
2193
2194         memcpy(args->trigger.classes, classes->ints, size);
2195
2196         if (n > classes->nint)
2197             classes->ints = pa_xrealloc(classes->ints, sizeof(int) * n);
2198         classes->nint = n;
2199
2200         for (i = mir_application_class_begin, n = 0;
2201              i < mir_application_class_end;
2202              i++)
2203         {
2204             if (!(clmask & (((uint32_t)1) << (i-mir_application_class_begin))))
2205                 classes->ints[n++] = i;
2206         }
2207     }
2208     else if (correct) {
2209         /* *(double **)vlim->args = limit->value; */
2210     
2211         memcpy(vlim->args, &limit->value, sizeof(limit->value));
2212     }
2213
2214     switch (type) {
2215     case vollim_generic:
2216         mir_volume_add_generic_limit(u, vollim_calculate, vlim->args);
2217         break;
2218     case vollim_class:
2219         for (i = 0;  i < classes->nint;  i++) {
2220             mir_volume_add_class_limit(u, classes->ints[i], vollim_calculate,
2221                                        vlim->args);
2222         }
2223         break;
2224     case vollim_maximum:
2225         mir_volume_add_maximum_limit(u, *(vlim->limit->value),
2226                                      classes->nint, classes->ints);
2227         break;
2228     default:
2229         break;
2230     }
2231
2232     MRP_LUA_LEAVE(1);
2233 }
2234
2235 static int vollim_getfield(lua_State *L)
2236 {
2237     scripting_vollim *vlim;
2238     field_t fld;
2239
2240     MRP_LUA_ENTER;
2241
2242     fld = field_check(L, 2, NULL);
2243     lua_pop(L, 1);
2244
2245     if (!(vlim = (scripting_vollim *)mrp_lua_check_object(L, VOLLIM_CLASS, 1)))
2246         lua_pushnil(L);
2247     else {
2248         switch (fld) {
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;
2254         }
2255     }
2256
2257     MRP_LUA_LEAVE(1);
2258 }
2259
2260 static int vollim_setfield(lua_State *L)
2261 {
2262     const char *f;
2263
2264     MRP_LUA_ENTER;
2265
2266     f = luaL_checkstring(L, 2);
2267     luaL_error(L, "attempt to set '%s' field of read-only volume_limit", f);
2268     
2269     MRP_LUA_LEAVE(0);
2270 }
2271
2272 static int vollim_tostring(lua_State *L)
2273 {
2274     scripting_vollim *vlim;
2275
2276     MRP_LUA_ENTER;
2277
2278     vlim = (scripting_vollim *)mrp_lua_check_object(L, VOLLIM_CLASS, 1);
2279
2280     lua_pushstring(L, vlim->name);
2281
2282     MRP_LUA_LEAVE(1);
2283 }
2284
2285 static void vollim_destroy(void *data)
2286 {
2287     scripting_vollim *vlim = (scripting_vollim *)data;
2288
2289     MRP_LUA_ENTER;
2290
2291     pa_xfree((void *)vlim->name);
2292     intarray_destroy(vlim->classes);
2293     limit_data_destroy(vlim->limit);
2294
2295     MRP_LUA_LEAVE_NOARG;
2296 }
2297
2298
2299 static double vollim_calculate(struct userdata *u, int class, mir_node *node,
2300                                void *data)
2301 {
2302     static int offset = ((scripting_vollim *)0)->args - (char *)0;
2303
2304     pa_scripting *scripting;
2305     lua_State *L;
2306     scripting_vollim *vlim;
2307     mrp_funcbridge_value_t args[3];
2308     char rt;
2309     mrp_funcbridge_value_t  rv;
2310     double limit;
2311
2312     pa_assert(u);
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)     );
2317     pa_assert(node);
2318
2319     vlim = (scripting_vollim *)(data - offset);
2320
2321     pa_assert(u == vlim->userdata);
2322
2323     limit = -90.0;
2324
2325     if (node->scripting) {
2326
2327         args[0].pointer = vlim;
2328         args[1].integer = class;
2329         args[2].pointer = node->scripting;
2330
2331         if (!mrp_funcbridge_call_from_c(L,vlim->calculate,"odo",args,&rt,&rv))
2332             pa_log("failed to call calculate function");
2333         else {
2334             if (rt != MRP_FUNCBRIDGE_FLOATING)
2335                 pa_log("accept function returned invalid type");
2336             else
2337                 limit = rv.floating;
2338         }
2339     }
2340
2341     return limit;
2342 }
2343
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)
2347 {
2348     mir_volume_func_t calculate;
2349     scripting_vollim *vlim;
2350     scripting_node *ns;
2351     struct userdata *u;
2352     int class;
2353     mir_node *node;
2354     bool success;
2355
2356     (void)L;
2357
2358     pa_assert(signature);
2359     pa_assert(args);
2360     pa_assert(ret_type);
2361     pa_assert(ret_val);
2362
2363     pa_assert_se((calculate = (mir_volume_func_t)data));
2364
2365     if (strcmp(signature, "odo"))
2366         success = false;
2367     else {
2368         pa_assert_se((vlim = args[0].pointer));
2369         pa_assert_se((u = vlim->userdata));
2370         pa_assert_se((ns = args[2].pointer));
2371
2372         class = args[1].integer;
2373
2374         pa_assert(!class || (class >= mir_application_class_begin &&
2375                              class <  mir_application_class_end));
2376
2377         if (!(node = ns->node))
2378             success = false;
2379         else {
2380             success = true;
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);
2384         }
2385     }
2386
2387     return success;
2388 }
2389
2390 static limit_data_t *limit_data_check(lua_State *L, int idx)
2391 {
2392     static double nolimit = 0.0;
2393
2394     limit_data_t *ld;
2395     double value;
2396     pa_value *v;
2397
2398     switch (lua_type(L, idx)) {
2399     case LUA_TNUMBER:
2400         if ((value = lua_tonumber(L, idx)) > 0.0)
2401             luaL_error(L, "volume limit is in dB and can't be positive");
2402         else {
2403             ld = pa_xnew0(limit_data_t, 1);
2404             ld->mallocd = true;
2405             ld->value = pa_xnew0(double, 1);
2406             *ld->value = value;
2407         }
2408         break;
2409     case LUA_TLIGHTUSERDATA:
2410         if (!(v = lua_touserdata(L, idx)) || v->type < 0)
2411             luaL_error(L, "broken link for volume limit value");
2412         else {
2413             ld = pa_xnew0(limit_data_t, 1);
2414             ld->mallocd = false;
2415             ld->value = &v->floating;
2416         }
2417         break;
2418     default:
2419         ld->mallocd = false;
2420         ld->value = &nolimit;
2421         break;
2422     }
2423
2424     return ld;
2425 }
2426
2427 #if 0
2428 static int limit_data_push(lua_State *L, limit_data_t *ld)
2429 {
2430     if (ld)
2431         lua_pushnumber(L, *ld->value);
2432     else
2433         lua_pushnil;
2434
2435     return 1;
2436 }
2437 #endif
2438
2439 static void limit_data_destroy(limit_data_t *ld)
2440 {
2441     if (ld) {
2442         if (ld->mallocd)
2443             pa_xfree(ld->value);
2444         pa_xfree(ld);
2445     }
2446 }
2447
2448
2449 static intarray_t *intarray_check(lua_State *L, int idx, int min, int max)
2450 {
2451     size_t len;
2452     size_t size;
2453     intarray_t *arr;
2454     int val;
2455     size_t i;
2456
2457     idx = (idx < 0) ? lua_gettop(L) + idx + 1 : idx;
2458
2459     luaL_checktype(L, idx, LUA_TTABLE);
2460
2461     if ((len = luaL_getn(L, idx)) < 1)
2462         arr = NULL;
2463     else {
2464         size = sizeof(intarray_t) + sizeof(int) * len;
2465         arr  = pa_xmalloc0(sizeof(intarray_t));
2466
2467         arr->nint = len;
2468         arr->ints = pa_xmalloc0(size);
2469
2470         for (i = 0;  i < len;  i++) {
2471             lua_pushnumber(L, (int)(i+1));
2472             lua_gettable(L, idx);
2473             
2474             val = luaL_checkint(L, -1);
2475             
2476             lua_pop(L, 1);
2477             
2478             if (val < min || val >= max)
2479                 luaL_error(L, "array [%u]: out of range value (%d)", i, val); 
2480             
2481             arr->ints[i] = val;
2482         }
2483     }
2484
2485     return arr;
2486 }
2487
2488 static int intarray_push(lua_State *L, intarray_t *arr)
2489 {
2490     size_t i;
2491
2492     if (!arr)
2493         lua_pushnil(L);
2494     else {
2495         lua_createtable(L, arr->nint, 0);
2496
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);
2501         }
2502     }
2503
2504     return 1;
2505 }
2506
2507 static void intarray_destroy(intarray_t *arr)
2508 {
2509     if (arr) {
2510         pa_xfree(arr->ints);
2511         pa_xfree(arr);
2512     }
2513 }
2514
2515 static resource_name_t *resource_names_check(lua_State *L, int tbl)
2516 {
2517     resource_name_t *name;
2518     size_t fldnamlen;
2519     const char *fldnam;
2520     const char *value;
2521
2522     tbl = (tbl < 0) ? lua_gettop(L) + tbl + 1 : tbl;
2523
2524     luaL_checktype(L, tbl, LUA_TTABLE);
2525
2526     name = pa_xnew0(resource_name_t, 1);
2527
2528     MRP_LUA_FOREACH_FIELD(L, tbl, fldnam, fldnamlen) {
2529         value = luaL_checkstring(L, -1);
2530
2531         if (!strcmp(fldnam, "recording"))
2532             name->recording = pa_xstrdup(value);
2533         else if (!strcmp(fldnam, "playback"))
2534             name->playback = pa_xstrdup(value);
2535         else {
2536             luaL_error(L, "invalid field '%s' in resource name definition",
2537                        fldnam);
2538         }
2539     }
2540
2541     return name;
2542 }
2543
2544 static void resource_names_destroy(resource_name_t *name)
2545 {
2546     if (name) {
2547         pa_xfree((void *)name->recording);
2548         pa_xfree((void *)name->playback);
2549         pa_xfree(name);
2550     }
2551 }
2552
2553 static attribute_t *attributes_check(lua_State *L, int tbl)
2554 {
2555     int def;
2556     size_t fldnamlen;
2557     const char *fldnam;
2558     attribute_t *attr, *attrs = NULL;
2559     size_t nattr = 0;
2560     mrp_attr_value_t *v;
2561     size_t i, len;
2562
2563     tbl = (tbl < 0) ? lua_gettop(L) + tbl + 1 : tbl;
2564
2565     luaL_checktype(L, tbl, LUA_TTABLE);
2566
2567     MRP_LUA_FOREACH_FIELD(L, tbl, fldnam, fldnamlen) {
2568         if (!fldnam[0])
2569             luaL_error(L, "invalid attribute definition");
2570
2571         attrs = pa_xrealloc(attrs, sizeof(attribute_t) * (nattr + 2));
2572         memset(attrs + nattr, 0, sizeof(attribute_t) * 2);
2573
2574         attr = attrs + nattr++;
2575         v = &attr->def.value;
2576         def = lua_gettop(L);
2577
2578         attr->def.name = pa_xstrdup(fldnam);
2579         
2580         if ((len = luaL_getn(L, def)) != 3)
2581             luaL_error(L, "invalid attribute definition '%s'", fldnam);
2582
2583         for (i = 0;  i < len;  i++) {
2584             lua_pushnumber(L, (int)(i+1));
2585             lua_gettable(L, def);
2586
2587             switch (i) {
2588             case 0:  attr->prop = pa_xstrdup(luaL_checkstring(L,-1));    break;
2589             case 1:  attr->def.type = luaL_checkint(L,-1);               break;
2590             case 2:
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;
2597                 }
2598             }
2599
2600             lua_pop(L, 1);
2601         }
2602
2603         if (!attr->prop)
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)
2607         {
2608             luaL_error(L, "invalid attribute type %d for '%s'",
2609                        attr->def.type, fldnam);
2610         }
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);
2614         }
2615     }
2616
2617     return attrs;
2618 }
2619
2620 static void attributes_destroy(attribute_t *attrs)
2621 {
2622     attribute_t *attr;
2623
2624     if (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);
2630         }
2631         pa_xfree(attrs);
2632     }
2633 }
2634
2635 static map_t *map_check(lua_State *L, int tbl)
2636 {
2637     int def;
2638     size_t namlen;
2639     const char *name;
2640     const char *option;
2641     const char *role;
2642     map_t *m, *map = NULL;
2643     size_t n = 0;
2644     size_t i, len;
2645     int priority;
2646     pa_nodeset_resdef *rd;
2647
2648     tbl = (tbl < 0) ? lua_gettop(L) + tbl + 1 : tbl;
2649
2650     luaL_checktype(L, tbl, LUA_TTABLE);
2651
2652     MRP_LUA_FOREACH_FIELD(L, tbl, name, namlen) {
2653         if (!name[0])
2654             luaL_error(L, "invalid role or binary definition");
2655
2656         map = pa_xrealloc(map, sizeof(map_t) * (n + 2));
2657         memset(map + n, 0, sizeof(map_t) * 2);
2658
2659         m = map + n++;
2660         def = lua_gettop(L);
2661
2662         m->name = pa_xstrdup(name);
2663
2664         switch (lua_type(L, -1)) {
2665
2666         case LUA_TNUMBER:
2667             m->needres = false;
2668             break;
2669
2670         case LUA_TSTRING:
2671             m->needres = FALSE;
2672             m->role = mrp_strdup(lua_tostring(L, def));
2673             break;
2674             
2675         case LUA_TTABLE:
2676             m->needres = true;
2677
2678             if ((len = luaL_getn(L, def)) < 1)
2679                 luaL_error(L, "invalid resource definition '%s'", name);
2680
2681             for (i = 1;  i <= len;  i++) {
2682                 lua_pushnumber(L, (int)i);
2683                 lua_gettable(L, def);
2684
2685                 if (i == 1) {
2686                     priority = luaL_checkint(L, -1);
2687
2688                     if (priority < 0 || priority > 7) {
2689                         luaL_error(L, "invalid priority %d for '%s'",
2690                                    priority, name);
2691                     }
2692
2693                     m->resource.priority = priority;
2694                 }
2695                 else {
2696                     option = luaL_checkstring(L, -1);
2697                     rd = &m->resource;
2698
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") )
2707                     {
2708                         if (!m->role)
2709                             m->role = pa_xstrdup(option);
2710                         else {
2711                             luaL_error(L, "multiple role definition '%s','%s'",
2712                                        m->role, option);
2713                         }
2714                     }
2715                 }
2716
2717                 lua_pop(L, 1);
2718             }
2719
2720             break;
2721
2722         default:
2723             luaL_error(L, "invalid resource specification. "
2724                        "Should be either 'no_resource' or a table");
2725             break;
2726         }
2727     } /* FOREACH_FIELD */
2728
2729     return map;
2730 }
2731
2732 static int map_push(lua_State *L, map_t *map)
2733 {
2734     map_t *m;
2735
2736     if (!map)
2737         lua_pushnil(L);
2738     else {
2739         lua_newtable(L);
2740
2741         for (m = map;  m->name;  m++) {
2742             if (!m->needres) {
2743                 if (m->role)
2744                     lua_pushstring(L, m->role);
2745                 else
2746                     lua_pushnumber(L, 0);
2747             }
2748             else {
2749                 lua_newtable(L);
2750                 lua_pushinteger(L, m->resource.priority);
2751                 if (m->role)
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");
2757                 else
2758                     lua_pushstring(L, "optional");
2759                 if (m->resource.flags.audio & RESPROTO_RESFLAG_SHARED)
2760                     lua_pushstring(L, "shared");
2761                 else
2762                     lua_pushstring(L, "exclusive");
2763             }
2764             lua_setfield(L, -2, m->name);
2765         }
2766     }
2767
2768     return 1;
2769 }
2770
2771 static void map_destroy(map_t *map)
2772 {
2773     map_t *m;
2774
2775     if (map) {
2776         for (m = map;  m->name;  m++) {
2777             pa_xfree((void *)m->name);
2778             pa_xfree((void *)m->role);
2779         }
2780         pa_xfree(map);
2781     }
2782 }
2783
2784
2785 static field_t field_check(lua_State *L, int idx, const char **ret_fldnam)
2786 {
2787     const char *fldnam;
2788     size_t fldnamlen;
2789     field_t fldtyp;
2790
2791     if (!(fldnam = lua_tolstring(L, idx, &fldnamlen)))
2792         fldtyp = 0;
2793     else
2794         fldtyp = field_name_to_type(fldnam, fldnamlen);
2795
2796     if (ret_fldnam)
2797         *ret_fldnam = fldnam;
2798
2799     return fldtyp;
2800 }
2801
2802 static field_t field_name_to_type(const char *name, size_t len)
2803 {
2804     switch (len) {
2805
2806     case 4:
2807         switch (name[0]) {
2808         case 'n':
2809             if (!strcmp(name, "name"))
2810                 return NAME;
2811             break;
2812         case 't':
2813             if (!strcmp(name, "type"))
2814                 return TYPE;
2815             break;
2816         case 'z':
2817             if (!strcmp(name, "zone"))
2818                 return ZONE;
2819             break;
2820         default:
2821             break;
2822         }
2823         break;
2824
2825     case 5:
2826         switch (name[0]) {
2827         case 'c':
2828             if (!strcmp(name, "class"))
2829                 return CLASS;
2830             break;
2831         case 'i':
2832             if (!strcmp(name, "input"))
2833                 return INPUT;
2834             break;
2835         case 'l':
2836             if (!strcmp(name, "limit"))
2837                 return LIMIT;
2838             break;
2839         case 'r':
2840             if (!strcmp(name, "route"))
2841                 return ROUTE;
2842             if (!strcmp(name, "roles"))
2843                 return ROLES;
2844             break;
2845         case 't':
2846             if (!strcmp(name, "table"))
2847                 return TABLE;
2848             break;
2849         default:
2850             break;
2851         }
2852         break;
2853
2854     case 6:
2855         switch (name[0]) {
2856         case 'a':
2857             if (!strcmp(name, "accept"))
2858                 return ACCEPT;
2859             break;
2860         case 'm':
2861             if (!strcmp(name, "maxrow"))
2862                 return MAXROW;
2863             break;
2864         case 'o':
2865             if (!strcmp(name, "output"))
2866                 return OUTPUT;
2867             break;
2868         case 't':
2869             if (!strcmp(name, "tables"))
2870                 return TABLES;
2871             break;
2872         case 'u':
2873             if (!strcmp(name, "update"))
2874                 return UPDATE;
2875             break;
2876         default:
2877             break;
2878         }
2879         break;
2880
2881     case 7:
2882         switch (name[0]) {
2883         case 'c':
2884             if (!strcmp(name, "compare"))
2885                 return COMPARE;
2886             if (!strcmp(name, "columns"))
2887                 return COLUMNS;
2888             break;
2889         case 'p':
2890             if (!strcmp(name, "privacy"))
2891                 return PRIVACY;
2892             break;
2893         default:
2894             break;
2895         }
2896         break;
2897
2898     case 8:
2899         switch (name[0]) {
2900         case 'b':
2901             if (!strcmp(name, "binaries"))
2902                 return BINARIES;
2903             break;
2904         case 'c':
2905             if (!strcmp(name, "channels"))
2906                 return CHANNELS;
2907             break;
2908         case 'l':
2909             if (!strcmp(name, "location"))
2910                 return LOCATION;
2911             break;
2912         case 'p':
2913             if (!strcmp(name, "priority"))
2914                 return PRIORITY;
2915             break;
2916         default:
2917             break;
2918         }
2919         break;
2920
2921     case 9:
2922         switch (name[0]) {
2923         case 'a':
2924             if (!strcmp(name, "available"))
2925                 return AVAILABLE;
2926             break;
2927         case 'c':
2928             if (!strcmp(name, "calculate"))
2929                 return CALCULATE;
2930             if (!strcmp(name, "condition"))
2931                 return CONDITION;
2932             break;
2933         case 'd':
2934             if (!strcmp(name, "direction"))
2935                 return DIRECTION;
2936             break;
2937         case 'i':
2938             if (!strcmp(name, "implement"))
2939                 return IMPLEMENT;
2940             break;
2941         case 'n':
2942             if (!strcmp(name, "node_type"))
2943                 return NODE_TYPE;
2944             break;
2945         default:
2946             break;
2947         }
2948         break;
2949
2950     case 10:
2951         if (!strcmp(name, "attributes"))
2952             return ATTRIBUTES;
2953         break;        
2954
2955     case 11:
2956         if (!strcmp(name, "autorelease"))
2957             return AUTORELEASE;
2958         if (!strcmp(name, "description"))
2959             return DESCRIPTION;
2960         break;        
2961
2962     default:
2963         break;
2964     }
2965
2966     return 0;
2967 }
2968
2969 static int make_id(char *buf, size_t len, const char *fmt, ...)
2970 {
2971     va_list ap;
2972     int l;
2973     char *p, c;
2974
2975     va_start(ap, fmt);
2976     l = vsnprintf(buf, len, fmt, ap);
2977     va_end(ap);
2978
2979     for (p = buf;  (c = *p);  p++) {
2980         if (isalpha(c))
2981             c = tolower(c);
2982         else if (!isdigit(c))
2983             c = '_';
2984         *p = c;
2985     }
2986
2987     return l;
2988 }
2989
2990
2991 static void setup_murphy_interface(struct userdata *u)
2992 {
2993     pa_scripting *scripting;
2994     scripting_import *imp;
2995     const char *key;
2996     lua_State *L;
2997     int class;
2998     bool need_domainctl;
2999     char buf[8192];
3000     const char *columns;
3001     int top;
3002     pa_value *values;
3003
3004     MRP_LUA_ENTER;
3005
3006     pa_assert(u);
3007     pa_assert_se((scripting = u->scripting));
3008     pa_assert_se((L = scripting->L));
3009
3010     top = lua_gettop(L);
3011
3012     mrp_lua_get_class_table(L, IMPORT_CLASS);
3013     class = lua_gettop(L);
3014
3015     if (!lua_istable(L, class)){
3016         luaL_error(L, "internal error: failed to find '%s' table",
3017                    (IMPORT_CLASS)->constructor);
3018     }
3019
3020     need_domainctl = false;
3021
3022     lua_pushnil(L);
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);
3027
3028                 pa_assert(!strcmp(key, imp->table));
3029                 pa_assert_se((values = imp->values));
3030
3031                 pa_log_debug("adding import '%s'", imp->table);
3032
3033                 need_domainctl = true;
3034                 columns = comma_separated_list(imp->columns, buf,sizeof(buf));
3035
3036                 pa_murphyif_add_watch(u, imp->table, columns, imp->condition,
3037                                       -values->type);
3038             }
3039         }
3040         lua_pop(L, 1);
3041     }
3042
3043     if (need_domainctl)
3044         pa_murphyif_setup_domainctl(u, import_data_changed);
3045
3046     lua_settop(L, top);
3047
3048     MRP_LUA_LEAVE_NOARG;
3049 }
3050
3051
3052 static char *comma_separated_list(mrp_lua_strarray_t *arr, char *buf, int len)
3053 {
3054     char *p, *e;
3055     size_t i;
3056
3057     pa_assert(arr);
3058     pa_assert(buf);
3059     pa_assert(len > 0);
3060
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]);
3063
3064     return (p < e) ? buf : NULL;
3065 }
3066
3067
3068 static bool define_constants(lua_State *L)
3069 {
3070     static const_def_t mdb_const[] = {
3071         { "string"           , mqi_string           },
3072         { "integer"          , mqi_integer          },
3073         { "unsigned"         , mqi_unsignd          },
3074         { "floating"         , mqi_floating         },
3075         {       NULL         ,         0            }
3076     };
3077
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   },
3109         {       NULL         ,         0            }
3110     };
3111
3112     static const_def_t vollim_const[] = {
3113         { "class"            , vollim_class         },
3114         { "generic"          , vollim_generic       },
3115         { "maximum"          , vollim_maximum       },
3116         {       NULL         ,         0            }
3117     };
3118
3119     const_def_t *cd;
3120     bool success = true;
3121
3122
3123     lua_getglobal(L, "mdb");
3124
3125     if (!lua_istable(L, -1))
3126         success = false;
3127     else {
3128         for (cd = mdb_const;   cd->name;   cd++) {
3129             lua_pushstring(L, cd->name);
3130             lua_pushinteger(L, cd->value);
3131             lua_rawset(L, -3);
3132         }
3133         lua_pop(L, 1);
3134     }
3135
3136
3137
3138     lua_getglobal(L, "node");
3139
3140     if (!lua_istable(L, -1))
3141         success = false;
3142     else {
3143         for (cd = node_const;   cd->name;   cd++) {
3144             lua_pushstring(L, cd->name);
3145             lua_pushinteger(L, cd->value);
3146             lua_rawset(L, -3);
3147         }
3148         lua_pop(L, 1);
3149     }
3150
3151
3152     lua_getglobal(L, "volume_limit");
3153
3154     if (!lua_istable(L, -1))
3155         success = false;
3156     else {
3157         for (cd = vollim_const;   cd->name;   cd++) {
3158             lua_pushstring(L, cd->name);
3159             lua_pushinteger(L, cd->value);
3160             lua_rawset(L, -3);
3161         }
3162         lua_pop(L, 1);
3163     }
3164
3165     lua_pushnumber(L, 0);
3166     lua_setglobal(L, "no_resource");
3167
3168     return success;
3169 }
3170
3171
3172 static bool register_methods(lua_State *L)
3173 {
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             }
3184     };
3185
3186     funcbridge_def_t *d;
3187     bool success = true;
3188
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'",
3192                    __FILE__, d->name);
3193             success = false;
3194         }
3195     }
3196
3197     return success;
3198 }
3199
3200
3201
3202 static void *alloc(void *ud, void *ptr, size_t osize, size_t nsize)
3203 {
3204     void *mem;
3205
3206     (void)ud;
3207     (void)osize;
3208
3209     if (nsize)
3210         mem = pa_xrealloc(ptr, nsize);
3211     else {
3212         mem = NULL;
3213         pa_xfree(ptr);
3214     }
3215
3216     return mem;
3217 }
3218
3219 static int panic(lua_State *L)
3220 {
3221     (void)L;
3222
3223     pa_log("PANIC: unprotected error in call to Lua API (%s)",
3224            lua_tostring(L,-1));
3225
3226     return 0;
3227 }
3228
3229                                   
3230 /*
3231  * Local Variables:
3232  * c-basic-offset: 4
3233  * indent-tabs-mode: nil
3234  * End:
3235  *
3236  */