introducing maximum volume limit for streams
[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 && calculate->type == MRP_C_FUNCTION) {
2114         if (strcmp(calculate->c.signature, "odo"))
2115             luaL_error(L, "invalid calculate field (mismatching signature)");
2116         if (calculate->c.data == mir_volume_suppress) {
2117             if (type != vollim_class)
2118                 luaL_error(L, "attempt to make generic volume supression");
2119             suppress = true;
2120             arglgh = sizeof(mir_volume_suppress_arg);
2121         }
2122         else if (calculate->c.data == mir_volume_correction) {
2123             if (type != vollim_generic)
2124                 luaL_error(L, "attempt to make class based volume correction");
2125             correct = true;
2126             arglgh = sizeof(double *);
2127         }
2128         else {
2129             luaL_error(L, "invalid builtin.method for calculate");
2130         }
2131     }
2132
2133     make_id(id, sizeof(id), "%s", name);
2134
2135     (VOLLIM_CLASS)->userdata_size = sizeof(scripting_vollim) + arglgh;
2136     vlim = (scripting_vollim *)mrp_lua_create_object(L, VOLLIM_CLASS, id,0);
2137     (VOLLIM_CLASS)->userdata_size = sizeof(scripting_vollim);
2138
2139     vlim->userdata = u;
2140     vlim->name = pa_xstrdup(name);
2141     vlim->type = type;
2142     vlim->classes = classes;
2143     vlim->limit = limit;
2144     vlim->calculate = calculate;
2145
2146     if (suppress) {
2147         mir_volume_suppress_arg *args = (mir_volume_suppress_arg *)vlim->args;
2148         size_t size = sizeof(int) * classes->nint;
2149         size_t n = mir_application_class_end - mir_application_class_begin;
2150
2151         for (i = 0, clmask = 0;   i < classes->nint;   i++) {
2152             class = classes->ints[i];
2153
2154             if (class <= mir_application_class_begin ||
2155                 class >  mir_application_class_end     )
2156             {
2157                 pa_log("invalid triggering class id %d", class);
2158                 clmask = 0;
2159                 classes->nint = n = 0;
2160                 break;
2161             }
2162
2163             mask = ((uint32_t)1) << (class - mir_application_class_begin);
2164
2165             if (!(clmask & mask) && n > 0)
2166                 n--;
2167
2168             clmask |= mask;
2169         }
2170
2171         args->attenuation = limit->value;
2172         args->trigger.nclass = classes->nint;
2173         args->trigger.classes = pa_xmalloc(size);
2174         args->trigger.clmask = clmask;
2175
2176         memcpy(args->trigger.classes, classes->ints, size);
2177
2178         if (n > classes->nint)
2179             classes->ints = pa_xrealloc(classes->ints, sizeof(int) * n);
2180         classes->nint = n;
2181
2182         for (i = mir_application_class_begin, n = 0;
2183              i < mir_application_class_end;
2184              i++)
2185         {
2186             if (!(clmask & (((uint32_t)1) << (i-mir_application_class_begin))))
2187                 classes->ints[n++] = i;
2188         }
2189     }
2190     else if (correct) {
2191         /* *(double **)vlim->args = limit->value; */
2192     
2193         memcpy(vlim->args, &limit->value, sizeof(limit->value));
2194     }
2195
2196     switch (type) {
2197     case vollim_generic:
2198         mir_volume_add_generic_limit(u, vollim_calculate, vlim->args);
2199         break;
2200     case vollim_class:
2201         for (i = 0;  i < classes->nint;  i++) {
2202             mir_volume_add_class_limit(u, classes->ints[i], vollim_calculate,
2203                                        vlim->args);
2204         }
2205         break;
2206     case vollim_maximum:
2207         mir_volume_add_maximum_limit(u, *(vlim->limit->value),
2208                                      classes->nint, classes->ints);
2209         break;
2210     default:
2211         break;
2212     }
2213
2214     MRP_LUA_LEAVE(1);
2215 }
2216
2217 static int vollim_getfield(lua_State *L)
2218 {
2219     scripting_vollim *vlim;
2220     field_t fld;
2221
2222     MRP_LUA_ENTER;
2223
2224     fld = field_check(L, 2, NULL);
2225     lua_pop(L, 1);
2226
2227     if (!(vlim = (scripting_vollim *)mrp_lua_check_object(L, VOLLIM_CLASS, 1)))
2228         lua_pushnil(L);
2229     else {
2230         switch (fld) {
2231         case NAME:         lua_pushstring(L, vlim->name);           break;
2232         case TYPE:         lua_pushinteger(L, vlim->type);          break;
2233         case NODE_TYPE:    intarray_push(L, vlim->classes);         break;
2234         case LIMIT:        lua_pushnumber(L, *vlim->limit->value);  break;
2235         default:           lua_pushnil(L);                          break;
2236         }
2237     }
2238
2239     MRP_LUA_LEAVE(1);
2240 }
2241
2242 static int vollim_setfield(lua_State *L)
2243 {
2244     const char *f;
2245
2246     MRP_LUA_ENTER;
2247
2248     f = luaL_checkstring(L, 2);
2249     luaL_error(L, "attempt to set '%s' field of read-only volume_limit", f);
2250     
2251     MRP_LUA_LEAVE(0);
2252 }
2253
2254 static int vollim_tostring(lua_State *L)
2255 {
2256     scripting_vollim *vlim;
2257
2258     MRP_LUA_ENTER;
2259
2260     vlim = (scripting_vollim *)mrp_lua_check_object(L, VOLLIM_CLASS, 1);
2261
2262     lua_pushstring(L, vlim->name);
2263
2264     MRP_LUA_LEAVE(1);
2265 }
2266
2267 static void vollim_destroy(void *data)
2268 {
2269     scripting_vollim *vlim = (scripting_vollim *)data;
2270
2271     MRP_LUA_ENTER;
2272
2273     pa_xfree((void *)vlim->name);
2274     intarray_destroy(vlim->classes);
2275     limit_data_destroy(vlim->limit);
2276
2277     MRP_LUA_LEAVE_NOARG;
2278 }
2279
2280
2281 static double vollim_calculate(struct userdata *u, int class, mir_node *node,
2282                                void *data)
2283 {
2284     static int offset = ((scripting_vollim *)0)->args - (char *)0;
2285
2286     pa_scripting *scripting;
2287     lua_State *L;
2288     scripting_vollim *vlim;
2289     mrp_funcbridge_value_t args[3];
2290     char rt;
2291     mrp_funcbridge_value_t  rv;
2292     double limit;
2293
2294     pa_assert(u);
2295     pa_assert_se((scripting = u->scripting));
2296     pa_assert_se((L = scripting->L));
2297     pa_assert(!class || (class >= mir_application_class_begin &&
2298                          class <  mir_application_class_end)     );
2299     pa_assert(node);
2300
2301     vlim = (scripting_vollim *)(data - offset);
2302
2303     pa_assert(u == vlim->userdata);
2304
2305     limit = -90.0;
2306
2307     if (node->scripting) {
2308
2309         args[0].pointer = vlim;
2310         args[1].integer = class;
2311         args[2].pointer = node->scripting;
2312
2313         if (!mrp_funcbridge_call_from_c(L,vlim->calculate,"odo",args,&rt,&rv))
2314             pa_log("failed to call calculate function");
2315         else {
2316             if (rt != MRP_FUNCBRIDGE_FLOATING)
2317                 pa_log("accept function returned invalid type");
2318             else
2319                 limit = rv.floating;
2320         }
2321     }
2322
2323     return limit;
2324 }
2325
2326 static bool calculate_bridge(lua_State *L, void *data, const char *signature,
2327                              mrp_funcbridge_value_t *args,
2328                              char *ret_type, mrp_funcbridge_value_t *ret_val)
2329 {
2330     mir_volume_func_t calculate;
2331     scripting_vollim *vlim;
2332     scripting_node *ns;
2333     struct userdata *u;
2334     int class;
2335     mir_node *node;
2336     bool success;
2337
2338     (void)L;
2339
2340     pa_assert(signature);
2341     pa_assert(args);
2342     pa_assert(ret_type);
2343     pa_assert(ret_val);
2344
2345     pa_assert_se((calculate = (mir_volume_func_t)data));
2346
2347     if (strcmp(signature, "odo"))
2348         success = false;
2349     else {
2350         pa_assert_se((vlim = args[0].pointer));
2351         pa_assert_se((u = vlim->userdata));
2352         pa_assert_se((ns = args[2].pointer));
2353
2354         class = args[1].integer;
2355
2356         pa_assert(!class || (class >= mir_application_class_begin &&
2357                              class <  mir_application_class_end));
2358
2359         if (!(node = ns->node))
2360             success = false;
2361         else {
2362             success = true;
2363             *ret_type = MRP_FUNCBRIDGE_FLOATING;
2364             ret_val->floating = calculate(u, class, node, vlim->args);
2365         }
2366     }
2367
2368     return success;
2369 }
2370
2371 static limit_data_t *limit_data_check(lua_State *L, int idx)
2372 {
2373     static double nolimit = 0.0;
2374
2375     limit_data_t *ld;
2376     double value;
2377     pa_value *v;
2378
2379     switch (lua_type(L, idx)) {
2380     case LUA_TNUMBER:
2381         if ((value = lua_tonumber(L, idx)) > 0.0)
2382             luaL_error(L, "volume limit is in dB and can't be positive");
2383         else {
2384             ld = pa_xnew0(limit_data_t, 1);
2385             ld->mallocd = true;
2386             ld->value = pa_xnew0(double, 1);
2387             *ld->value = value;
2388         }
2389         break;
2390     case LUA_TLIGHTUSERDATA:
2391         if (!(v = lua_touserdata(L, idx)) || v->type < 0)
2392             luaL_error(L, "broken link for volume limit value");
2393         else {
2394             ld = pa_xnew0(limit_data_t, 1);
2395             ld->mallocd = false;
2396             ld->value = &v->floating;
2397         }
2398         break;
2399     default:
2400         ld->mallocd = false;
2401         ld->value = &nolimit;
2402         break;
2403     }
2404
2405     return ld;
2406 }
2407
2408 #if 0
2409 static int limit_data_push(lua_State *L, limit_data_t *ld)
2410 {
2411     if (ld)
2412         lua_pushnumber(L, *ld->value);
2413     else
2414         lua_pushnil;
2415
2416     return 1;
2417 }
2418 #endif
2419
2420 static void limit_data_destroy(limit_data_t *ld)
2421 {
2422     if (ld) {
2423         if (ld->mallocd)
2424             pa_xfree(ld->value);
2425         pa_xfree(ld);
2426     }
2427 }
2428
2429
2430 static intarray_t *intarray_check(lua_State *L, int idx, int min, int max)
2431 {
2432     size_t len;
2433     size_t size;
2434     intarray_t *arr;
2435     int val;
2436     size_t i;
2437
2438     idx = (idx < 0) ? lua_gettop(L) + idx + 1 : idx;
2439
2440     luaL_checktype(L, idx, LUA_TTABLE);
2441
2442     if ((len = luaL_getn(L, idx)) < 1)
2443         arr = NULL;
2444     else {
2445         size = sizeof(intarray_t) + sizeof(int) * len;
2446         arr  = pa_xmalloc0(sizeof(intarray_t));
2447
2448         arr->nint = len;
2449         arr->ints = pa_xmalloc0(size);
2450
2451         for (i = 0;  i < len;  i++) {
2452             lua_pushnumber(L, (int)(i+1));
2453             lua_gettable(L, idx);
2454             
2455             val = luaL_checkint(L, -1);
2456             
2457             lua_pop(L, 1);
2458             
2459             if (val < min || val >= max)
2460                 luaL_error(L, "array [%u]: out of range value (%d)", i, val); 
2461             
2462             arr->ints[i] = val;
2463         }
2464     }
2465
2466     return arr;
2467 }
2468
2469 static int intarray_push(lua_State *L, intarray_t *arr)
2470 {
2471     size_t i;
2472
2473     if (!arr)
2474         lua_pushnil(L);
2475     else {
2476         lua_createtable(L, arr->nint, 0);
2477
2478         for (i = 0;  i < arr->nint;  i++) {
2479             lua_pushinteger(L, (int)(i+1));
2480             lua_pushinteger(L, arr->ints[i]);
2481             lua_settable(L, -3);
2482         }
2483     }
2484
2485     return 1;
2486 }
2487
2488 static void intarray_destroy(intarray_t *arr)
2489 {
2490     if (arr) {
2491         pa_xfree(arr->ints);
2492         pa_xfree(arr);
2493     }
2494 }
2495
2496 static resource_name_t *resource_names_check(lua_State *L, int tbl)
2497 {
2498     resource_name_t *name;
2499     size_t fldnamlen;
2500     const char *fldnam;
2501     const char *value;
2502
2503     tbl = (tbl < 0) ? lua_gettop(L) + tbl + 1 : tbl;
2504
2505     luaL_checktype(L, tbl, LUA_TTABLE);
2506
2507     name = pa_xnew0(resource_name_t, 1);
2508
2509     MRP_LUA_FOREACH_FIELD(L, tbl, fldnam, fldnamlen) {
2510         value = luaL_checkstring(L, -1);
2511
2512         if (!strcmp(fldnam, "recording"))
2513             name->recording = pa_xstrdup(value);
2514         else if (!strcmp(fldnam, "playback"))
2515             name->playback = pa_xstrdup(value);
2516         else {
2517             luaL_error(L, "invalid field '%s' in resource name definition",
2518                        fldnam);
2519         }
2520     }
2521
2522     return name;
2523 }
2524
2525 static void resource_names_destroy(resource_name_t *name)
2526 {
2527     if (name) {
2528         pa_xfree((void *)name->recording);
2529         pa_xfree((void *)name->playback);
2530         pa_xfree(name);
2531     }
2532 }
2533
2534 static attribute_t *attributes_check(lua_State *L, int tbl)
2535 {
2536     int def;
2537     size_t fldnamlen;
2538     const char *fldnam;
2539     attribute_t *attr, *attrs = NULL;
2540     size_t nattr = 0;
2541     mrp_attr_value_t *v;
2542     size_t i, len;
2543
2544     tbl = (tbl < 0) ? lua_gettop(L) + tbl + 1 : tbl;
2545
2546     luaL_checktype(L, tbl, LUA_TTABLE);
2547
2548     MRP_LUA_FOREACH_FIELD(L, tbl, fldnam, fldnamlen) {
2549         if (!fldnam[0])
2550             luaL_error(L, "invalid attribute definition");
2551
2552         attrs = pa_xrealloc(attrs, sizeof(attribute_t) * (nattr + 2));
2553         memset(attrs + nattr, 0, sizeof(attribute_t) * 2);
2554
2555         attr = attrs + nattr++;
2556         v = &attr->def.value;
2557         def = lua_gettop(L);
2558
2559         attr->def.name = pa_xstrdup(fldnam);
2560         
2561         if ((len = luaL_getn(L, def)) != 3)
2562             luaL_error(L, "invalid attribute definition '%s'", fldnam);
2563
2564         for (i = 0;  i < len;  i++) {
2565             lua_pushnumber(L, (int)(i+1));
2566             lua_gettable(L, def);
2567
2568             switch (i) {
2569             case 0:  attr->prop = pa_xstrdup(luaL_checkstring(L,-1));    break;
2570             case 1:  attr->def.type = luaL_checkint(L,-1);               break;
2571             case 2:
2572                 switch (attr->def.type) {
2573                 case mqi_string:   v->string = luaL_checkstring(L,-1);   break;
2574                 case mqi_integer:  v->integer = luaL_checkint(L,-1);     break;
2575                 case mqi_unsignd:  v->integer = luaL_checkint(L,-1);     break;
2576                 case mqi_floating: v->floating = luaL_checknumber(L,-1); break;
2577                 default:           memset(v, 0, sizeof(*v));             break;
2578                 }
2579             }
2580
2581             lua_pop(L, 1);
2582         }
2583
2584         if (!attr->prop)
2585             luaL_error(L, "missing property name definition from '%s'",fldnam);
2586         if (attr->def.type != mqi_string  && attr->def.type != mqi_integer &&
2587             attr->def.type != mqi_unsignd && attr->def.type != mqi_floating)
2588         {
2589             luaL_error(L, "invalid attribute type %d for '%s'",
2590                        attr->def.type, fldnam);
2591         }
2592         if (attr->def.type == mqi_unsignd && attr->def.value.integer < 0) {
2593             luaL_error(L, "attempt to give negative value (%d) for field '%s'",
2594                        attr->def.value.integer, fldnam);
2595         }
2596     }
2597
2598     return attrs;
2599 }
2600
2601 static void attributes_destroy(attribute_t *attrs)
2602 {
2603     attribute_t *attr;
2604
2605     if (attrs) {
2606         for (attr = attrs;  attr->prop && attr->def.name;  attr++) {
2607             pa_xfree((void *)attr->prop);
2608             pa_xfree((void *)attr->def.name);
2609             if (attr->def.type == mqi_string)
2610                 pa_xfree((void *)attr->def.value.string);
2611         }
2612         pa_xfree(attrs);
2613     }
2614 }
2615
2616 static map_t *map_check(lua_State *L, int tbl)
2617 {
2618     int def;
2619     size_t namlen;
2620     const char *name;
2621     const char *option;
2622     const char *role;
2623     map_t *m, *map = NULL;
2624     size_t n = 0;
2625     size_t i, len;
2626     int priority;
2627     pa_nodeset_resdef *rd;
2628
2629     tbl = (tbl < 0) ? lua_gettop(L) + tbl + 1 : tbl;
2630
2631     luaL_checktype(L, tbl, LUA_TTABLE);
2632
2633     MRP_LUA_FOREACH_FIELD(L, tbl, name, namlen) {
2634         if (!name[0])
2635             luaL_error(L, "invalid role or binary definition");
2636
2637         map = pa_xrealloc(map, sizeof(map_t) * (n + 2));
2638         memset(map + n, 0, sizeof(map_t) * 2);
2639
2640         m = map + n++;
2641         def = lua_gettop(L);
2642
2643         m->name = pa_xstrdup(name);
2644
2645         switch (lua_type(L, -1)) {
2646
2647         case LUA_TNUMBER:
2648             m->needres = false;
2649             break;
2650
2651         case LUA_TSTRING:
2652             m->needres = FALSE;
2653             m->role = mrp_strdup(lua_tostring(L, def));
2654             break;
2655             
2656         case LUA_TTABLE:
2657             m->needres = true;
2658
2659             if ((len = luaL_getn(L, def)) < 1)
2660                 luaL_error(L, "invalid resource definition '%s'", name);
2661
2662             for (i = 1;  i <= len;  i++) {
2663                 lua_pushnumber(L, (int)i);
2664                 lua_gettable(L, def);
2665
2666                 if (i == 1) {
2667                     priority = luaL_checkint(L, -1);
2668
2669                     if (priority < 0 || priority > 7) {
2670                         luaL_error(L, "invalid priority %d for '%s'",
2671                                    priority, name);
2672                     }
2673
2674                     m->resource.priority = priority;
2675                 }
2676                 else {
2677                     option = luaL_checkstring(L, -1);
2678                     rd = &m->resource;
2679
2680                     if (pa_streq(option, "autorelease"))
2681                         rd->flags.rset |= RESPROTO_RSETFLAG_AUTORELEASE;
2682                     else if (pa_streq(option, "mandatory"))
2683                         rd->flags.audio |= RESPROTO_RESFLAG_MANDATORY;
2684                     else if (pa_streq(option, "shared"))
2685                         rd->flags.audio |= RESPROTO_RESFLAG_SHARED;
2686                     else if (!pa_streq(option, "optional") &&
2687                              !pa_streq(option, "exclusive") )
2688                     {
2689                         if (!m->role)
2690                             m->role = pa_xstrdup(option);
2691                         else {
2692                             luaL_error(L, "multiple role definition '%s','%s'",
2693                                        m->role, option);
2694                         }
2695                     }
2696                 }
2697
2698                 lua_pop(L, 1);
2699             }
2700
2701             break;
2702
2703         default:
2704             luaL_error(L, "invalid resource specification. "
2705                        "Should be either 'no_resource' or a table");
2706             break;
2707         }
2708     } /* FOREACH_FIELD */
2709
2710     return map;
2711 }
2712
2713 static int map_push(lua_State *L, map_t *map)
2714 {
2715     map_t *m;
2716
2717     if (!map)
2718         lua_pushnil(L);
2719     else {
2720         lua_newtable(L);
2721
2722         for (m = map;  m->name;  m++) {
2723             if (!m->needres) {
2724                 if (m->role)
2725                     lua_pushstring(L, m->role);
2726                 else
2727                     lua_pushnumber(L, 0);
2728             }
2729             else {
2730                 lua_newtable(L);
2731                 lua_pushinteger(L, m->resource.priority);
2732                 if (m->role)
2733                     lua_pushstring(L, m->role);
2734                 if (m->resource.flags.rset & RESPROTO_RSETFLAG_AUTORELEASE)
2735                     lua_pushstring(L, "autorelease");
2736                 if (m->resource.flags.audio & RESPROTO_RESFLAG_MANDATORY)
2737                     lua_pushstring(L, "mandatory");
2738                 else
2739                     lua_pushstring(L, "optional");
2740                 if (m->resource.flags.audio & RESPROTO_RESFLAG_SHARED)
2741                     lua_pushstring(L, "shared");
2742                 else
2743                     lua_pushstring(L, "exclusive");
2744             }
2745             lua_setfield(L, -2, m->name);
2746         }
2747     }
2748
2749     return 1;
2750 }
2751
2752 static void map_destroy(map_t *map)
2753 {
2754     map_t *m;
2755
2756     if (map) {
2757         for (m = map;  m->name;  m++) {
2758             pa_xfree((void *)m->name);
2759             pa_xfree((void *)m->role);
2760         }
2761         pa_xfree(map);
2762     }
2763 }
2764
2765
2766 static field_t field_check(lua_State *L, int idx, const char **ret_fldnam)
2767 {
2768     const char *fldnam;
2769     size_t fldnamlen;
2770     field_t fldtyp;
2771
2772     if (!(fldnam = lua_tolstring(L, idx, &fldnamlen)))
2773         fldtyp = 0;
2774     else
2775         fldtyp = field_name_to_type(fldnam, fldnamlen);
2776
2777     if (ret_fldnam)
2778         *ret_fldnam = fldnam;
2779
2780     return fldtyp;
2781 }
2782
2783 static field_t field_name_to_type(const char *name, size_t len)
2784 {
2785     switch (len) {
2786
2787     case 4:
2788         switch (name[0]) {
2789         case 'n':
2790             if (!strcmp(name, "name"))
2791                 return NAME;
2792             break;
2793         case 't':
2794             if (!strcmp(name, "type"))
2795                 return TYPE;
2796             break;
2797         case 'z':
2798             if (!strcmp(name, "zone"))
2799                 return ZONE;
2800             break;
2801         default:
2802             break;
2803         }
2804         break;
2805
2806     case 5:
2807         switch (name[0]) {
2808         case 'c':
2809             if (!strcmp(name, "class"))
2810                 return CLASS;
2811             break;
2812         case 'i':
2813             if (!strcmp(name, "input"))
2814                 return INPUT;
2815             break;
2816         case 'l':
2817             if (!strcmp(name, "limit"))
2818                 return LIMIT;
2819             break;
2820         case 'r':
2821             if (!strcmp(name, "route"))
2822                 return ROUTE;
2823             if (!strcmp(name, "roles"))
2824                 return ROLES;
2825             break;
2826         case 't':
2827             if (!strcmp(name, "table"))
2828                 return TABLE;
2829             break;
2830         default:
2831             break;
2832         }
2833         break;
2834
2835     case 6:
2836         switch (name[0]) {
2837         case 'a':
2838             if (!strcmp(name, "accept"))
2839                 return ACCEPT;
2840             break;
2841         case 'm':
2842             if (!strcmp(name, "maxrow"))
2843                 return MAXROW;
2844             break;
2845         case 'o':
2846             if (!strcmp(name, "output"))
2847                 return OUTPUT;
2848             break;
2849         case 't':
2850             if (!strcmp(name, "tables"))
2851                 return TABLES;
2852             break;
2853         case 'u':
2854             if (!strcmp(name, "update"))
2855                 return UPDATE;
2856             break;
2857         default:
2858             break;
2859         }
2860         break;
2861
2862     case 7:
2863         switch (name[0]) {
2864         case 'c':
2865             if (!strcmp(name, "compare"))
2866                 return COMPARE;
2867             if (!strcmp(name, "columns"))
2868                 return COLUMNS;
2869             break;
2870         case 'p':
2871             if (!strcmp(name, "privacy"))
2872                 return PRIVACY;
2873             break;
2874         default:
2875             break;
2876         }
2877         break;
2878
2879     case 8:
2880         switch (name[0]) {
2881         case 'b':
2882             if (!strcmp(name, "binaries"))
2883                 return BINARIES;
2884             break;
2885         case 'c':
2886             if (!strcmp(name, "channels"))
2887                 return CHANNELS;
2888             break;
2889         case 'l':
2890             if (!strcmp(name, "location"))
2891                 return LOCATION;
2892             break;
2893         case 'p':
2894             if (!strcmp(name, "priority"))
2895                 return PRIORITY;
2896             break;
2897         default:
2898             break;
2899         }
2900         break;
2901
2902     case 9:
2903         switch (name[0]) {
2904         case 'a':
2905             if (!strcmp(name, "available"))
2906                 return AVAILABLE;
2907             break;
2908         case 'c':
2909             if (!strcmp(name, "calculate"))
2910                 return CALCULATE;
2911             if (!strcmp(name, "condition"))
2912                 return CONDITION;
2913             break;
2914         case 'd':
2915             if (!strcmp(name, "direction"))
2916                 return DIRECTION;
2917             break;
2918         case 'i':
2919             if (!strcmp(name, "implement"))
2920                 return IMPLEMENT;
2921             break;
2922         case 'n':
2923             if (!strcmp(name, "node_type"))
2924                 return NODE_TYPE;
2925             break;
2926         default:
2927             break;
2928         }
2929         break;
2930
2931     case 10:
2932         if (!strcmp(name, "attributes"))
2933             return ATTRIBUTES;
2934         break;        
2935
2936     case 11:
2937         if (!strcmp(name, "autorelease"))
2938             return AUTORELEASE;
2939         if (!strcmp(name, "description"))
2940             return DESCRIPTION;
2941         break;        
2942
2943     default:
2944         break;
2945     }
2946
2947     return 0;
2948 }
2949
2950 static int make_id(char *buf, size_t len, const char *fmt, ...)
2951 {
2952     va_list ap;
2953     int l;
2954     char *p, c;
2955
2956     va_start(ap, fmt);
2957     l = vsnprintf(buf, len, fmt, ap);
2958     va_end(ap);
2959
2960     for (p = buf;  (c = *p);  p++) {
2961         if (isalpha(c))
2962             c = tolower(c);
2963         else if (!isdigit(c))
2964             c = '_';
2965         *p = c;
2966     }
2967
2968     return l;
2969 }
2970
2971
2972 static void setup_murphy_interface(struct userdata *u)
2973 {
2974     pa_scripting *scripting;
2975     scripting_import *imp;
2976     const char *key;
2977     lua_State *L;
2978     int class;
2979     bool need_domainctl;
2980     char buf[8192];
2981     const char *columns;
2982     int top;
2983     pa_value *values;
2984
2985     MRP_LUA_ENTER;
2986
2987     pa_assert(u);
2988     pa_assert_se((scripting = u->scripting));
2989     pa_assert_se((L = scripting->L));
2990
2991     top = lua_gettop(L);
2992
2993     mrp_lua_get_class_table(L, IMPORT_CLASS);
2994     class = lua_gettop(L);
2995
2996     if (!lua_istable(L, class)){
2997         luaL_error(L, "internal error: failed to find '%s' table",
2998                    (IMPORT_CLASS)->constructor);
2999     }
3000
3001     need_domainctl = false;
3002
3003     lua_pushnil(L);
3004     while (lua_next(L, class)) {
3005         if (lua_isstring(L, -2)) {
3006             if ((imp = mrp_lua_to_object(L, IMPORT_CLASS, -1))) {
3007                 key = lua_tostring(L, -2);
3008
3009                 pa_assert(!strcmp(key, imp->table));
3010                 pa_assert_se((values = imp->values));
3011
3012                 pa_log_debug("adding import '%s'", imp->table);
3013
3014                 need_domainctl = true;
3015                 columns = comma_separated_list(imp->columns, buf,sizeof(buf));
3016
3017                 pa_murphyif_add_watch(u, imp->table, columns, imp->condition,
3018                                       -values->type);
3019             }
3020         }
3021         lua_pop(L, 1);
3022     }
3023
3024     if (need_domainctl)
3025         pa_murphyif_setup_domainctl(u, import_data_changed);
3026
3027     lua_settop(L, top);
3028
3029     MRP_LUA_LEAVE_NOARG;
3030 }
3031
3032
3033 static char *comma_separated_list(mrp_lua_strarray_t *arr, char *buf, int len)
3034 {
3035     char *p, *e;
3036     size_t i;
3037
3038     pa_assert(arr);
3039     pa_assert(buf);
3040     pa_assert(len > 0);
3041
3042     for (i = 0, e = (p = buf) + len;   i < arr->nstring && p < e;    i++)
3043         p += snprintf(p, e-p, "%s%s", (p == buf ? "" : ","), arr->strings[i]);
3044
3045     return (p < e) ? buf : NULL;
3046 }
3047
3048
3049 static bool define_constants(lua_State *L)
3050 {
3051     static const_def_t mdb_const[] = {
3052         { "string"           , mqi_string           },
3053         { "integer"          , mqi_integer          },
3054         { "unsigned"         , mqi_unsignd          },
3055         { "floating"         , mqi_floating         },
3056         {       NULL         ,         0            }
3057     };
3058
3059     static const_def_t node_const[] = {
3060         { "input"            , mir_input            },
3061         { "output"           , mir_output           },
3062         { "device"           , mir_device           },
3063         { "stream"           , mir_stream           },
3064         { "internal"         , mir_internal         },
3065         { "external"         , mir_external         },
3066         { "radio"            , mir_radio            },
3067         { "player"           , mir_player           },
3068         { "navigator"        , mir_navigator        },
3069         { "game"             , mir_game             },
3070         { "browser"          , mir_browser          },
3071         { "camera"           , mir_camera           },
3072         { "phone"            , mir_phone            },
3073         { "alert"            , mir_alert            },
3074         { "event"            , mir_event            },
3075         { "system"           , mir_system           },
3076         { "speakers"         , mir_speakers         },
3077         { "microphone"       , mir_microphone       },
3078         { "jack"             , mir_jack             },
3079         { "spdif"            , mir_spdif            },
3080         { "hdmi"             , mir_hdmi             },
3081         { "wired_headset"    , mir_wired_headset    },
3082         { "wired_headphone"  , mir_wired_headphone  },
3083         { "usb_headset"      , mir_usb_headset      },
3084         { "usb_headphone"    , mir_usb_headphone    },
3085         { "bluetooth_sco"    , mir_bluetooth_sco    },
3086         { "bluetooth_a2dp"   , mir_bluetooth_a2dp   },
3087         { "bluetooth_carkit" , mir_bluetooth_carkit },
3088         { "bluetooth_source" , mir_bluetooth_source },
3089         { "bluetooth_sink"   , mir_bluetooth_sink   },
3090         {       NULL         ,         0            }
3091     };
3092
3093     static const_def_t vollim_const[] = {
3094         { "class"            , vollim_class         },
3095         { "generic"          , vollim_generic       },
3096         { "maximum"          , vollim_maximum       },
3097         {       NULL         ,         0            }
3098     };
3099
3100     const_def_t *cd;
3101     bool success = true;
3102
3103
3104     lua_getglobal(L, "mdb");
3105
3106     if (!lua_istable(L, -1))
3107         success = false;
3108     else {
3109         for (cd = mdb_const;   cd->name;   cd++) {
3110             lua_pushstring(L, cd->name);
3111             lua_pushinteger(L, cd->value);
3112             lua_rawset(L, -3);
3113         }
3114         lua_pop(L, 1);
3115     }
3116
3117
3118
3119     lua_getglobal(L, "node");
3120
3121     if (!lua_istable(L, -1))
3122         success = false;
3123     else {
3124         for (cd = node_const;   cd->name;   cd++) {
3125             lua_pushstring(L, cd->name);
3126             lua_pushinteger(L, cd->value);
3127             lua_rawset(L, -3);
3128         }
3129         lua_pop(L, 1);
3130     }
3131
3132
3133     lua_getglobal(L, "volume_limit");
3134
3135     if (!lua_istable(L, -1))
3136         success = false;
3137     else {
3138         for (cd = vollim_const;   cd->name;   cd++) {
3139             lua_pushstring(L, cd->name);
3140             lua_pushinteger(L, cd->value);
3141             lua_rawset(L, -3);
3142         }
3143         lua_pop(L, 1);
3144     }
3145
3146     lua_pushnumber(L, 0);
3147     lua_setglobal(L, "no_resource");
3148
3149     return success;
3150 }
3151
3152
3153 static bool register_methods(lua_State *L)
3154 {
3155     static funcbridge_def_t funcbridge_defs[] = {
3156         {"make_routes"    ,"o"  , update_bridge   ,mir_router_make_routing   },
3157         {"make_volumes"   ,"o"  , update_bridge   ,mir_volume_make_limiting  },
3158         {"accept_default" ,"oo" , accept_bridge   ,mir_router_default_accept },
3159         {"compare_default","ooo", compare_bridge  ,mir_router_default_compare},
3160         {"accept_phone"   ,"oo" , accept_bridge   ,mir_router_phone_accept   },
3161         {"compare_phone"  ,"ooo", compare_bridge  ,mir_router_phone_compare  },
3162         {"volume_supress" ,"odo", calculate_bridge,mir_volume_suppress       },
3163         {"volume_correct" ,"odo", calculate_bridge,mir_volume_correction     },
3164         {       NULL      , NULL,      NULL       ,         NULL             }
3165     };
3166
3167     funcbridge_def_t *d;
3168     bool success = true;
3169
3170     for (d = funcbridge_defs;   d->name;    d++) {
3171         if (!mrp_funcbridge_create_cfunc(L,d->name,d->sign,d->func,d->data)) {
3172             pa_log("%s: failed to register builtin function '%s'",
3173                    __FILE__, d->name);
3174             success = false;
3175         }
3176     }
3177
3178     return success;
3179 }
3180
3181
3182
3183 static void *alloc(void *ud, void *ptr, size_t osize, size_t nsize)
3184 {
3185     void *mem;
3186
3187     (void)ud;
3188     (void)osize;
3189
3190     if (nsize)
3191         mem = pa_xrealloc(ptr, nsize);
3192     else {
3193         mem = NULL;
3194         pa_xfree(ptr);
3195     }
3196
3197     return mem;
3198 }
3199
3200 static int panic(lua_State *L)
3201 {
3202     (void)L;
3203
3204     pa_log("PANIC: unprotected error in call to Lua API (%s)",
3205            lua_tostring(L,-1));
3206
3207     return 0;
3208 }
3209
3210                                   
3211 /*
3212  * Local Variables:
3213  * c-basic-offset: 4
3214  * indent-tabs-mode: nil
3215  * End:
3216  *
3217  */