scripting: support for zone based routing in application classes
[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     pa_bool_t 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     pa_bool_t           needres;
135     pa_nodeset_resdef   resource;
136 } map_t;
137
138 struct scripting_apclass {
139     struct userdata    *userdata;
140     const char         *name;
141     const char         *class;
142     mir_node_type       type;
143     int                 priority;
144     route_t            *route;
145     map_t              *roles;
146     map_t              *binaries;
147     struct {
148         pa_bool_t resource;
149     }                   needs;
150 };
151
152 typedef enum {
153     vollim_class = 1,
154     vollim_generic
155 } vollim_type;
156
157 typedef struct {
158     size_t      nint;
159     int        *ints;
160 } intarray_t;
161
162 typedef struct {
163     pa_bool_t   mallocd;
164     double     *value;
165 } limit_data_t;
166
167 struct scripting_vollim {
168     struct userdata  *userdata;
169     const char       *name;
170     vollim_type       type;
171     intarray_t       *classes;
172     limit_data_t     *limit;
173     mrp_funcbridge_t *calculate;
174     char              args[0];
175 };
176
177
178 typedef struct {
179     const char *name;
180     int value;
181 } const_def_t;
182
183 typedef struct {
184     const char *name;
185     const char *sign;
186     mrp_funcbridge_cfunc_t func;
187     void *data;
188 } funcbridge_def_t;
189
190 typedef enum {
191     NAME = 1,
192     TYPE,
193     ZONE,
194     CLASS,
195     INPUT,
196     LIMIT,
197     ROUTE,
198     ROLES,
199     TABLE,
200     ACCEPT,
201     MAXROW,
202     OUTPUT,
203     TABLES,
204     UPDATE,
205     COMPARE,
206     COLUMNS,
207     PRIVACY,
208     BINARIES,
209     CHANNELS,
210     LOCATION,
211     PRIORITY,
212     AVAILABLE,
213     CALCULATE,
214     CONDITION,
215     DIRECTION,
216     IMPLEMENT,
217     NODE_TYPE,
218     ATTRIBUTES,
219     AUTORELEASE,
220     DESCRIPTION,
221 } field_t;
222
223 static int  import_create(lua_State *);
224 static int  import_getfield(lua_State *);
225 static int  import_setfield(lua_State *);
226 static int  import_tostring(lua_State *);
227 static void import_destroy(void *);
228
229 static int  import_link(lua_State *);
230
231 static void import_data_changed(struct userdata *, const char *,
232                                 int, mrp_domctl_value_t **);
233 static bool update_bridge(lua_State *, void *, const char *,
234                           mrp_funcbridge_value_t *, char *,
235                           mrp_funcbridge_value_t *);
236
237 static void array_class_create(lua_State *);
238 static pa_value *array_create(lua_State *, int, mrp_lua_strarray_t *);
239 static int  array_getfield(lua_State *);
240 static int  array_setfield(lua_State *);
241 static int  array_getlength(lua_State *);
242
243 #if 0
244 static void array_destroy(void *);
245 #endif
246
247 static int  node_create(lua_State *);
248 static int  node_getfield(lua_State *);
249 static int  node_setfield(lua_State *);
250 static int  node_tostring(lua_State *);
251 static void node_destroy(void *);
252
253 static int  zone_create(lua_State *);
254 static int  zone_getfield(lua_State *);
255 static int  zone_setfield(lua_State *);
256 static void zone_destroy(void *);
257
258 static int  resource_create(lua_State *);
259 static int  resource_getfield(lua_State *);
260 static int  resource_setfield(lua_State *);
261 static void resource_destroy(void *);
262
263 static int  rtgroup_create(lua_State *);
264 static int  rtgroup_getfield(lua_State *);
265 static int  rtgroup_setfield(lua_State *);
266 static int  rtgroup_tostring(lua_State *);
267 static void rtgroup_destroy(void *);
268
269 static pa_bool_t rtgroup_accept(struct userdata *, mir_rtgroup *, mir_node *);
270 static int  rtgroup_compare(struct userdata *, mir_rtgroup *,
271                             mir_node *, mir_node *);
272
273 static bool accept_bridge(lua_State *, void *, const char *,
274                           mrp_funcbridge_value_t *, char *,
275                           mrp_funcbridge_value_t *);
276 static bool compare_bridge(lua_State *, void *, const char *,
277                            mrp_funcbridge_value_t *, char *,
278                            mrp_funcbridge_value_t *);
279
280 static int  apclass_create(lua_State *);
281 static int  apclass_getfield(lua_State *);
282 static int  apclass_setfield(lua_State *);
283 static int  apclass_tostring(lua_State *);
284 static void apclass_destroy(void *);
285
286 static route_t *route_check(lua_State *, int);
287 static int route_push(lua_State *, route_t *);
288 static void route_destroy(route_t *);
289
290 static int  vollim_create(lua_State *);
291 static int  vollim_getfield(lua_State *);
292 static int  vollim_setfield(lua_State *);
293 static int  vollim_tostring(lua_State *);
294 static void vollim_destroy(void *);
295
296 static double vollim_calculate(struct userdata *, int, mir_node *, void *);
297 static bool calculate_bridge(lua_State *, void *, const char *,
298                              mrp_funcbridge_value_t *, char *,
299                              mrp_funcbridge_value_t *);
300
301 static limit_data_t *limit_data_check(lua_State *, int);
302
303 #if 0
304 static int limit_data_push(lua_State *, limit_data_t *);
305 #endif
306
307 static void limit_data_destroy(limit_data_t *);
308
309 static intarray_t *intarray_check(lua_State *, int, int, int);
310 static int intarray_push(lua_State *, intarray_t *);
311 static void intarray_destroy(intarray_t *);
312
313 static resource_name_t *resource_names_check(lua_State *, int);
314 static void resource_names_destroy(resource_name_t *);
315
316 static attribute_t *attributes_check(lua_State *, int);
317 static void attributes_destroy(attribute_t *);
318
319 static map_t *map_check(lua_State *, int);
320 static int map_push(lua_State *, map_t *);
321 static void map_destroy(map_t *);
322
323 static field_t field_check(lua_State *, int, const char **);
324 static field_t field_name_to_type(const char *, size_t);
325 static int make_id(char *buf, size_t len, const char *fmt, ...);
326
327 static void setup_murphy_interface(struct userdata *);
328 static char *comma_separated_list(mrp_lua_strarray_t *, char *, int);
329
330 static bool define_constants(lua_State *);
331 static bool register_methods(lua_State *);
332
333 static void *alloc(void *, void *, size_t, size_t);
334 static int panic(lua_State *);
335
336
337 MRP_LUA_METHOD_LIST_TABLE (
338     import_methods,           /* methodlist name */
339     MRP_LUA_METHOD_CONSTRUCTOR  (import_create)
340     MRP_LUA_METHOD        (link, import_link  )
341 );
342
343 MRP_LUA_METHOD_LIST_TABLE (
344     node_methods,             /* methodlist name */
345     MRP_LUA_METHOD_CONSTRUCTOR  (node_create)
346 );
347
348
349 MRP_LUA_METHOD_LIST_TABLE (
350     import_overrides,        /* methodlist_name */
351     MRP_LUA_OVERRIDE_CALL       (import_create)
352     MRP_LUA_OVERRIDE_GETFIELD   (import_getfield)
353     MRP_LUA_OVERRIDE_SETFIELD   (import_setfield)
354     MRP_LUA_OVERRIDE_STRINGIFY  (import_tostring)
355 );
356
357 MRP_LUA_METHOD_LIST_TABLE (
358     array_overrides,         /* methodlist_name */
359     MRP_LUA_OVERRIDE_GETFIELD   (array_getfield)
360     MRP_LUA_OVERRIDE_SETFIELD   (array_setfield)
361     MRP_LUA_OVERRIDE_GETLENGTH  (array_getlength)
362 );
363
364 MRP_LUA_METHOD_LIST_TABLE (
365     node_overrides,           /* methodlist name */
366     MRP_LUA_OVERRIDE_CALL       (node_create)
367     MRP_LUA_OVERRIDE_GETFIELD   (node_getfield)
368     MRP_LUA_OVERRIDE_SETFIELD   (node_setfield)
369     MRP_LUA_OVERRIDE_STRINGIFY  (node_tostring)
370 );
371
372
373 MRP_LUA_CLASS_DEF (
374    mdb,                         /* class name */
375    import,                      /* constructor name */
376    scripting_import,            /* userdata type */
377    import_destroy,              /* userdata destructor */
378    import_methods,              /* class methods */
379    import_overrides             /* override methods */
380 );
381
382 MRP_LUA_CLASS_DEF (
383    node,                        /* class name */
384    instance,                    /* constructor name */
385    scripting_node,              /* userdata type */
386    node_destroy,                /* userdata destructor */
387    node_methods,                /* class methods */
388    node_overrides               /* override methods */
389 );
390
391 MRP_LUA_CLASS_DEF_SIMPLE (
392    zone,                         /* class name */
393    scripting_zone,               /* userdata type */
394    zone_destroy,                 /* userdata destructor */
395    MRP_LUA_METHOD_LIST (         /* methods */
396       MRP_LUA_METHOD_CONSTRUCTOR  (zone_create)
397    ),
398    MRP_LUA_METHOD_LIST (         /* overrides */
399       MRP_LUA_OVERRIDE_CALL       (zone_create)
400       MRP_LUA_OVERRIDE_GETFIELD   (zone_getfield)
401       MRP_LUA_OVERRIDE_SETFIELD   (zone_setfield)
402    )
403 );
404
405 MRP_LUA_CLASS_DEF_SIMPLE (
406    audio_resource,               /* class name */
407    scripting_resource,           /* userdata type */
408    resource_destroy,             /* userdata destructor */
409    MRP_LUA_METHOD_LIST (         /* methods */
410       MRP_LUA_METHOD_CONSTRUCTOR  (resource_create)
411    ),
412    MRP_LUA_METHOD_LIST (         /* overrides */
413       MRP_LUA_OVERRIDE_CALL       (resource_create)
414       MRP_LUA_OVERRIDE_GETFIELD   (resource_getfield)
415       MRP_LUA_OVERRIDE_SETFIELD   (resource_setfield)
416    )
417 );
418
419 MRP_LUA_CLASS_DEF_SIMPLE (
420    routing_group,                /* class name */
421    scripting_rtgroup,            /* userdata type */
422    rtgroup_destroy,              /* userdata destructor */
423    MRP_LUA_METHOD_LIST (         /* methods */
424       MRP_LUA_METHOD_CONSTRUCTOR  (rtgroup_create)
425    ),
426    MRP_LUA_METHOD_LIST (         /* overrides */
427       MRP_LUA_OVERRIDE_CALL       (rtgroup_create)
428       MRP_LUA_OVERRIDE_GETFIELD   (rtgroup_getfield)
429       MRP_LUA_OVERRIDE_SETFIELD   (rtgroup_setfield)
430       MRP_LUA_OVERRIDE_STRINGIFY  (rtgroup_tostring)
431    )
432 );
433
434 MRP_LUA_CLASS_DEF_SIMPLE (
435    application_class,            /* class name */
436    scripting_apclass,            /* userdata type */
437    apclass_destroy,              /* userdata destructor */
438    MRP_LUA_METHOD_LIST (         /* methods */
439       MRP_LUA_METHOD_CONSTRUCTOR  (apclass_create)
440    ),
441    MRP_LUA_METHOD_LIST (        /* overrides */
442       MRP_LUA_OVERRIDE_CALL       (apclass_create)
443       MRP_LUA_OVERRIDE_GETFIELD   (apclass_getfield)
444       MRP_LUA_OVERRIDE_SETFIELD   (apclass_setfield)
445       MRP_LUA_OVERRIDE_STRINGIFY  (apclass_tostring)
446    )
447 );
448
449 MRP_LUA_CLASS_DEF_SIMPLE (
450    volume_limit,                 /* class name */
451    scripting_vollim,             /* userdata type */
452    vollim_destroy,               /* userdata destructor */
453    MRP_LUA_METHOD_LIST (         /* methods */
454       MRP_LUA_METHOD_CONSTRUCTOR  (vollim_create)
455    ),
456    MRP_LUA_METHOD_LIST (        /* overrides */
457       MRP_LUA_OVERRIDE_CALL       (vollim_create)
458       MRP_LUA_OVERRIDE_GETFIELD   (vollim_getfield)
459       MRP_LUA_OVERRIDE_SETFIELD   (vollim_setfield)
460       MRP_LUA_OVERRIDE_STRINGIFY  (vollim_tostring)
461    )
462 );
463
464
465 pa_scripting *pa_scripting_init(struct userdata *u)
466 {
467     pa_scripting *scripting;
468     lua_State *L;
469
470     pa_assert(u);
471
472     scripting = pa_xnew0(pa_scripting, 1);
473
474     if (!(L = lua_newstate(alloc, u)))
475         pa_log("failed to initialize Lua");
476     else {
477         lua_atpanic(L, &panic);
478         luaL_openlibs(L);
479
480         mrp_create_funcbridge_class(L);
481         mrp_lua_create_object_class(L, IMPORT_CLASS);
482         mrp_lua_create_object_class(L, NODE_CLASS);
483         mrp_lua_create_object_class(L, ZONE_CLASS);
484         mrp_lua_create_object_class(L, RESOURCE_CLASS);
485         mrp_lua_create_object_class(L, RTGROUP_CLASS);
486         mrp_lua_create_object_class(L, APPLICATION_CLASS);
487         mrp_lua_create_object_class(L, VOLLIM_CLASS);
488
489         array_class_create(L);
490
491         define_constants(L);
492         register_methods(L);
493
494         lua_pushlightuserdata(L, u);
495         lua_setglobal(L, USERDATA);
496
497         scripting->L = L;
498         scripting->configured = FALSE;
499     }
500
501     return scripting;
502 }
503
504 void pa_scripting_done(struct userdata *u)
505 {
506     pa_scripting *scripting;
507
508     if (u && (scripting = u->scripting)) {
509         pa_xfree(scripting);
510         u->scripting = NULL;
511     }
512 }
513
514 pa_bool_t pa_scripting_dofile(struct userdata *u, const char *file)
515 {
516     pa_scripting *scripting;
517     lua_State *L;
518     pa_bool_t success;
519
520     pa_assert(u);
521     pa_assert(file);
522
523     pa_assert_se((scripting = u->scripting));
524     pa_assert_se((L = scripting->L));
525
526     if (luaL_loadfile(L, file) || lua_pcall(L, 0, 0, 0)) {
527         success = FALSE;
528         pa_log("%s", lua_tostring(L, -1));
529         lua_pop(L, 1);
530     }
531     else {
532         success =TRUE;
533         scripting->configured = TRUE;
534         setup_murphy_interface(u);
535         pa_zoneset_update_module_property(u);
536     }
537
538     return success;
539 }
540
541 static int import_create(lua_State *L)
542 {
543     struct userdata *u;
544     pa_scripting *scripting;
545     size_t fldnamlen;
546     const char *fldnam;
547     scripting_import *imp;
548     const char *table = NULL;
549     mrp_lua_strarray_t *columns = NULL;
550     const char *condition = NULL;
551     int maxrow = 0;
552     mrp_funcbridge_t *update = NULL;
553     size_t maxcol;
554     pa_value **rows;
555     pa_value **cols;
556     int i,j;
557     int top;
558
559     MRP_LUA_ENTER;
560
561     top = lua_gettop(L);
562
563     lua_getglobal(L, USERDATA);
564     if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
565         luaL_error(L, "missing or invalid global '" USERDATA "'");
566
567     pa_assert_se((scripting = u->scripting));
568
569     MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
570
571         switch (field_name_to_type(fldnam, fldnamlen)) {
572         case TABLE:      table = luaL_checkstring(L, -1);                break;
573         case COLUMNS:    columns = mrp_lua_check_strarray(L, -1);        break;
574         case CONDITION:  condition = luaL_checkstring(L, -1);            break;
575         case MAXROW:     maxrow = luaL_checkint(L, -1);                  break;
576         case UPDATE:     update = mrp_funcbridge_create_luafunc(L, -1);  break;
577         default:         luaL_error(L, "bad field '%s'", fldnam);        break;
578         }
579
580     } /* MRP_LUA_FOREACH_FIELD */
581
582     lua_settop(L, top);
583
584     if (!table)
585         luaL_error(L, "missing table field");
586     if (!columns)
587         luaL_error(L, "missing columns field");
588     if (maxrow < 1 || maxrow >= MQI_QUERY_RESULT_MAX)
589         luaL_error(L, "missing or invalid maxrow field");
590     if (!update)
591         luaL_error(L, "missing update function");
592
593     maxcol = columns->nstring;
594
595     if (maxcol >= MQI_COLUMN_MAX)
596         luaL_error(L, "too many columns (max %d allowed)", MQI_COLUMN_MAX);
597
598     if (scripting->configured)
599         luaL_error(L, "refuse to import '%s' after configuration phase",table);
600
601     imp = (scripting_import *)mrp_lua_create_object(L, IMPORT_CLASS, table,0);
602
603     imp->userdata = u;
604     imp->table = pa_xstrdup(table);
605     imp->columns = columns;
606     imp->condition = condition;
607     imp->values = array_create(L, maxrow, NULL);
608     imp->update = update;
609
610     for (i = 0, rows = imp->values->array;  i < maxrow;   i++) {
611         cols = (rows[i] = array_create(L, maxcol, columns))->array;
612         lua_rawseti(L, -3, i+1); /* we add this to the import */
613         for (j = 0;  j < maxcol;  j++)
614             cols[j] = pa_xnew0(pa_value, 1);
615     }
616
617     lua_rawseti(L, -2, MQI_QUERY_RESULT_MAX);
618
619     MRP_LUA_LEAVE(1);
620 }
621
622 static int import_getfield(lua_State *L)
623 {
624     scripting_import *imp;
625     pa_value *values;
626     int colidx;
627     field_t fld;
628
629     MRP_LUA_ENTER;
630
631     if (!(imp = (scripting_import *)mrp_lua_check_object(L, IMPORT_CLASS, 1)))
632         lua_pushnil(L);
633     else {
634         pa_assert_se((values = imp->values));
635
636         if (lua_type(L, 2) == LUA_TNUMBER) {
637             colidx = lua_tointeger(L, 2);
638
639             if (colidx < 1 || colidx > -values->type)
640                 lua_pushnil(L);
641             else
642                 lua_rawgeti(L, 1, colidx);
643         }
644         else {
645             fld = field_check(L, 2, NULL);
646             lua_pop(L, 1);
647
648             switch (fld) {
649             case TABLE:       lua_pushstring(L, imp->table);             break;
650             case COLUMNS:     mrp_lua_push_strarray(L, imp->columns);    break;
651             case CONDITION:   lua_pushstring(L, imp->condition);         break;
652             case MAXROW:      lua_pushinteger(L, -imp->values->type);    break;
653             default:          lua_pushnil(L);                            break;
654             }
655         }
656     }
657
658     MRP_LUA_LEAVE(1);
659 }
660
661 static int import_setfield(lua_State *L)
662 {
663     const char *f;
664
665     MRP_LUA_ENTER;
666
667     f = luaL_checkstring(L, 2);
668     luaL_error(L, "attempt to set '%s' field of read-only mdb.import", f);
669     
670     MRP_LUA_LEAVE(0);
671 }
672
673 static int import_tostring(lua_State *L)
674 {
675     scripting_import *imp;
676
677     MRP_LUA_ENTER;
678
679     imp = (scripting_import *)mrp_lua_check_object(L, IMPORT_CLASS, 1);
680
681     lua_pushstring(L, imp->table);
682
683     MRP_LUA_LEAVE(1);
684 }
685
686 static void import_destroy(void *data)
687 {
688     scripting_import *imp = (scripting_import *)data;
689
690     MRP_LUA_ENTER;
691
692     pa_xfree((void *)imp->table);
693     mrp_lua_free_strarray(imp->columns);
694     pa_xfree((void *)imp->condition);
695
696     MRP_LUA_LEAVE_NOARG;
697 }
698
699 static int import_link(lua_State *L)
700 {
701     scripting_import *imp;
702     mrp_lua_strarray_t *columns;
703     pa_value *values;
704     const char *colnam;
705     int rowidx;
706     size_t colidx;
707     pa_value *row;
708     pa_value *col;
709
710     MRP_LUA_ENTER;
711
712     imp = (scripting_import *)mrp_lua_check_object(L, IMPORT_CLASS, 1);
713     rowidx = luaL_checkint(L, 2) - 1;
714     colnam = luaL_checkstring(L, 3);
715
716     pa_assert(imp);
717     pa_assert_se((columns = imp->columns));
718
719     col = NULL;
720
721     if (rowidx >= 0 && rowidx < -imp->values->type) {
722         for (colidx = 0;   colidx < columns->nstring;   colidx++) {
723             if (!strcmp(colnam, columns->strings[colidx])) {
724                 pa_assert_se((values = imp->values));
725                 pa_assert_se((row = values->array[rowidx]));
726                 pa_assert(colidx < (size_t)-row->type);
727                 pa_assert_se((col = row->array[colidx]));
728                 break;
729             }
730         }
731     }
732
733     pa_log_debug("userdata: type:%d", col->type);
734
735     lua_pushlightuserdata(L, col);
736
737     MRP_LUA_LEAVE(1);
738 }
739
740 static void import_data_changed(struct userdata *u,
741                                 const char *table,
742                                 int nrow,
743                                 mrp_domctl_value_t **mval)
744 {
745     static mrp_domctl_value_t empty;
746
747     pa_scripting *scripting;
748     lua_State *L;
749     scripting_import *imp;
750     mrp_domctl_value_t *mrow;
751     mrp_domctl_value_t *mcol;
752     pa_value *ptval, *prval, *pcval;
753     pa_value **prow;
754     pa_value **pcol;
755     int maxcol;
756     int maxrow;
757     mrp_funcbridge_value_t arg;
758     mrp_funcbridge_value_t ret;
759     char t;
760     int i,j;
761
762     pa_assert(u);
763     pa_assert(table);
764     pa_assert(mval || nrow == 0);
765     pa_assert_se((scripting = u->scripting));
766     pa_assert_se((L = scripting->L));
767
768     pa_log_debug("table '%s' data changed: got %d rows", table, nrow);
769
770     mrp_lua_get_class_table(L, IMPORT_CLASS);
771
772     if (!lua_istable(L, -1)){
773         luaL_error(L, "internal error: failed to find '%s' table",
774                    (IMPORT_CLASS)->constructor);
775     }
776
777     lua_pushstring(L, table);
778     lua_rawget(L, -2);
779
780     if (!(imp = mrp_lua_to_object(L, IMPORT_CLASS, -1)))
781         pa_log("can't find import '%s'", table);
782     else {
783         pa_assert(!strcmp(table, imp->table));
784         pa_assert(imp->columns);
785         pa_assert(imp->update);
786         pa_assert_se((ptval = imp->values));
787         pa_assert_se((prow = ptval->array));
788         
789         maxrow = -ptval->type;
790         maxcol = imp->columns->nstring;
791
792         pa_assert(maxrow >= 0);
793         pa_assert(nrow <= maxrow);
794
795         pa_log_debug("import '%s' found", imp->table);
796
797         for (i = 0; i < maxrow;  i++) {
798             pa_assert_se((prval = prow[i]));
799             pa_assert_se((pcol = prval->array));
800             pa_assert(prval->type < 0);
801             pa_assert(maxcol == -prval->type);
802
803             mrow = (i < nrow) ? mval[i] : NULL;
804
805             for (j = 0;  j < maxcol;  j++) {
806                 pcval = pcol[j];
807                 mcol = mrow ? mrow + j : &empty;
808
809                 switch (mcol->type) {
810                 case MRP_DOMCTL_STRING:
811                     pa_assert(!pcval->type || pcval->type == pa_value_string);
812                     pa_xfree((void *)pcval->string);
813                     pcval->type = pa_value_string;
814                     pcval->string = pa_xstrdup(mcol->str);
815                     break;
816                 case MRP_DOMCTL_INTEGER:
817                     pa_assert(!pcval->type || pcval->type == pa_value_integer);
818                     pcval->type = pa_value_integer;
819                     pcval->integer = mcol->s32;
820                     break;
821                 case MRP_DOMCTL_UNSIGNED:
822                     pa_assert(!pcval->type || pcval->type == pa_value_unsignd);
823                     pcval->type = pa_value_unsignd;
824                     pcval->unsignd = mcol->u32;
825                     break;
826                 case MRP_DOMCTL_DOUBLE:
827                     pa_assert(!pcval->type || pcval->type ==pa_value_floating);
828                     pcval->type = pa_value_floating;
829                     pcval->floating = mcol->dbl;
830                     break;
831                 default:
832                     if (pcval->type == pa_value_string)
833                         pa_xfree((void *)pcval->string);
834                     memset(pcval, 0, sizeof(pa_value));
835                     break;
836                 }
837             }
838         }
839
840         arg.pointer = imp;
841
842         if (!mrp_funcbridge_call_from_c(L, imp->update, "o", &arg, &t, &ret)) {
843             pa_log("failed to call %s:update method (%s)",
844                    imp->table, ret.string);
845             pa_xfree((void *)ret.string);
846         }
847     }
848
849     lua_pop(L, 2);
850 }
851
852
853 static bool update_bridge(lua_State *L, void *data, const char *signature,
854                           mrp_funcbridge_value_t *args,
855                           char *ret_type, mrp_funcbridge_value_t *ret_val)
856 {
857     update_func_t update;
858     scripting_import *imp;
859     struct userdata *u;
860     bool success;
861
862     (void)L;
863
864     pa_assert(signature);
865     pa_assert(args);
866     pa_assert(ret_type);
867     pa_assert(ret_val);
868
869     pa_assert_se((update = (update_func_t)data));
870
871     if (strcmp(signature, "o"))
872         success = false;
873     else {
874         pa_assert_se((imp = args[0].pointer));
875         pa_assert_se((u = imp->userdata));
876
877         success = true;
878         *ret_type = MRP_FUNCBRIDGE_NO_DATA;
879         memset(ret_val, 0, sizeof(mrp_funcbridge_value_t));
880         update(u);
881     }
882
883     return success;
884 }
885
886
887
888 static void array_class_create(lua_State *L)
889 {
890     /* create a metatable for row's */
891     luaL_newmetatable(L, ARRAY_CLASSID);
892     lua_pushliteral(L, "__index");
893     lua_pushvalue(L, -2);
894     lua_settable(L, -3);        /* metatable.__index = metatable */
895     luaL_openlib(L, NULL, array_overrides, 0);
896 }
897
898
899 static pa_value *array_create(lua_State *L, int dimension,
900                               mrp_lua_strarray_t *names)
901 {
902     pa_value  *value;
903     pa_value **array;
904
905     pa_assert(L);
906     pa_assert(dimension >= 0);
907     pa_assert(dimension < MQI_QUERY_RESULT_MAX);
908
909     array = pa_xnew0(pa_value *, dimension + 1);
910     value = lua_newuserdata(L, sizeof(pa_value));
911     value->type = -dimension;
912     value->array = array;
913
914     array[dimension] = (pa_value *)names;
915
916     luaL_getmetatable(L, ARRAY_CLASSID);
917     lua_setmetatable(L, -2);
918
919     return value;
920 }
921
922 static int array_getfield(lua_State *L)
923 {
924     pa_value *arr, *value;
925     int dimension;
926     int key_type;
927     const char *key;
928     mrp_lua_strarray_t *names;
929     int idx;
930     size_t i;
931
932     MRP_LUA_ENTER;
933
934     pa_assert(L);
935
936     arr = (pa_value *)luaL_checkudata(L, 1, ARRAY_CLASSID);
937
938     pa_assert(arr->type < 0);
939     
940     dimension = -arr->type;
941     key_type = lua_type(L, 2);
942     
943     switch (key_type) {
944     case LUA_TNUMBER:
945         idx = lua_tointeger(L, 2) - 1;
946         break;
947     case LUA_TSTRING:
948         idx = -1;
949         if ((names = (mrp_lua_strarray_t *)arr->array[dimension])) {
950             pa_assert(dimension == names->nstring);
951             key = lua_tostring(L, 2);
952             pa_assert(key);
953             for (i = 0;  i < dimension;  i++) {
954                 if (!strcmp(key, names->strings[i])) {
955                     idx = i;
956                     break;
957                 }
958             }
959         }
960         break;
961     default:
962         idx = -1;
963         break;
964     }
965
966
967     if (idx < 0 || idx >= dimension || !(value = arr->array[idx]))
968         lua_pushnil(L);
969     else if (value->type < 0)
970         lua_rawgeti(L, 1, 1 - value->type);
971     else {
972         switch (value->type) {
973         case pa_value_string:   lua_pushstring(L, value->string);   break;
974         case pa_value_integer:  lua_pushinteger(L, value->integer); break;
975         case pa_value_unsignd:  lua_pushinteger(L, value->unsignd); break;
976         case pa_value_floating: lua_pushnumber(L, value->floating); break;
977         default:                lua_pushnil(L);                     break;
978         }
979     }
980
981     MRP_LUA_LEAVE(1);
982 }
983
984 static int array_setfield(lua_State *L)
985 {
986     MRP_LUA_ENTER;
987
988     pa_assert(L);
989
990     luaL_error(L, "attempt to write to a read-only object");
991
992     MRP_LUA_LEAVE(0);
993 }
994
995 static int array_getlength(lua_State *L)
996 {
997     MRP_LUA_ENTER;
998
999     pa_assert(L);
1000
1001     MRP_LUA_LEAVE(1);
1002 }
1003
1004 #if 0
1005 static void array_destroy(void *data)
1006 {
1007     pa_value *value = (pa_value *)data; 
1008
1009     MRP_LUA_ENTER;
1010
1011     if (value) {
1012         pa_assert(value->type < 0);
1013         pa_xfree(value->array);
1014     }
1015
1016     MRP_LUA_LEAVE_NOARG;
1017 }
1018 #endif
1019
1020 scripting_node *pa_scripting_node_create(struct userdata *u, mir_node *node)
1021 {
1022     pa_scripting *scripting;
1023     lua_State *L;
1024     scripting_node *sn;
1025     char id[256];
1026
1027     pa_assert(u);
1028     pa_assert(node);
1029     pa_assert(node->amname);
1030
1031     pa_assert_se((scripting = u->scripting));
1032     pa_assert_se((L = scripting->L));
1033
1034     make_id(id, sizeof(id), "%s_%d", node->amname, node->index);
1035
1036     if ((sn = (scripting_node *)mrp_lua_create_object(L, NODE_CLASS, id,0))) {
1037         sn->userdata = u;
1038         sn->id = pa_xstrdup(id);
1039         sn->node = node;
1040     }
1041
1042     return sn;
1043 }
1044
1045 void pa_scripting_node_destroy(struct userdata *u, mir_node *node)
1046 {
1047     pa_scripting *scripting;
1048     lua_State *L;
1049     scripting_node *sn;
1050
1051     MRP_LUA_ENTER;
1052
1053     pa_assert(u);
1054     pa_assert(node);
1055     
1056     pa_assert_se((scripting = u->scripting));
1057     pa_assert_se((L = scripting->L));
1058
1059     if ((sn = node->scripting)) {
1060         mrp_lua_destroy_object(L, sn->id,0, sn);
1061         sn->node = NULL;
1062         node->scripting = NULL;
1063     }
1064
1065     MRP_LUA_LEAVE_NOARG;
1066 }
1067
1068 static int node_create(lua_State *L)
1069 {
1070     MRP_LUA_ENTER;
1071
1072     lua_pushnil(L);
1073
1074     MRP_LUA_LEAVE(1);
1075 }
1076
1077 static int node_getfield(lua_State *L)
1078 {
1079     scripting_node *sn;
1080     mir_node *node;
1081     field_t fld;
1082
1083     MRP_LUA_ENTER;
1084
1085     fld = field_check(L, 2, NULL);
1086     lua_pop(L, 1);
1087
1088     if (!(sn = (scripting_node *)mrp_lua_check_object(L, NODE_CLASS, 1)))
1089         lua_pushnil(L);
1090     else {
1091         pa_assert_se((node = sn->node));
1092
1093         switch (fld) {
1094         case NAME:           lua_pushstring(L, node->amname);         break;
1095         case DESCRIPTION:    lua_pushstring(L, node->amdescr);        break;
1096         case DIRECTION:      lua_pushinteger(L, node->direction);     break;
1097         case IMPLEMENT:      lua_pushinteger(L, node->implement);     break;
1098         case CHANNELS:       lua_pushinteger(L, node->channels);      break;
1099         case LOCATION:       lua_pushinteger(L, node->location);      break;
1100         case PRIVACY:        lua_pushinteger(L, node->privacy);       break;
1101         case ZONE:           lua_pushstring(L, node->zone);           break;
1102         case TYPE:           lua_pushinteger(L, node->type);          break;
1103         case AVAILABLE:      lua_pushboolean(L, node->available);     break;
1104         default:             lua_pushnil(L);                          break;
1105         }
1106     }
1107
1108     MRP_LUA_LEAVE(1);
1109 }
1110
1111 static int node_setfield(lua_State *L)
1112 {
1113     const char *f;
1114
1115     MRP_LUA_ENTER;
1116     
1117     f = luaL_checkstring(L, 2);
1118     luaL_error(L, "attempt to set '%s' field of read-only node", f);
1119
1120     MRP_LUA_LEAVE(0);
1121 }
1122
1123 static int node_tostring(lua_State *L)
1124 {
1125     scripting_node *sn;
1126
1127     MRP_LUA_ENTER;
1128
1129     sn = (scripting_node *)mrp_lua_check_object(L, NODE_CLASS, 1);
1130
1131     lua_pushstring(L, (sn && sn->id) ? sn->id : "<unknown node>");
1132
1133     MRP_LUA_LEAVE(1);
1134 }
1135
1136 static void node_destroy(void *data)
1137 {
1138     scripting_node *sn = (scripting_node *)data;
1139     mir_node *node;
1140
1141     MRP_LUA_ENTER;
1142
1143     if ((node = sn->node) && sn == node->scripting)
1144         node->scripting = NULL;
1145
1146     pa_xfree((void *)sn->id);
1147
1148     MRP_LUA_LEAVE_NOARG;
1149 }
1150
1151
1152 static int zone_create(lua_State *L)
1153 {
1154     static uint32_t index;
1155
1156     struct userdata *u;
1157     size_t fldnamlen;
1158     const char *fldnam;
1159     scripting_zone *zone;
1160     const char *name = NULL;
1161     attribute_t *attributes = NULL;
1162
1163     MRP_LUA_ENTER;
1164
1165     lua_getglobal(L, USERDATA);
1166     if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
1167         luaL_error(L, "missing or invalid global '" USERDATA "'");
1168     lua_pop(L, 1);
1169
1170
1171     MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
1172
1173         switch (field_name_to_type(fldnam, fldnamlen)) {
1174         case NAME:         name = luaL_checkstring(L, -1);           break;
1175         case ATTRIBUTES:   attributes = attributes_check(L, -1);     break;
1176         default:           luaL_error(L, "bad field '%s'", fldnam);  break;
1177         }
1178
1179     } /* MRP_LUA_FOREACH_FIELD */
1180
1181     if (!name)
1182         luaL_error(L, "missing or invalid name field");
1183
1184     if (pa_zoneset_add_zone(u, name, index+1))
1185         luaL_error(L, "attempt to define zone '%s' multiple times", name);
1186
1187     zone = (scripting_zone *)mrp_lua_create_object(L, ZONE_CLASS,
1188                                                    "definition",0);
1189
1190     zone->userdata = u;
1191     zone->name = pa_xstrdup(name);
1192     zone->index = ++index;
1193
1194
1195     MRP_LUA_LEAVE(1);
1196 }
1197
1198 static int zone_getfield(lua_State *L)
1199 {
1200     scripting_zone *zone;
1201     field_t fld;
1202
1203     MRP_LUA_ENTER;
1204
1205     fld = field_check(L, 2, NULL);
1206     lua_pop(L, 1);
1207
1208     if (!(zone = (scripting_zone *)mrp_lua_check_object(L, ZONE_CLASS, 1)))
1209         lua_pushnil(L);
1210     else {
1211         switch (fld) {
1212         case NAME:           lua_pushstring(L, zone->name);         break;
1213 #if 0
1214         case ATTRIBUTES:     lua_pushinteger(L, rtgs->type);       break;
1215 #endif
1216         default:             lua_pushnil(L);                       break;
1217         }
1218     }
1219
1220     MRP_LUA_LEAVE(1);
1221 }
1222
1223 static int zone_setfield(lua_State *L)
1224 {
1225     const char *f;
1226
1227     MRP_LUA_ENTER;
1228
1229     f = luaL_checkstring(L, 2);
1230     luaL_error(L, "attempt to set '%s' field of read-only zone", f);
1231     
1232     MRP_LUA_LEAVE(0);
1233 }
1234
1235 static void zone_destroy(void *data)
1236 {
1237     scripting_zone *zone = (scripting_zone *)data;
1238
1239     MRP_LUA_ENTER;
1240
1241     pa_xfree((void *)zone->name);
1242     
1243     zone->name = NULL;
1244
1245     MRP_LUA_LEAVE_NOARG;
1246 }
1247
1248
1249 static int resource_create(lua_State *L)
1250 {
1251     struct userdata *u;
1252     size_t fldnamlen;
1253     const char *fldnam;
1254     mir_rtgroup *rtg;
1255     scripting_resource *res;
1256     resource_name_t *name = NULL;
1257     attribute_t *attributes = NULL;
1258     attribute_t *attr;
1259
1260     MRP_LUA_ENTER;
1261
1262     lua_getglobal(L, USERDATA);
1263     if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
1264         luaL_error(L, "missing or invalid global '" USERDATA "'");
1265     lua_pop(L, 1);
1266
1267
1268     MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
1269
1270         switch (field_name_to_type(fldnam, fldnamlen)) {
1271         case NAME:         name = resource_names_check(L, -1);       break;
1272         case ATTRIBUTES:   attributes = attributes_check(L, -1);     break;
1273         default:           luaL_error(L, "bad field '%s'", fldnam);  break;
1274         }
1275
1276     } /* MRP_LUA_FOREACH_FIELD */
1277
1278     if (!name)
1279         luaL_error(L, "missing or invalid name field");
1280
1281     pa_murphyif_add_audio_resource(u, mir_input,  name->playback);
1282     pa_murphyif_add_audio_resource(u, mir_output, name->recording);
1283
1284     if (attributes) {
1285         for (attr = attributes;   attr->prop && attr->def.name;   attr++) {
1286             switch (attr->def.type) {
1287             case mqi_string:
1288                 pa_murphyif_add_audio_attribute(u, attr->prop,
1289                                                 attr->def.name,
1290                                                 attr->def.type,
1291                                                 attr->def.value.string);
1292                 break;
1293             case mqi_integer:
1294                 pa_murphyif_add_audio_attribute(u, attr->prop,
1295                                                 attr->def.name,
1296                                                 attr->def.type,
1297                                                 attr->def.value.integer);
1298                 break;
1299             case mqi_unsignd:
1300                 pa_murphyif_add_audio_attribute(u, attr->prop,
1301                                                 attr->def.name,
1302                                                 attr->def.type,
1303                                                 attr->def.value.unsignd);
1304                 break;
1305             case mqi_floating:
1306                 pa_murphyif_add_audio_attribute(u, attr->prop,
1307                                                 attr->def.name,
1308                                                 attr->def.type,
1309                                                 attr->def.value.floating);
1310                 break;
1311             default:
1312                 luaL_error(L, "invalid audio resource attribute '%s'",
1313                            attr->def.name);
1314                 break;
1315             }
1316         }
1317     }
1318
1319     res = (scripting_resource *)mrp_lua_create_object(L, RTGROUP_CLASS,
1320                                                       "definition",0);
1321
1322     res->userdata = u;
1323     res->name = name;
1324     res->attributes = attributes;
1325
1326     MRP_LUA_LEAVE(1);
1327 }
1328
1329 static int resource_getfield(lua_State *L)
1330 {
1331     scripting_resource *res;
1332     field_t fld;
1333
1334     MRP_LUA_ENTER;
1335
1336     fld = field_check(L, 2, NULL);
1337     lua_pop(L, 1);
1338
1339     if (!(res = (scripting_resource*)mrp_lua_check_object(L,RESOURCE_CLASS,1)))
1340         lua_pushnil(L);
1341     else {
1342 #if 0
1343         switch (fld) {
1344         case NAME:           lua_pushstring(L, rtg->name);         break;
1345         case ATTRIBUTES:     lua_pushinteger(L, rtgs->type);       break;
1346         default:             lua_pushnil(L);                       break;
1347         }
1348 #else
1349         lua_pushnil(L);
1350 #endif
1351     }
1352
1353     MRP_LUA_LEAVE(1);
1354 }
1355
1356 static int resource_setfield(lua_State *L)
1357 {
1358     const char *f;
1359
1360     MRP_LUA_ENTER;
1361
1362     f = luaL_checkstring(L, 2);
1363     luaL_error(L, "attempt to set '%s' field of read-only resource_class", f);
1364     
1365     MRP_LUA_LEAVE(0);
1366 }
1367
1368 static void resource_destroy(void *data)
1369 {
1370     scripting_resource *res = (scripting_resource *)data;
1371
1372     MRP_LUA_ENTER;
1373
1374     resource_names_destroy(res->name);
1375     attributes_destroy(res->attributes);
1376     
1377     res->name = NULL;
1378     res->attributes = NULL;
1379
1380     MRP_LUA_LEAVE_NOARG;
1381 }
1382
1383
1384 static int rtgroup_create(lua_State *L)
1385 {
1386     struct userdata *u;
1387     size_t fldnamlen;
1388     const char *fldnam;
1389     mir_rtgroup *rtg;
1390     scripting_rtgroup *rtgs;
1391     const char *name = NULL;
1392     mir_direction type = 0;
1393     mrp_funcbridge_t *accept = NULL;
1394     mrp_funcbridge_t *compare = NULL;
1395     char id[256];
1396
1397     MRP_LUA_ENTER;
1398
1399     lua_getglobal(L, USERDATA);
1400     if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
1401         luaL_error(L, "missing or invalid global '" USERDATA "'");
1402     lua_pop(L, 1);
1403
1404
1405     MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
1406
1407         switch (field_name_to_type(fldnam, fldnamlen)) {
1408         case NAME:      name    = luaL_checkstring(L, -1);               break;
1409         case NODE_TYPE: type    = luaL_checkint(L, -1);                  break;
1410         case ACCEPT:    accept  = mrp_funcbridge_create_luafunc(L, -1);  break;
1411         case COMPARE:   compare = mrp_funcbridge_create_luafunc(L, -1);  break;
1412         default:        luaL_error(L, "bad field '%s'", fldnam);         break;
1413         }
1414
1415     } /* MRP_LUA_FOREACH_FIELD */
1416
1417     if (!name)
1418         luaL_error(L, "missing name field");
1419     if (type != mir_input && type != mir_output)
1420         luaL_error(L, "missing or invalid node_type");
1421     if (!accept)
1422         luaL_error(L, "missing or invalid accept field");
1423     if (!compare)
1424         luaL_error(L, "missing or invalid compare field");
1425
1426     make_id(id,sizeof(id), "%s_%sput", name, (type == mir_input) ? "in":"out");
1427
1428     rtgs = (scripting_rtgroup *)mrp_lua_create_object(L, RTGROUP_CLASS, id,0);
1429
1430     rtg  = mir_router_create_rtgroup(u, type, pa_xstrdup(name),
1431                                      rtgroup_accept, rtgroup_compare);
1432     if (!rtgs || !rtg)
1433         luaL_error(L, "failed to create routing group '%s'", id);
1434
1435     rtg->scripting = rtgs;
1436
1437     rtgs->userdata = u;
1438     rtgs->rtg = rtg;
1439     rtgs->type = type;
1440     rtgs->accept = accept;
1441     rtgs->compare = compare;
1442
1443     MRP_LUA_LEAVE(1);
1444 }
1445
1446 static int rtgroup_getfield(lua_State *L)
1447 {
1448     scripting_rtgroup *rtgs;
1449     mir_rtgroup *rtg;
1450     field_t fld;
1451
1452     MRP_LUA_ENTER;
1453
1454     fld = field_check(L, 2, NULL);
1455     lua_pop(L, 1);
1456
1457     if (!(rtgs = (scripting_rtgroup *)mrp_lua_check_object(L,RTGROUP_CLASS,1)))
1458         lua_pushnil(L);
1459     else {
1460         pa_assert_se((rtg = rtgs->rtg));
1461
1462         switch (fld) {
1463         case NAME:           lua_pushstring(L, rtg->name);         break;
1464         case NODE_TYPE:      lua_pushinteger(L, rtgs->type);       break;
1465         default:             lua_pushnil(L);                       break;
1466         }
1467     }
1468
1469     MRP_LUA_LEAVE(1);
1470 }
1471
1472 static int rtgroup_setfield(lua_State *L)
1473 {
1474     const char *f;
1475
1476     MRP_LUA_ENTER;
1477
1478     f = luaL_checkstring(L, 2);
1479     luaL_error(L, "attempt to set '%s' field of read-only routing_group", f);
1480     
1481     MRP_LUA_LEAVE(0);
1482 }
1483
1484 static int rtgroup_tostring(lua_State *L)
1485 {
1486     scripting_rtgroup *rtgs;
1487     mir_rtgroup *rtg;
1488
1489     MRP_LUA_ENTER;
1490
1491     rtgs = (scripting_rtgroup *)mrp_lua_check_object(L, RTGROUP_CLASS, 1);
1492     pa_assert_se((rtg = rtgs->rtg));
1493
1494     lua_pushstring(L, rtg->name);
1495
1496     MRP_LUA_LEAVE(1);
1497 }
1498
1499 static void rtgroup_destroy(void *data)
1500 {
1501     scripting_rtgroup *rtgs = (scripting_rtgroup *)data;
1502     mir_rtgroup *rtg;
1503
1504     MRP_LUA_ENTER;
1505
1506     pa_assert_se((rtg = rtgs->rtg));
1507     pa_assert(rtgs == rtg->scripting);
1508
1509     rtg->scripting = NULL;
1510
1511     MRP_LUA_LEAVE_NOARG;
1512 }
1513
1514
1515 static pa_bool_t rtgroup_accept(struct userdata *u,
1516                                 mir_rtgroup *rtg,
1517                                 mir_node *node)
1518 {
1519     pa_scripting *scripting;
1520     lua_State *L;
1521     scripting_rtgroup *rtgs;
1522     mrp_funcbridge_value_t  args[2];
1523     char rt;
1524     mrp_funcbridge_value_t  rv;
1525     pa_bool_t accept;
1526
1527     pa_assert(u);
1528     pa_assert_se((scripting = u->scripting));
1529     pa_assert_se((L = scripting->L));
1530     pa_assert(rtg);
1531     pa_assert_se((rtgs = rtg->scripting));
1532     pa_assert(u == rtgs->userdata);
1533     pa_assert(rtgs->accept);
1534     pa_assert(node);
1535
1536     accept = false;
1537
1538     if ((rtgs = rtg->scripting) && node->scripting) {
1539
1540         args[0].pointer = rtgs;
1541         args[1].pointer = node->scripting;
1542
1543         if (!mrp_funcbridge_call_from_c(L, rtgs->accept, "oo",args, &rt,&rv)) {
1544             if (rt != MRP_FUNCBRIDGE_STRING)
1545                 pa_log("call to accept function failed");
1546             else {
1547                 pa_log("call to accept function failed: %s", rv.string);
1548                 mrp_free((void *)rv.string);
1549             }
1550         }
1551         else {
1552             if (rt != MRP_FUNCBRIDGE_BOOLEAN)
1553                 pa_log("accept function returned invalid type");
1554             else
1555                 accept = rv.boolean;
1556         }
1557     }
1558
1559     return accept;
1560 }
1561
1562 static int rtgroup_compare(struct userdata *u,
1563                            mir_rtgroup *rtg,
1564                            mir_node *node1,
1565                            mir_node *node2)
1566 {
1567     pa_scripting *scripting;
1568     lua_State *L;
1569     scripting_rtgroup *rtgs;
1570     mrp_funcbridge_value_t  args[3];
1571     char rt;
1572     mrp_funcbridge_value_t  rv;
1573     int result;
1574
1575     pa_assert(u);
1576     pa_assert_se((scripting = u->scripting));
1577     pa_assert_se((L = scripting->L));
1578     pa_assert(rtg);
1579     pa_assert_se((rtgs = rtg->scripting));
1580     pa_assert(u == rtgs->userdata);
1581     pa_assert(rtgs->compare);
1582     pa_assert(node1);
1583     pa_assert(node2);
1584
1585     result = -1;
1586
1587     if ((rtgs = rtg->scripting) && node1->scripting && node2->scripting) {
1588
1589         args[0].pointer = rtgs;
1590         args[1].pointer = node1->scripting;
1591         args[2].pointer = node2->scripting;
1592
1593         if (!mrp_funcbridge_call_from_c(L, rtgs->compare, "ooo",args, &rt,&rv))
1594             pa_log("failed to call compare function");
1595         else {
1596             if (rt != MRP_FUNCBRIDGE_FLOATING)
1597                 pa_log("compare function returned invalid type");
1598             else
1599                 result = rv.floating;
1600         }
1601     }
1602
1603     return result;
1604 }
1605
1606
1607 static bool accept_bridge(lua_State *L, void *data,
1608                           const char *signature, mrp_funcbridge_value_t *args,
1609                           char *ret_type, mrp_funcbridge_value_t *ret_val)
1610 {
1611     mir_rtgroup_accept_t accept;
1612     scripting_rtgroup *rtgs;
1613     scripting_node *ns;
1614     struct userdata *u;
1615     mir_rtgroup *rtg;
1616     mir_node *node;
1617     bool success;
1618
1619     (void)L;
1620
1621     pa_assert(signature);
1622     pa_assert(args);
1623     pa_assert(ret_type);
1624     pa_assert(ret_val);
1625
1626     pa_assert_se((accept = (mir_rtgroup_accept_t)data));
1627
1628     if (strcmp(signature, "oo"))
1629         success = false;
1630     else {
1631         pa_assert_se((rtgs = args[0].pointer));
1632         pa_assert_se((u = rtgs->userdata));
1633         pa_assert_se((ns = args[1].pointer));
1634
1635         if (!(rtg = rtgs->rtg) || !(node = ns->node))
1636             success = false;
1637         else {
1638             success = true;
1639             *ret_type = MRP_FUNCBRIDGE_BOOLEAN;
1640             ret_val->boolean = accept(u, rtg, node);
1641         }
1642     }
1643
1644     return success;
1645 }
1646
1647
1648 static bool compare_bridge(lua_State *L, void *data,
1649                            const char *signature, mrp_funcbridge_value_t *args,
1650                            char *ret_type, mrp_funcbridge_value_t *ret_val)
1651 {
1652     mir_rtgroup_compare_t compare;
1653     scripting_rtgroup *rtgs;
1654     scripting_node *ns1, *ns2;
1655     struct userdata *u;
1656     mir_rtgroup *rtg;
1657     mir_node *node1, *node2;
1658     bool success;
1659
1660     (void)L;
1661
1662     pa_assert(signature);
1663     pa_assert(args);
1664     pa_assert(ret_type);
1665     pa_assert(ret_val);
1666
1667     pa_assert_se((compare = (mir_rtgroup_compare_t)data));
1668
1669     if (strcmp(signature, "ooo"))
1670         success = false;
1671     else {
1672         pa_assert_se((rtgs = args[0].pointer));
1673         pa_assert_se((u = rtgs->userdata));
1674         pa_assert_se((ns1 = args[1].pointer));
1675         pa_assert_se((ns2 = args[2].pointer));
1676
1677
1678         if (!(rtg = rtgs->rtg) || !(node1 = ns1->node) || !(node2 = ns2->node))
1679             success = false;
1680         else {
1681             success = true;
1682             *ret_type = MRP_FUNCBRIDGE_FLOATING;
1683             ret_val->floating = compare(u, rtg, node1, node2);
1684         }
1685     }
1686
1687     return success;
1688 }
1689
1690
1691 static int apclass_create(lua_State *L)
1692 {
1693     struct userdata *u;
1694     size_t fldnamlen;
1695     const char *fldnam;
1696     scripting_apclass *ac;
1697     char name[256];
1698     const char *class = NULL;
1699     mir_node_type type = -1;
1700     int priority = -1;
1701     route_t *route = NULL;
1702     map_t *roles = NULL;
1703     map_t *binaries = NULL;
1704     pa_bool_t needs_resource = FALSE;
1705     pa_nodeset_resdef *resdef;
1706     map_t *r, *b;
1707     size_t i;
1708     pa_bool_t ir, or;
1709
1710     MRP_LUA_ENTER;
1711
1712     lua_getglobal(L, USERDATA);
1713     if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
1714         luaL_error(L, "missing or invalid global '" USERDATA "'");
1715     lua_pop(L, 1);
1716
1717
1718     MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
1719
1720         switch (field_name_to_type(fldnam, fldnamlen)) {
1721         case CLASS:       class = luaL_checkstring(L, -1);             break;
1722         case NODE_TYPE:   type = luaL_checkint(L, -1);                 break;
1723         case PRIORITY:    priority = luaL_checkint(L, -1);             break;
1724         case ROUTE:       route = route_check(L, -1);                  break;
1725         case ROLES:       roles = map_check(L, -1);                    break;
1726         case BINARIES:    binaries = map_check(L, -1);                 break;
1727         default:          luaL_error(L, "bad field '%s'", fldnam);     break;
1728         }
1729
1730     } /* MRP_LUA_FOREACH_FIELD */
1731
1732     if (type < mir_application_class_begin ||
1733         type >= mir_application_class_end    )
1734         luaL_error(L, "missing or invalid node_type %d", type);
1735     if (priority < 0)
1736         luaL_error(L, "missing or invalid priority field");
1737     if (!route)
1738         luaL_error(L, "missing or invalid route field");
1739     if (!roles && !binaries)
1740         luaL_error(L, "missing roles or binaries");
1741
1742     make_id(name, sizeof(name), "%s", mir_node_type_str(type));
1743
1744     mir_router_assign_class_priority(u, type, priority); 
1745
1746     /*
1747     ir = !route->input  ? TRUE : mir_router_assign_class_to_rtgroup(
1748                                                         u, type,
1749                                                         mir_input,
1750                                                         route->input);
1751     or = !route->output ? TRUE : mir_router_assign_class_to_rtgroup(
1752                                                         u, type,
1753                                                         mir_output,
1754                                                         route->output);
1755     */
1756
1757     ac = (scripting_apclass *)mrp_lua_create_object(L, APPLICATION_CLASS,
1758                                                     name, 0);
1759
1760     if (/* !ir || !or || */ !ac)
1761         luaL_error(L, "failed to create application class '%s'", name);
1762
1763     ac->userdata = u;
1764     ac->name = pa_xstrdup(name);
1765     ac->class = class ? pa_xstrdup(class) : NULL;
1766     ac->type = type;
1767     ac->priority = priority;
1768     ac->route = route;
1769     ac->roles = roles;
1770     ac->binaries = binaries;
1771
1772     if (class) {
1773         if (pa_nodeset_add_class(u, type, class)) {
1774             luaL_error(L, "node type '%s' is defined multiple times",
1775                        mir_node_type_str(type));
1776         }
1777     }
1778
1779     if (roles) {
1780         for (r = roles;  r->name;  r++) {
1781             resdef = r->needres ? &r->resource : NULL;
1782
1783             if (pa_nodeset_add_role(u, r->name, type, resdef)) {
1784                 luaL_error(L, "role '%s' is added to mutiple application "
1785                            "classes", r->name);
1786             }
1787         }
1788     }
1789
1790     if (binaries) {
1791         for (b = binaries;  b->name;  b++) {
1792             resdef = b->needres ? &b->resource : NULL;
1793
1794             if (pa_nodeset_add_binary(u, b->name, type, resdef)) {
1795                 luaL_error(L, "binary '%s' is added to multiple application "
1796                            "classes", b->name);
1797             }
1798         }
1799     }
1800
1801     MRP_LUA_LEAVE(1);
1802 }
1803
1804 static int apclass_getfield(lua_State *L)
1805 {
1806     scripting_apclass *ac;
1807     field_t fld;
1808
1809     MRP_LUA_ENTER;
1810
1811     fld = field_check(L, 2, NULL);
1812     lua_pop(L, 1);
1813
1814     if (!(ac=(scripting_apclass *)mrp_lua_check_object(L,APPLICATION_CLASS,1)))
1815         lua_pushnil(L);
1816     else {
1817         switch (fld) {
1818         case NAME:           lua_pushstring(L, ac->name);          break;
1819         case NODE_TYPE:      lua_pushinteger(L, ac->type);         break;
1820         case PRIORITY:       lua_pushinteger(L, ac->priority);     break;
1821         case ROUTE:          route_push(L, ac->route);             break;
1822         case ROLES:          map_push(L, ac->roles);               break;
1823         case BINARIES:       map_push(L, ac->binaries);            break;
1824         default:             lua_pushnil(L);                       break;
1825         }
1826     }
1827
1828     MRP_LUA_LEAVE(1);
1829 }
1830
1831 static int apclass_setfield(lua_State *L)
1832 {
1833     const char *f;
1834
1835     MRP_LUA_ENTER;
1836
1837     f = luaL_checkstring(L, 2);
1838     luaL_error(L,"attempt to set '%s' field of read-only application class",f);
1839     
1840     MRP_LUA_LEAVE(0);
1841 }
1842
1843 static int apclass_tostring(lua_State *L)
1844 {
1845     scripting_apclass *ac;
1846
1847     MRP_LUA_ENTER;
1848
1849     ac = (scripting_apclass *)mrp_lua_check_object(L, APPLICATION_CLASS, 1);
1850
1851     lua_pushstring(L, ac->name);
1852
1853     MRP_LUA_LEAVE(1);
1854 }
1855
1856 static void apclass_destroy(void *data)
1857 {
1858     scripting_apclass *ac = (scripting_apclass *)data;
1859     struct userdata *u;
1860     map_t *r, *b;
1861     size_t i;
1862
1863     MRP_LUA_ENTER;
1864
1865     pa_assert(ac);
1866     pa_assert_se((u = ac->userdata));
1867
1868     route_destroy(ac->route);
1869     ac->route = NULL;
1870
1871     pa_xfree((void *)ac->name);
1872     ac->name = NULL;
1873
1874     pa_nodeset_delete_class(u, ac->type);
1875     pa_xfree((void *)ac->class);
1876     ac->class = NULL;
1877
1878     if (ac->roles) {
1879         for (r = ac->roles;  r->name;  r++)
1880             pa_nodeset_delete_role(u, r->name);
1881
1882         map_destroy(ac->roles);
1883         ac->roles = NULL;
1884     }
1885
1886     if (ac->binaries) {
1887         for (b = ac->binaries;  b->name;  b++)
1888             pa_nodeset_delete_binary(u, b->name);
1889
1890         map_destroy(ac->binaries);
1891         ac->binaries = NULL;
1892     }
1893
1894     MRP_LUA_LEAVE_NOARG;
1895 }
1896
1897 static const char **route_definition_check(lua_State *L, int idx)
1898 {
1899     size_t zonelen;
1900     const char *zonenam;
1901     scripting_zone *zone;
1902     scripting_rtgroup *rtgs;
1903     mir_rtgroup *rtg;
1904     const char **defs;
1905     const char *rtgnam;
1906     int ndef;
1907
1908     idx = (idx < 0) ? lua_gettop(L) + idx + 1 : idx;
1909
1910     luaL_checktype(L, idx, LUA_TTABLE);
1911
1912     defs = pa_xnew0(const char *, MRP_ZONE_MAX);
1913     ndef = 0;
1914
1915     MRP_LUA_FOREACH_FIELD(L, idx, zonenam, zonelen) {
1916         if (!zonenam[0])
1917             luaL_error(L, "invalid route definition");
1918
1919         mrp_lua_find_object(L, ZONE_CLASS, zonenam);
1920
1921         if (!(zone = mrp_lua_check_object(L, NULL, -1)))
1922             luaL_error(L, "can't find zone '%s'", zonenam);
1923
1924         lua_pop(L, 1);
1925
1926         if (zone->index >= MRP_ZONE_MAX)
1927             luaL_error(L, "Internal error: zone index overflow");
1928
1929         switch (lua_type(L, -1)) {
1930         case LUA_TSTRING:
1931             rtgnam = lua_tostring(L, -1);
1932             break;
1933         case LUA_TTABLE:
1934             rtgs = (scripting_rtgroup*)mrp_lua_check_object(L,RTGROUP_CLASS,-1);
1935             if (!rtgs || !(rtg = rtgs->rtg))
1936                 rtgnam = NULL;
1937             else
1938                 rtgnam = rtg->name;
1939             break;
1940         default:
1941             rtgnam = NULL;
1942             break;
1943         }
1944
1945         if (!rtgnam)
1946             luaL_error(L, "missing or invalid routing group");
1947
1948         defs[zone->index] = pa_xstrdup(rtgnam);
1949         ndef++;
1950     }
1951
1952     if (!ndef)
1953         luaL_error(L, "empty definition");
1954
1955     return defs;
1956 }
1957
1958 static int route_definition_push(lua_State *L, const char **defs)
1959 {
1960     int i;
1961
1962     lua_createtable(L, MRP_ZONE_MAX, 0);
1963
1964     for (i = 0;  i < MRP_ZONE_MAX;  i++) {
1965     }
1966
1967     return 1;
1968 }
1969
1970
1971 static void route_definition_free(const char **defs)
1972 {
1973     int i;
1974
1975     if (defs) {
1976         for (i = 0;  i < MRP_ZONE_MAX;  i++)
1977             pa_xfree((void *)defs[i]);
1978         pa_xfree((void *)defs);
1979     }
1980 }
1981
1982
1983 static route_t *route_check(lua_State *L, int idx)
1984 {
1985     size_t fldnamlen;
1986     const char *fldnam;
1987     route_t *rt;
1988     const char **input = NULL;
1989     const char **output = NULL;
1990
1991     idx = (idx < 0) ? lua_gettop(L) + idx + 1 : idx;
1992
1993     luaL_checktype(L, idx, LUA_TTABLE);
1994
1995     MRP_LUA_FOREACH_FIELD(L, idx, fldnam, fldnamlen) {
1996         switch (field_name_to_type(fldnam, fldnamlen)) {
1997         case        INPUT:  input  = route_definition_check(L, -1);      break;
1998         case        OUTPUT: output = route_definition_check(L, -1);      break;
1999         default:    luaL_error(L, "invalid field '%s'", fldnam);         break;
2000         }
2001     } /* MRP_LUA_FOREACH_FIELD */
2002
2003     if (!input && !output)
2004         luaL_error(L, "neither input nor output routing group were specified");
2005
2006     rt = pa_xmalloc(sizeof(route_t));
2007     rt->input  = input;
2008     rt->output = output;
2009
2010     return rt;
2011 }
2012
2013 static int route_push(lua_State *L, route_t *rt)
2014 {
2015     if (!rt || (!rt->input && !rt->output))
2016         lua_pushnil(L);
2017     else {
2018         lua_createtable(L, 0, 2);
2019
2020         if (rt->input) {
2021             lua_pushstring(L, "input");
2022             route_definition_push(L, rt->input);
2023             lua_settable(L, -3);
2024         }
2025         
2026         if (rt->output) {
2027             lua_pushstring(L, "output");
2028             route_definition_push(L, rt->output);
2029             lua_settable(L, -3);
2030         }
2031     }
2032
2033     return 1;
2034 }
2035
2036 static void route_destroy(route_t *rt)
2037 {
2038     if (rt) {
2039         pa_xfree((void *)rt->input);
2040         pa_xfree((void *)rt->output);
2041         pa_xfree((void *)rt);
2042     }
2043 }
2044
2045
2046 static int vollim_create(lua_State *L)
2047 {
2048     static int min = mir_application_class_begin;
2049     static int max = mir_application_class_end;
2050
2051     struct userdata *u;
2052     size_t fldnamlen;
2053     const char *fldnam;
2054     scripting_vollim *vlim;
2055     const char *name = NULL;
2056     vollim_type type = 0;
2057     limit_data_t *limit = NULL;
2058     mrp_funcbridge_t *calculate = NULL;
2059     intarray_t *classes = NULL;
2060     pa_bool_t suppress = FALSE;
2061     pa_bool_t correct = FALSE;
2062     size_t arglgh = 0;
2063     size_t i;
2064     int class;
2065     uint32_t mask, clmask;
2066     char id[256];
2067
2068     MRP_LUA_ENTER;
2069
2070     lua_getglobal(L, USERDATA);
2071     if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
2072         luaL_error(L, "missing or invalid global '" USERDATA "'");
2073     lua_pop(L, 1);
2074
2075
2076     MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
2077
2078         switch (field_name_to_type(fldnam, fldnamlen)) {
2079         case NAME:      name      = luaL_checkstring(L, -1);             break;
2080         case TYPE:      type      = luaL_checkint(L, -1);                break;
2081         case NODE_TYPE: classes = intarray_check(L, -1, min, max);       break;
2082         case LIMIT:     limit     = limit_data_check(L, -1);             break;
2083         case CALCULATE: calculate = mrp_funcbridge_create_luafunc(L,-1); break;
2084         default:        luaL_error(L, "bad field '%s'", fldnam);         break;
2085         }
2086
2087     } /* MRP_LUA_FOREACH_FIELD */
2088
2089     if (!name)
2090         luaL_error(L, "missing name field");
2091     if (type != vollim_class && type != vollim_generic)
2092         luaL_error(L, "missing or invalid type");
2093     if (type == vollim_class && !classes)
2094         luaL_error(L, "missing or invalid node_type for class volume limit");
2095     if (type == vollim_generic && classes)
2096         luaL_error(L, "can't specify node_type for generic volume limit");
2097     if (!limit)
2098         luaL_error(L, "missing or invalid limit");
2099     if (!calculate)
2100         luaL_error(L, "missing calculate field");
2101     if (calculate->type == MRP_C_FUNCTION) {
2102         if (strcmp(calculate->c.signature, "odo"))
2103             luaL_error(L, "invalid calculate field (mismatching signature)");
2104         if (calculate->c.data == mir_volume_suppress) {
2105             if (type != vollim_class)
2106                 luaL_error(L, "attempt to make generic volume supression");
2107             suppress = TRUE;
2108             arglgh = sizeof(mir_volume_suppress_arg);
2109         }
2110         else if (calculate->c.data == mir_volume_correction) {
2111             if (type != vollim_generic)
2112                 luaL_error(L, "attempt to make class based volume correction");
2113             correct = TRUE;
2114             arglgh = sizeof(double *);
2115         }
2116         else {
2117             luaL_error(L, "invalid builtin.method for calculate");
2118         }
2119     }
2120
2121     make_id(id, sizeof(id), "%s", name);
2122
2123     (VOLLIM_CLASS)->userdata_size = sizeof(scripting_vollim) + arglgh;
2124     vlim = (scripting_vollim *)mrp_lua_create_object(L, VOLLIM_CLASS, id,0);
2125     (VOLLIM_CLASS)->userdata_size = sizeof(scripting_vollim);
2126
2127     vlim->userdata = u;
2128     vlim->name = pa_xstrdup(name);
2129     vlim->type = type;
2130     vlim->classes = classes;
2131     vlim->limit = limit;
2132     vlim->calculate = calculate;
2133
2134     if (suppress) {
2135         mir_volume_suppress_arg *args = (mir_volume_suppress_arg *)vlim->args;
2136         size_t size = sizeof(int) * classes->nint;
2137         size_t n = mir_application_class_end - mir_application_class_begin;
2138
2139         for (i = 0, clmask = 0;   i < classes->nint;   i++) {
2140             class = classes->ints[i];
2141
2142             if (class <= mir_application_class_begin ||
2143                 class >  mir_application_class_end     )
2144             {
2145                 pa_log("invalid triggering class id %d", class);
2146                 clmask = 0;
2147                 classes->nint = n = 0;
2148                 break;
2149             }
2150
2151             mask = ((uint32_t)1) << (class - mir_application_class_begin);
2152
2153             if (!(clmask & mask) && n > 0)
2154                 n--;
2155
2156             clmask |= mask;
2157         }
2158
2159         args->attenuation = limit->value;
2160         args->trigger.nclass = classes->nint;
2161         args->trigger.classes = pa_xmalloc(size);
2162         args->trigger.clmask = clmask;
2163
2164         memcpy(args->trigger.classes, classes->ints, size);
2165
2166         if (n > classes->nint)
2167             classes->ints = pa_xrealloc(classes->ints, sizeof(int) * n);
2168         classes->nint = n;
2169
2170         for (i = mir_application_class_begin, n = 0;
2171              i < mir_application_class_end;
2172              i++)
2173         {
2174             if (!(clmask & (((uint32_t)1) << (i-mir_application_class_begin))))
2175                 classes->ints[n++] = i;
2176         }
2177     }
2178     else if (correct) {
2179         /* *(double **)vlim->args = limit->value; */
2180     
2181         memcpy(vlim->args, &limit->value, sizeof(limit->value));
2182     }
2183
2184     if (type == vollim_generic)
2185         mir_volume_add_generic_limit(u, vollim_calculate, vlim->args);
2186     else {
2187         for (i = 0;  i < classes->nint;  i++) {
2188             mir_volume_add_class_limit(u, classes->ints[i], vollim_calculate,
2189                                        vlim->args);
2190         }
2191     }
2192
2193     MRP_LUA_LEAVE(1);
2194 }
2195
2196 static int vollim_getfield(lua_State *L)
2197 {
2198     scripting_vollim *vlim;
2199     field_t fld;
2200
2201     MRP_LUA_ENTER;
2202
2203     fld = field_check(L, 2, NULL);
2204     lua_pop(L, 1);
2205
2206     if (!(vlim = (scripting_vollim *)mrp_lua_check_object(L, VOLLIM_CLASS, 1)))
2207         lua_pushnil(L);
2208     else {
2209         switch (fld) {
2210         case NAME:         lua_pushstring(L, vlim->name);           break;
2211         case TYPE:         lua_pushinteger(L, vlim->type);          break;
2212         case NODE_TYPE:    intarray_push(L, vlim->classes);         break;
2213         case LIMIT:        lua_pushnumber(L, *vlim->limit->value);  break;
2214         default:           lua_pushnil(L);                          break;
2215         }
2216     }
2217
2218     MRP_LUA_LEAVE(1);
2219 }
2220
2221 static int vollim_setfield(lua_State *L)
2222 {
2223     const char *f;
2224
2225     MRP_LUA_ENTER;
2226
2227     f = luaL_checkstring(L, 2);
2228     luaL_error(L, "attempt to set '%s' field of read-only volume_limit", f);
2229     
2230     MRP_LUA_LEAVE(0);
2231 }
2232
2233 static int vollim_tostring(lua_State *L)
2234 {
2235     scripting_vollim *vlim;
2236
2237     MRP_LUA_ENTER;
2238
2239     vlim = (scripting_vollim *)mrp_lua_check_object(L, VOLLIM_CLASS, 1);
2240
2241     lua_pushstring(L, vlim->name);
2242
2243     MRP_LUA_LEAVE(1);
2244 }
2245
2246 static void vollim_destroy(void *data)
2247 {
2248     scripting_vollim *vlim = (scripting_vollim *)data;
2249
2250     MRP_LUA_ENTER;
2251
2252     pa_xfree((void *)vlim->name);
2253     intarray_destroy(vlim->classes);
2254     limit_data_destroy(vlim->limit);
2255
2256     MRP_LUA_LEAVE_NOARG;
2257 }
2258
2259
2260 static double vollim_calculate(struct userdata *u, int class, mir_node *node,
2261                                void *data)
2262 {
2263     static int offset = ((scripting_vollim *)0)->args - (char *)0;
2264
2265     pa_scripting *scripting;
2266     lua_State *L;
2267     scripting_vollim *vlim;
2268     mrp_funcbridge_value_t args[3];
2269     char rt;
2270     mrp_funcbridge_value_t  rv;
2271     double limit;
2272
2273     pa_assert(u);
2274     pa_assert_se((scripting = u->scripting));
2275     pa_assert_se((L = scripting->L));
2276     pa_assert(!class || (class >= mir_application_class_begin &&
2277                          class <  mir_application_class_end)     );
2278     pa_assert(node);
2279
2280     vlim = (scripting_vollim *)(data - offset);
2281
2282     pa_assert(u == vlim->userdata);
2283
2284     limit = -90.0;
2285
2286     if (node->scripting) {
2287
2288         args[0].pointer = vlim;
2289         args[1].integer = class;
2290         args[2].pointer = node->scripting;
2291
2292         if (!mrp_funcbridge_call_from_c(L,vlim->calculate,"odo",args,&rt,&rv))
2293             pa_log("failed to call calculate function");
2294         else {
2295             if (rt != MRP_FUNCBRIDGE_FLOATING)
2296                 pa_log("accept function returned invalid type");
2297             else
2298                 limit = rv.floating;
2299         }
2300     }
2301
2302     return limit;
2303 }
2304
2305 static bool calculate_bridge(lua_State *L, void *data, const char *signature,
2306                              mrp_funcbridge_value_t *args,
2307                              char *ret_type, mrp_funcbridge_value_t *ret_val)
2308 {
2309     mir_volume_func_t calculate;
2310     scripting_vollim *vlim;
2311     scripting_node *ns;
2312     struct userdata *u;
2313     int class;
2314     mir_node *node;
2315     bool success;
2316
2317     (void)L;
2318
2319     pa_assert(signature);
2320     pa_assert(args);
2321     pa_assert(ret_type);
2322     pa_assert(ret_val);
2323
2324     pa_assert_se((calculate = (mir_volume_func_t)data));
2325
2326     if (strcmp(signature, "odo"))
2327         success = false;
2328     else {
2329         pa_assert_se((vlim = args[0].pointer));
2330         pa_assert_se((u = vlim->userdata));
2331         pa_assert_se((ns = args[2].pointer));
2332
2333         class = args[1].integer;
2334
2335         pa_assert(!class || (class >= mir_application_class_begin &&
2336                              class <  mir_application_class_end));
2337
2338         if (!(node = ns->node))
2339             success = false;
2340         else {
2341             success = true;
2342             *ret_type = MRP_FUNCBRIDGE_FLOATING;
2343             ret_val->floating = calculate(u, class, node, vlim->args);
2344         }
2345     }
2346
2347     return success;
2348 }
2349
2350 static limit_data_t *limit_data_check(lua_State *L, int idx)
2351 {
2352     static double nolimit = 0.0;
2353
2354     limit_data_t *ld;
2355     double value;
2356     pa_value *v;
2357
2358     switch (lua_type(L, idx)) {
2359     case LUA_TNUMBER:
2360         if ((value = lua_tonumber(L, idx)) > 0.0)
2361             luaL_error(L, "volume limit is in dB and can't be positive");
2362         else {
2363             ld = pa_xnew0(limit_data_t, 1);
2364             ld->mallocd = TRUE;
2365             ld->value = pa_xnew0(double, 1);
2366             *ld->value = value;
2367         }
2368         break;
2369     case LUA_TLIGHTUSERDATA:
2370         if (!(v = lua_touserdata(L, idx)) || v->type < 0)
2371             luaL_error(L, "broken link for volume limit value");
2372         else {
2373             ld = pa_xnew0(limit_data_t, 1);
2374             ld->mallocd = FALSE;
2375             ld->value = &v->floating;
2376         }
2377         break;
2378     default:
2379         ld->mallocd = FALSE;
2380         ld->value = &nolimit;
2381         break;
2382     }
2383
2384     return ld;
2385 }
2386
2387 #if 0
2388 static int limit_data_push(lua_State *L, limit_data_t *ld)
2389 {
2390     if (ld)
2391         lua_pushnumber(L, *ld->value);
2392     else
2393         lua_pushnil;
2394
2395     return 1;
2396 }
2397 #endif
2398
2399 static void limit_data_destroy(limit_data_t *ld)
2400 {
2401     if (ld) {
2402         if (ld->mallocd)
2403             pa_xfree(ld->value);
2404         pa_xfree(ld);
2405     }
2406 }
2407
2408
2409 static intarray_t *intarray_check(lua_State *L, int idx, int min, int max)
2410 {
2411     size_t len;
2412     size_t size;
2413     intarray_t *arr;
2414     int val;
2415     size_t i;
2416
2417     idx = (idx < 0) ? lua_gettop(L) + idx + 1 : idx;
2418
2419     luaL_checktype(L, idx, LUA_TTABLE);
2420
2421     if ((len = luaL_getn(L, idx)) < 1)
2422         arr = NULL;
2423     else {
2424         size = sizeof(intarray_t) + sizeof(int) * len;
2425         arr  = pa_xmalloc0(sizeof(intarray_t));
2426
2427         arr->nint = len;
2428         arr->ints = pa_xmalloc0(size);
2429
2430         for (i = 0;  i < len;  i++) {
2431             lua_pushnumber(L, (int)(i+1));
2432             lua_gettable(L, idx);
2433             
2434             val = luaL_checkint(L, -1);
2435             
2436             lua_pop(L, 1);
2437             
2438             if (val < min || val >= max)
2439                 luaL_error(L, "array [%u]: out of range value (%d)", i, val); 
2440             
2441             arr->ints[i] = val;
2442         }
2443     }
2444
2445     return arr;
2446 }
2447
2448 static int intarray_push(lua_State *L, intarray_t *arr)
2449 {
2450     size_t i;
2451
2452     if (!arr)
2453         lua_pushnil(L);
2454     else {
2455         lua_createtable(L, arr->nint, 0);
2456
2457         for (i = 0;  i < arr->nint;  i++) {
2458             lua_pushinteger(L, (int)(i+1));
2459             lua_pushinteger(L, arr->ints[i]);
2460             lua_settable(L, -3);
2461         }
2462     }
2463
2464     return 1;
2465 }
2466
2467 static void intarray_destroy(intarray_t *arr)
2468 {
2469     if (arr) {
2470         pa_xfree(arr->ints);
2471         pa_xfree(arr);
2472     }
2473 }
2474
2475 static resource_name_t *resource_names_check(lua_State *L, int tbl)
2476 {
2477     resource_name_t *name;
2478     size_t fldnamlen;
2479     const char *fldnam;
2480     const char *value;
2481
2482     tbl = (tbl < 0) ? lua_gettop(L) + tbl + 1 : tbl;
2483
2484     luaL_checktype(L, tbl, LUA_TTABLE);
2485
2486     name = pa_xnew0(resource_name_t, 1);
2487
2488     MRP_LUA_FOREACH_FIELD(L, tbl, fldnam, fldnamlen) {
2489         value = luaL_checkstring(L, -1);
2490
2491         if (!strcmp(fldnam, "recording"))
2492             name->recording = pa_xstrdup(value);
2493         else if (!strcmp(fldnam, "playback"))
2494             name->playback = pa_xstrdup(value);
2495         else {
2496             luaL_error(L, "invalid field '%s' in resource name definition",
2497                        fldnam);
2498         }
2499     }
2500
2501     return name;
2502 }
2503
2504 static void resource_names_destroy(resource_name_t *name)
2505 {
2506     if (name) {
2507         pa_xfree((void *)name->recording);
2508         pa_xfree((void *)name->playback);
2509         pa_xfree(name);
2510     }
2511 }
2512
2513 static attribute_t *attributes_check(lua_State *L, int tbl)
2514 {
2515     int def;
2516     size_t fldnamlen;
2517     const char *fldnam;
2518     attribute_t *attr, *attrs = NULL;
2519     size_t nattr = 0;
2520     mrp_attr_value_t *v;
2521     size_t i, len;
2522
2523     tbl = (tbl < 0) ? lua_gettop(L) + tbl + 1 : tbl;
2524
2525     luaL_checktype(L, tbl, LUA_TTABLE);
2526
2527     MRP_LUA_FOREACH_FIELD(L, tbl, fldnam, fldnamlen) {
2528         if (!fldnam[0])
2529             luaL_error(L, "invalid attribute definition");
2530
2531         attrs = pa_xrealloc(attrs, sizeof(attribute_t) * (nattr + 2));
2532         memset(attrs + nattr, 0, sizeof(attribute_t) * 2);
2533
2534         attr = attrs + nattr++;
2535         v = &attr->def.value;
2536         def = lua_gettop(L);
2537
2538         attr->def.name = pa_xstrdup(fldnam);
2539         
2540         if ((len = luaL_getn(L, def)) != 3)
2541             luaL_error(L, "invalid attribute definition '%s'", fldnam);
2542
2543         for (i = 0;  i < len;  i++) {
2544             lua_pushnumber(L, (int)(i+1));
2545             lua_gettable(L, def);
2546
2547             switch (i) {
2548             case 0:  attr->prop = pa_xstrdup(luaL_checkstring(L,-1));    break;
2549             case 1:  attr->def.type = luaL_checkint(L,-1);               break;
2550             case 2:
2551                 switch (attr->def.type) {
2552                 case mqi_string:   v->string = luaL_checkstring(L,-1);   break;
2553                 case mqi_integer:  v->integer = luaL_checkint(L,-1);     break;
2554                 case mqi_unsignd:  v->integer = luaL_checkint(L,-1);     break;
2555                 case mqi_floating: v->floating = luaL_checknumber(L,-1); break;
2556                 default:           memset(v, 0, sizeof(*v));             break;
2557                 }
2558             }
2559
2560             lua_pop(L, 1);
2561         }
2562
2563         if (!attr->prop)
2564             luaL_error(L, "missing property name definition from '%s'",fldnam);
2565         if (attr->def.type != mqi_string  && attr->def.type != mqi_integer &&
2566             attr->def.type != mqi_unsignd && attr->def.type != mqi_floating)
2567         {
2568             luaL_error(L, "invalid attribute type %d for '%s'",
2569                        attr->def.type, fldnam);
2570         }
2571         if (attr->def.type == mqi_unsignd && attr->def.value.integer < 0) {
2572             luaL_error(L, "attempt to give negative value (%d) for field '%s'",
2573                        attr->def.value.integer, fldnam);
2574         }
2575     }
2576
2577     return attrs;
2578 }
2579
2580 static void attributes_destroy(attribute_t *attrs)
2581 {
2582     attribute_t *attr;
2583
2584     if (attrs) {
2585         for (attr = attrs;  attr->prop && attr->def.name;  attr++) {
2586             pa_xfree((void *)attr->prop);
2587             pa_xfree((void *)attr->def.name);
2588             if (attr->def.type == mqi_string)
2589                 pa_xfree((void *)attr->def.value.string);
2590         }
2591         pa_xfree(attrs);
2592     }
2593 }
2594
2595 static map_t *map_check(lua_State *L, int tbl)
2596 {
2597     int def;
2598     size_t namlen;
2599     const char *name;
2600     const char *flag;
2601     map_t *m, *map = NULL;
2602     size_t n = 0;
2603     size_t i, len;
2604     int priority;
2605     pa_nodeset_resdef *rd;
2606
2607     tbl = (tbl < 0) ? lua_gettop(L) + tbl + 1 : tbl;
2608
2609     luaL_checktype(L, tbl, LUA_TTABLE);
2610
2611     MRP_LUA_FOREACH_FIELD(L, tbl, name, namlen) {
2612         if (!name[0])
2613             luaL_error(L, "invalid role or binary definition");
2614
2615         map = pa_xrealloc(map, sizeof(map_t) * (n + 2));
2616         memset(map + n, 0, sizeof(map_t) * 2);
2617
2618         m = map + n++;
2619         def = lua_gettop(L);
2620
2621         m->name = pa_xstrdup(name);
2622
2623         switch (lua_type(L, -1)) {
2624
2625         case LUA_TNUMBER:
2626             m->needres = FALSE;
2627             break;
2628
2629         case LUA_TTABLE:
2630             m->needres = TRUE;
2631
2632             if ((len = luaL_getn(L, def)) < 1)
2633                 luaL_error(L, "invalid resource definition '%s'", name);
2634
2635             for (i = 1;  i <= len;  i++) {
2636                 lua_pushnumber(L, (int)i);
2637                 lua_gettable(L, def);
2638
2639                 if (i == 1) {
2640                     priority = luaL_checkint(L, -1);
2641
2642                     if (priority < 0 || priority > 7) {
2643                         luaL_error(L, "invalid priority %d for '%s'",
2644                                    priority, name);
2645                     }
2646
2647                     m->resource.priority = priority;
2648                 }
2649                 else {
2650                     flag = luaL_checkstring(L, -1);
2651                     rd = &m->resource;
2652
2653                     if (pa_streq(flag, "autorelease"))
2654                         rd->flags.rset |= RESPROTO_RSETFLAG_AUTORELEASE;
2655                     else if (pa_streq(flag, "mandatory"))
2656                         rd->flags.audio |= RESPROTO_RESFLAG_MANDATORY;
2657                     else if (pa_streq(flag, "shared"))
2658                         rd->flags.audio |= RESPROTO_RESFLAG_SHARED;
2659                     else if (!pa_streq(flag, "optional") &&
2660                              !pa_streq(flag, "exclusive") )
2661                     {
2662                         luaL_error(L, "invalid flag '%s' for '%s'", flag,name);
2663                     }
2664                 }
2665
2666                 lua_pop(L, 1);
2667             }
2668
2669             break;
2670
2671         default:
2672             luaL_error(L, "invalid resource specification. "
2673                        "Should be either 'no_resource' or a table");
2674             break;
2675         }
2676     } /* FOREACH_FIELD */
2677
2678     return map;
2679 }
2680
2681 static int map_push(lua_State *L, map_t *map)
2682 {
2683     map_t *m;
2684
2685     if (!map)
2686         lua_pushnil(L);
2687     else {
2688         lua_newtable(L);
2689
2690         for (m = map;  m->name;  m++) {
2691             if (!m->needres)
2692                 lua_pushnumber(L, 0);
2693             else {
2694                 lua_newtable(L);
2695                 lua_pushinteger(L, m->resource.priority);
2696                 if (m->resource.flags.rset & RESPROTO_RSETFLAG_AUTORELEASE)
2697                     lua_pushstring(L, "autorelease");
2698                 if (m->resource.flags.audio & RESPROTO_RESFLAG_MANDATORY)
2699                     lua_pushstring(L, "mandatory");
2700                 else
2701                     lua_pushstring(L, "optional");
2702                 if (m->resource.flags.audio & RESPROTO_RESFLAG_SHARED)
2703                     lua_pushstring(L, "shared");
2704                 else
2705                     lua_pushstring(L, "exclusive");
2706             }
2707             lua_setfield(L, -2, m->name);
2708         }
2709     }
2710
2711     return 1;
2712 }
2713
2714 static void map_destroy(map_t *map)
2715 {
2716     map_t *m;
2717
2718     if (map) {
2719         for (m = map;  m->name;  m++) {
2720             pa_xfree((void *)m->name);
2721         }
2722         pa_xfree(map);
2723     }
2724 }
2725
2726
2727 static field_t field_check(lua_State *L, int idx, const char **ret_fldnam)
2728 {
2729     const char *fldnam;
2730     size_t fldnamlen;
2731     field_t fldtyp;
2732
2733     if (!(fldnam = lua_tolstring(L, idx, &fldnamlen)))
2734         fldtyp = 0;
2735     else
2736         fldtyp = field_name_to_type(fldnam, fldnamlen);
2737
2738     if (ret_fldnam)
2739         *ret_fldnam = fldnam;
2740
2741     return fldtyp;
2742 }
2743
2744 static field_t field_name_to_type(const char *name, size_t len)
2745 {
2746     switch (len) {
2747
2748     case 4:
2749         switch (name[0]) {
2750         case 'n':
2751             if (!strcmp(name, "name"))
2752                 return NAME;
2753             break;
2754         case 't':
2755             if (!strcmp(name, "type"))
2756                 return TYPE;
2757             break;
2758         case 'z':
2759             if (!strcmp(name, "zone"))
2760                 return ZONE;
2761             break;
2762         default:
2763             break;
2764         }
2765         break;
2766
2767     case 5:
2768         switch (name[0]) {
2769         case 'c':
2770             if (!strcmp(name, "class"))
2771                 return CLASS;
2772             break;
2773         case 'i':
2774             if (!strcmp(name, "input"))
2775                 return INPUT;
2776             break;
2777         case 'l':
2778             if (!strcmp(name, "limit"))
2779                 return LIMIT;
2780             break;
2781         case 'r':
2782             if (!strcmp(name, "route"))
2783                 return ROUTE;
2784             if (!strcmp(name, "roles"))
2785                 return ROLES;
2786             break;
2787         case 't':
2788             if (!strcmp(name, "table"))
2789                 return TABLE;
2790             break;
2791         default:
2792             break;
2793         }
2794         break;
2795
2796     case 6:
2797         switch (name[0]) {
2798         case 'a':
2799             if (!strcmp(name, "accept"))
2800                 return ACCEPT;
2801             break;
2802         case 'm':
2803             if (!strcmp(name, "maxrow"))
2804                 return MAXROW;
2805             break;
2806         case 'o':
2807             if (!strcmp(name, "output"))
2808                 return OUTPUT;
2809             break;
2810         case 't':
2811             if (!strcmp(name, "tables"))
2812                 return TABLES;
2813             break;
2814         case 'u':
2815             if (!strcmp(name, "update"))
2816                 return UPDATE;
2817             break;
2818         default:
2819             break;
2820         }
2821         break;
2822
2823     case 7:
2824         switch (name[0]) {
2825         case 'c':
2826             if (!strcmp(name, "compare"))
2827                 return COMPARE;
2828             if (!strcmp(name, "columns"))
2829                 return COLUMNS;
2830             break;
2831         case 'p':
2832             if (!strcmp(name, "privacy"))
2833                 return PRIVACY;
2834             break;
2835         default:
2836             break;
2837         }
2838         break;
2839
2840     case 8:
2841         switch (name[0]) {
2842         case 'b':
2843             if (!strcmp(name, "binaries"))
2844                 return BINARIES;
2845             break;
2846         case 'c':
2847             if (!strcmp(name, "channels"))
2848                 return CHANNELS;
2849             break;
2850         case 'l':
2851             if (!strcmp(name, "location"))
2852                 return LOCATION;
2853             break;
2854         case 'p':
2855             if (!strcmp(name, "priority"))
2856                 return PRIORITY;
2857             break;
2858         default:
2859             break;
2860         }
2861         break;
2862
2863     case 9:
2864         switch (name[0]) {
2865         case 'a':
2866             if (!strcmp(name, "available"))
2867                 return AVAILABLE;
2868             break;
2869         case 'c':
2870             if (!strcmp(name, "calculate"))
2871                 return CALCULATE;
2872             if (!strcmp(name, "condition"))
2873                 return CONDITION;
2874             break;
2875         case 'd':
2876             if (!strcmp(name, "direction"))
2877                 return DIRECTION;
2878             break;
2879         case 'i':
2880             if (!strcmp(name, "implement"))
2881                 return IMPLEMENT;
2882             break;
2883         case 'n':
2884             if (!strcmp(name, "node_type"))
2885                 return NODE_TYPE;
2886             break;
2887         default:
2888             break;
2889         }
2890         break;
2891
2892     case 10:
2893         if (!strcmp(name, "attributes"))
2894             return ATTRIBUTES;
2895         break;        
2896
2897     case 11:
2898         if (!strcmp(name, "autorelease"))
2899             return AUTORELEASE;
2900         if (!strcmp(name, "description"))
2901             return DESCRIPTION;
2902         break;        
2903
2904     default:
2905         break;
2906     }
2907
2908     return 0;
2909 }
2910
2911 static int make_id(char *buf, size_t len, const char *fmt, ...)
2912 {
2913     va_list ap;
2914     int l;
2915     char *p, c;
2916
2917     va_start(ap, fmt);
2918     l = vsnprintf(buf, len, fmt, ap);
2919     va_end(ap);
2920
2921     for (p = buf;  (c = *p);  p++) {
2922         if (isalpha(c))
2923             c = tolower(c);
2924         else if (!isdigit(c))
2925             c = '_';
2926         *p = c;
2927     }
2928
2929     return l;
2930 }
2931
2932
2933 static void setup_murphy_interface(struct userdata *u)
2934 {
2935     pa_scripting *scripting;
2936     scripting_import *imp;
2937     const char *key;
2938     lua_State *L;
2939     int class;
2940     pa_bool_t need_domainctl;
2941     char buf[8192];
2942     const char *columns;
2943     int top;
2944     pa_value *values;
2945
2946     MRP_LUA_ENTER;
2947
2948     pa_assert(u);
2949     pa_assert_se((scripting = u->scripting));
2950     pa_assert_se((L = scripting->L));
2951
2952     top = lua_gettop(L);
2953
2954     mrp_lua_get_class_table(L, IMPORT_CLASS);
2955     class = lua_gettop(L);
2956
2957     if (!lua_istable(L, class)){
2958         luaL_error(L, "internal error: failed to find '%s' table",
2959                    (IMPORT_CLASS)->constructor);
2960     }
2961
2962     need_domainctl = FALSE;
2963
2964     lua_pushnil(L);
2965     while (lua_next(L, class)) {
2966         if (lua_isstring(L, -2)) {
2967             if ((imp = mrp_lua_to_object(L, IMPORT_CLASS, -1))) {
2968                 key = lua_tostring(L, -2);
2969
2970                 pa_assert(!strcmp(key, imp->table));
2971                 pa_assert_se((values = imp->values));
2972
2973                 pa_log_debug("adding import '%s'", imp->table);
2974
2975                 need_domainctl = TRUE;
2976                 columns = comma_separated_list(imp->columns, buf,sizeof(buf));
2977
2978                 pa_murphyif_add_watch(u, imp->table, columns, imp->condition,
2979                                       -values->type);
2980             }
2981         }
2982         lua_pop(L, 1);
2983     }
2984
2985     if (need_domainctl)
2986         pa_murphyif_setup_domainctl(u, import_data_changed);
2987
2988     lua_settop(L, top);
2989
2990     MRP_LUA_LEAVE_NOARG;
2991 }
2992
2993
2994 static char *comma_separated_list(mrp_lua_strarray_t *arr, char *buf, int len)
2995 {
2996     char *p, *e;
2997     size_t i;
2998
2999     pa_assert(arr);
3000     pa_assert(buf);
3001     pa_assert(len > 0);
3002
3003     for (i = 0, e = (p = buf) + len;   i < arr->nstring && p < e;    i++)
3004         p += snprintf(p, e-p, "%s%s", (p == buf ? "" : ","), arr->strings[i]);
3005
3006     return (p < e) ? buf : NULL;
3007 }
3008
3009
3010 static bool define_constants(lua_State *L)
3011 {
3012     static const_def_t mdb_const[] = {
3013         { "string"           , mqi_string           },
3014         { "integer"          , mqi_integer          },
3015         { "unsigned"         , mqi_unsignd          },
3016         { "floating"         , mqi_floating         },
3017         {       NULL         ,         0            }
3018     };
3019
3020     static const_def_t node_const[] = {
3021         { "input"            , mir_input            },
3022         { "output"           , mir_output           },
3023         { "device"           , mir_device           },
3024         { "stream"           , mir_stream           },
3025         { "internal"         , mir_internal         },
3026         { "external"         , mir_external         },
3027         { "radio"            , mir_radio            },
3028         { "player"           , mir_player           },
3029         { "navigator"        , mir_navigator        },
3030         { "game"             , mir_game             },
3031         { "browser"          , mir_browser          },
3032         { "camera"           , mir_camera           },
3033         { "phone"            , mir_phone            },
3034         { "alert"            , mir_alert            },
3035         { "event"            , mir_event            },
3036         { "system"           , mir_system           },
3037         { "speakers"         , mir_speakers         },
3038         { "microphone"       , mir_microphone       },
3039         { "jack"             , mir_jack             },
3040         { "spdif"            , mir_spdif            },
3041         { "hdmi"             , mir_hdmi             },
3042         { "wired_headset"    , mir_wired_headset    },
3043         { "wired_headphone"  , mir_wired_headphone  },
3044         { "usb_headset"      , mir_usb_headset      },
3045         { "usb_headphone"    , mir_usb_headphone    },
3046         { "bluetooth_sco"    , mir_bluetooth_sco    },
3047         { "bluetooth_a2dp"   , mir_bluetooth_a2dp   },
3048         { "bluetooth_carkit" , mir_bluetooth_carkit },
3049         { "bluetooth_source" , mir_bluetooth_source },
3050         { "bluetooth_sink"   , mir_bluetooth_sink   },
3051         {       NULL         ,         0            }
3052     };
3053
3054     static const_def_t vollim_const[] = {
3055         { "class"            , vollim_class         },
3056         { "generic"          , vollim_generic       },
3057         {       NULL         ,         0            }
3058     };
3059
3060     const_def_t *cd;
3061     bool success = true;
3062
3063
3064     lua_getglobal(L, "mdb");
3065
3066     if (!lua_istable(L, -1))
3067         success = false;
3068     else {
3069         for (cd = mdb_const;   cd->name;   cd++) {
3070             lua_pushstring(L, cd->name);
3071             lua_pushinteger(L, cd->value);
3072             lua_rawset(L, -3);
3073         }
3074         lua_pop(L, 1);
3075     }
3076
3077
3078
3079     lua_getglobal(L, "node");
3080
3081     if (!lua_istable(L, -1))
3082         success = false;
3083     else {
3084         for (cd = node_const;   cd->name;   cd++) {
3085             lua_pushstring(L, cd->name);
3086             lua_pushinteger(L, cd->value);
3087             lua_rawset(L, -3);
3088         }
3089         lua_pop(L, 1);
3090     }
3091
3092
3093     lua_getglobal(L, "volume_limit");
3094
3095     if (!lua_istable(L, -1))
3096         success = false;
3097     else {
3098         for (cd = vollim_const;   cd->name;   cd++) {
3099             lua_pushstring(L, cd->name);
3100             lua_pushinteger(L, cd->value);
3101             lua_rawset(L, -3);
3102         }
3103         lua_pop(L, 1);
3104     }
3105
3106     lua_pushnumber(L, 0);
3107     lua_setglobal(L, "no_resource");
3108
3109     return success;
3110 }
3111
3112
3113 static bool register_methods(lua_State *L)
3114 {
3115     static funcbridge_def_t funcbridge_defs[] = {
3116         {"make_routes"    ,"o"  , update_bridge   ,mir_router_make_routing   },
3117         {"make_volumes"   ,"o"  , update_bridge   ,mir_volume_make_limiting  },
3118         {"accept_default" ,"oo" , accept_bridge   ,mir_router_default_accept },
3119         {"compare_default","ooo", compare_bridge  ,mir_router_default_compare},
3120         {"accept_phone"   ,"oo" , accept_bridge   ,mir_router_phone_accept   },
3121         {"compare_phone"  ,"ooo", compare_bridge  ,mir_router_phone_compare  },
3122         {"volume_supress" ,"odo", calculate_bridge,mir_volume_suppress       },
3123         {"volume_correct" ,"odo", calculate_bridge,mir_volume_correction     },
3124         {       NULL      , NULL,      NULL       ,         NULL             }
3125     };
3126
3127     funcbridge_def_t *d;
3128     bool success = true;
3129
3130     for (d = funcbridge_defs;   d->name;    d++) {
3131         if (!mrp_funcbridge_create_cfunc(L,d->name,d->sign,d->func,d->data)) {
3132             pa_log("%s: failed to register builtin function '%s'",
3133                    __FILE__, d->name);
3134             success = false;
3135         }
3136     }
3137
3138     return success;
3139 }
3140
3141
3142
3143 static void *alloc(void *ud, void *ptr, size_t osize, size_t nsize)
3144 {
3145     void *mem;
3146
3147     (void)ud;
3148     (void)osize;
3149
3150     if (nsize)
3151         mem = pa_xrealloc(ptr, nsize);
3152     else {
3153         mem = NULL;
3154         pa_xfree(ptr);
3155     }
3156
3157     return mem;
3158 }
3159
3160 static int panic(lua_State *L)
3161 {
3162     (void)L;
3163
3164     pa_log("PANIC: unprotected error in call to Lua API (%s)",
3165            lua_tostring(L,-1));
3166
3167     return 0;
3168 }
3169
3170                                   
3171 /*
3172  * Local Variables:
3173  * c-basic-offset: 4
3174  * indent-tabs-mode: nil
3175  * End:
3176  *
3177  */