scripting: support for zone based routing in application classes
[profile/ivi/pulseaudio-module-murphy-ivi.git] / murphy / node.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
22 #include <pulsecore/pulsecore-config.h>
23
24 #include <pulsecore/hashmap.h>
25 #include <pulsecore/idxset.h>
26 #include <pulsecore/strbuf.h>
27
28
29 #include "node.h"
30 #include "discover.h"
31 #include "router.h"
32 #include "constrain.h"
33 #include "scripting.h"
34 #include "murphyif.h"
35
36 #define APCLASS_DIM  (mir_application_class_end - mir_application_class_begin)
37
38 struct pa_nodeset {
39     pa_idxset      *nodes;
40     pa_hashmap     *roles;
41     pa_hashmap     *binaries;
42     const char     *class_name[APCLASS_DIM];
43 };
44
45
46 static void free_map_cb(void *);
47 static int print_map(pa_hashmap *, const char *, char *, int);
48
49 pa_nodeset *pa_nodeset_init(struct userdata *u)
50 {
51     pa_nodeset *ns;
52
53     pa_assert(u);
54
55     ns = pa_xnew0(pa_nodeset, 1);
56     ns->nodes = pa_idxset_new(pa_idxset_trivial_hash_func,
57                               pa_idxset_trivial_compare_func);
58     ns->roles = pa_hashmap_new(pa_idxset_string_hash_func,
59                                pa_idxset_string_compare_func);
60     ns->binaries = pa_hashmap_new(pa_idxset_string_hash_func,
61                                   pa_idxset_string_compare_func);
62     return ns;
63 }
64
65 void pa_nodeset_done(struct userdata *u)
66 {
67     pa_nodeset *ns;
68     int i;
69
70     if (u && (ns = u->nodeset)) {
71         pa_idxset_free(ns->nodes, NULL);
72         pa_hashmap_free(ns->roles, free_map_cb);
73         pa_hashmap_free(ns->binaries, free_map_cb);
74
75         for (i = 0;  i < APCLASS_DIM;  i++)
76             pa_xfree((void *)ns->class_name[i]);
77
78         free(ns);
79     }    
80 }
81
82 int pa_nodeset_add_class(struct userdata *u, mir_node_type t,const char *clnam)
83 {
84     pa_nodeset *ns;
85     
86     pa_assert(u);
87     pa_assert(t >= mir_application_class_begin &&
88               t <  mir_application_class_end);
89     pa_assert(clnam);
90     pa_assert_se((ns = u->nodeset));
91
92     if (!ns->class_name[t]) {
93         ns->class_name[t] = pa_xstrdup(clnam);
94         return 0;
95     }
96
97     return -1;
98 }
99
100 void pa_nodeset_delete_class(struct userdata *u, mir_node_type t)
101 {
102     pa_nodeset *ns;
103
104     pa_assert(u);
105     pa_assert(t >= mir_application_class_begin &&
106               t <  mir_application_class_end);
107     pa_assert_se((ns = u->nodeset));
108
109     pa_xfree((void *)ns->class_name[t]);
110
111     ns->class_name[t] = NULL;
112 }
113
114 const char *pa_nodeset_get_class(struct userdata *u, mir_node_type t)
115 {
116     pa_nodeset *ns;
117
118     pa_assert(u);
119     pa_assert_se((ns = u->nodeset));
120
121     if (t >= mir_application_class_begin && t <  mir_application_class_end)
122         return ns->class_name[t];
123
124     return NULL;
125 }
126
127 int pa_nodeset_add_role(struct userdata *u,
128                         const char *role,
129                         mir_node_type type,
130                         pa_nodeset_resdef *resdef)
131 {
132     pa_nodeset *ns;
133     pa_nodeset_map *map;
134
135     pa_assert(u);
136     pa_assert(role);
137     pa_assert(type >= mir_application_class_begin &&
138               type <  mir_application_class_end);
139     pa_assert_se((ns = u->nodeset));
140
141     map = pa_xnew0(pa_nodeset_map, 1);
142     map->name = pa_xstrdup(role);
143     map->type = type;
144
145     if (resdef) {
146         map->resdef = pa_xnew(pa_nodeset_resdef, 1);
147         memcpy(map->resdef, resdef, sizeof(pa_nodeset_resdef));
148     }
149
150     return pa_hashmap_put(ns->roles, map->name, map);
151 }
152
153 void pa_nodeset_delete_role(struct userdata *u, const char *role)
154 {
155     pa_nodeset_map *map;
156     pa_nodeset *ns;
157
158     pa_assert(u);
159     pa_assert(role);
160     pa_assert_se((ns = u->nodeset));
161
162     if ((map = pa_hashmap_remove(ns->roles, role))) {
163         pa_xfree((void *)map->name);
164         pa_xfree((void *)map->resdef);
165     }
166 }
167
168 pa_nodeset_map *pa_nodeset_get_map_by_role(struct userdata *u,
169                                            const char *role)
170 {
171     pa_nodeset_map *map;
172     pa_nodeset *ns;
173
174     pa_assert(u);
175     pa_assert_se((ns = u->nodeset));
176
177     if (role && ns->roles)
178         map = pa_hashmap_get(ns->roles, role);
179     else
180         map = NULL;
181         
182
183     return map;
184 }
185
186 int pa_nodeset_add_binary(struct userdata *u,
187                           const char *bin,
188                           mir_node_type type,
189                           pa_nodeset_resdef *resdef)
190 {
191     pa_nodeset *ns;
192     pa_nodeset_map *map;
193
194     pa_assert(u);
195     pa_assert(bin);
196     pa_assert(type >= mir_application_class_begin &&
197               type <  mir_application_class_end);
198     pa_assert_se((ns = u->nodeset));
199
200     map = pa_xnew0(pa_nodeset_map, 1);
201     map->name = pa_xstrdup(bin);
202     map->type = type;
203
204     if (resdef) {
205         map->resdef = pa_xnew(pa_nodeset_resdef, 1);
206         memcpy(map->resdef, resdef, sizeof(pa_nodeset_resdef));
207     }
208
209     return pa_hashmap_put(ns->binaries, map->name, map);
210 }
211
212 void pa_nodeset_delete_binary(struct userdata *u, const char *bin)
213 {
214     pa_nodeset_map *map;
215     pa_nodeset *ns;
216
217     pa_assert(u);
218     pa_assert(bin);
219     pa_assert_se((ns = u->nodeset));
220
221     if ((map = pa_hashmap_remove(ns->binaries, bin))) {
222         pa_xfree((void *)map->name);
223         pa_xfree((void *)map->resdef);
224     }
225 }
226
227 pa_nodeset_map *pa_nodeset_get_map_by_binary(struct userdata *u,
228                                              const char *bin)
229 {
230     pa_nodeset_map *map;
231     pa_nodeset *ns;
232
233     pa_assert(u);
234     pa_assert_se((ns = u->nodeset));
235
236     if (bin)
237         map = pa_hashmap_get(ns->binaries, bin);
238     else
239         map = NULL;
240         
241
242     return map;
243 }
244
245 int pa_nodeset_print_maps(struct userdata *u, char *buf, int len)
246 {
247     pa_nodeset *ns;
248     char *p, *e;
249
250     pa_assert(u);
251     pa_assert(buf);
252     pa_assert(len > 0);
253
254     pa_assert_se((ns = u->nodeset));
255
256     e = (p = buf) + len;
257
258     p += print_map(ns->roles, "roles", p, e-p);
259     p += print_map(ns->binaries, "binaries", p, e-p);
260
261     return p - buf;
262 }
263
264 mir_node *pa_nodeset_iterate_nodes(struct userdata *u, uint32_t *pidx)
265 {
266     pa_nodeset *ns;
267     pa_idxset *idxset;
268     mir_node *node;
269
270     pa_assert(u);
271     pa_assert(pidx);
272     pa_assert_se((ns = u->nodeset));
273     pa_assert_se((idxset = ns->nodes));
274
275     if (*pidx == PA_IDXSET_INVALID)
276         node = pa_idxset_first(idxset, pidx);
277     else
278         node = pa_idxset_next(idxset, pidx);
279
280     return node;
281 }
282
283 mir_node *mir_node_create(struct userdata *u, mir_node *data)
284 {
285     pa_nodeset *ns;
286     mir_node *node;
287
288     pa_assert(u);
289     pa_assert(data);
290     pa_assert_se((ns = u->nodeset));
291     pa_assert(data->key);
292     pa_assert(data->paname);
293     
294     node = pa_xnew0(mir_node, 1);
295
296     pa_idxset_put(ns->nodes, node, &node->index);
297
298     node->key       = pa_xstrdup(data->key);
299     node->direction = data->direction;
300     node->implement = data->implement;
301     node->channels  = data->channels;
302     node->location  = data->location;
303     node->privacy   = data->privacy;
304     node->type      = data->type;
305     node->zone      = pa_xstrdup(data->zone);
306     node->visible   = data->visible;
307     node->available = data->available;
308     node->amname    = pa_xstrdup(data->amname ? data->amname : data->paname);
309     node->amdescr   = pa_xstrdup(data->amdescr ? data->amdescr : "");
310     node->amid      = data->amid;
311     node->paname    = pa_xstrdup(data->paname);
312     node->paidx     = data->paidx;
313     node->mux       = data->mux;
314     node->loop      = data->loop;
315     node->stamp     = data->stamp;
316     node->rsetid    = data->rsetid ? pa_xstrdup(data->rsetid) : NULL;
317     node->scripting = pa_scripting_node_create(u, node);
318     MIR_DLIST_INIT(node->rtentries);
319     MIR_DLIST_INIT(node->rtprilist);
320     MIR_DLIST_INIT(node->constrains);
321     
322     if (node->implement == mir_device) {
323         node->pacard.index = data->pacard.index;
324         if (data->pacard.profile)
325             node->pacard.profile = pa_xstrdup(data->pacard.profile);
326         if (data->paport)
327             node->paport = pa_xstrdup(data->paport);
328     }
329
330     mir_router_register_node(u, node);
331
332     return node;
333 }
334
335 void mir_node_destroy(struct userdata *u, mir_node *node)
336 {
337     pa_nodeset *ns;
338
339     pa_assert(u);
340     pa_assert_se((ns = u->nodeset));
341
342     if (node) {
343         if (node->implement == mir_stream) {
344             if (node->localrset)
345                 pa_murphyif_destroy_resource_set(u, node);
346             else
347                 pa_murphyif_delete_node(u, node);
348         }
349
350         mir_router_unregister_node(u, node);
351         pa_scripting_node_destroy(u, node);
352
353         pa_idxset_remove_by_index(ns->nodes, node->index);
354
355         pa_xfree(node->key);
356         pa_xfree(node->zone);
357         pa_xfree(node->amname);
358         pa_xfree(node->amdescr);
359         pa_xfree(node->paname);
360         pa_xfree(node->pacard.profile);
361         pa_xfree(node->paport);
362         pa_xfree(node->rsetid);
363
364         pa_xfree(node);
365     }
366 }
367
368 mir_node *mir_node_find_by_index(struct userdata *u, uint32_t nodidx)
369 {
370     pa_nodeset *ns;
371     mir_node *node;
372
373     pa_assert(u);
374     pa_assert_se((ns = u->nodeset));
375
376     node = pa_idxset_get_by_index(ns->nodes, nodidx);
377
378     return node;
379 }
380
381
382 int mir_node_print(mir_node *node, char *buf, int len)
383 {
384     char *p, *e;
385     char mux[256];
386     char loop[256];
387     char constr[512];
388
389     pa_assert(node);
390     pa_assert(buf);
391     pa_assert(len > 0);
392
393     pa_multiplex_print(node->mux, mux, sizeof(mux));
394     pa_loopback_print(node->loop, loop, sizeof(loop));
395     mir_constrain_print(node, constr, sizeof(constr));
396
397     e = (p = buf) + len;
398
399 #define PRINT(f,v) if (p < e) p += snprintf(p, e-p, f "\n", v)
400
401     PRINT("   index         : %u"  ,  node->index);
402     PRINT("   key           : '%s'",  node->key ? node->key : "");
403     PRINT("   direction     : %s"  ,  mir_direction_str(node->direction));
404     PRINT("   implement     : %s"  ,  mir_implement_str(node->implement));
405     PRINT("   channels      : %u"  ,  node->channels);
406     PRINT("   location      : %s"  ,  mir_location_str(node->location));
407     PRINT("   privacy       : %s"  ,  mir_privacy_str(node->privacy));
408     PRINT("   type          : %s"  ,  mir_node_type_str(node->type));
409     PRINT("   zone          : '%s'",  node->zone ? node->zone : "");
410     PRINT("   visible       : %s"  ,  node->visible ? "yes" : "no");
411     PRINT("   available     : %s"  ,  node->available ? "yes" : "no");
412     PRINT("   ignore        : %s"  ,  node->ignore ? "yes" : "no");
413     PRINT("   localrset     : %s"  ,  node->localrset ? "yes" : "no");
414     PRINT("   amname        : '%s'",  node->amname ? node->amname : "");
415     PRINT("   amdescr       : '%s'",  node->amdescr ? node->amdescr : "");
416     PRINT("   amid          : %u"  ,  node->amid);
417     PRINT("   paname        : '%s'",  node->paname ? node->paname : "");
418     PRINT("   paidx         : %u"  ,  node->paidx);
419     PRINT("   pacard.index  : %u"  ,  node->pacard.index);
420     PRINT("   pacard.profile: '%s'",  node->pacard.profile ?
421                                       node->pacard.profile : "");
422     PRINT("   paport        : '%s'",  node->paport ? node->paport : "");
423     PRINT("   mux           : %s"  ,  mux);
424     PRINT("   loop          : %s"  ,  loop);
425     PRINT("   constrain     : %s"  ,  constr);
426     PRINT("   rsetid        : '%s'",  node->rsetid ? node->rsetid : "");
427     PRINT("   stamp         : %u"  ,  node->stamp);
428
429 #undef PRINT
430
431     return p - buf;
432 }
433
434 const char *mir_direction_str(mir_direction direction)
435 {
436     switch (direction) {
437     case mir_direction_unknown:  return "unknown";
438     case mir_input:              return "input";
439     case mir_output:             return "output";
440     default:                     return "< ??? >";
441     }
442 }
443
444 const char *mir_implement_str(mir_implement implement)
445 {
446     switch (implement) {
447     case mir_implementation_unknown:  return "unknown";
448     case mir_device:                  return "device";
449     case mir_stream:                  return "stream";
450     default:                          return "< ??? >";
451     }
452 }
453
454 const char *mir_location_str(mir_location location)
455 {
456     switch (location) {
457     case mir_location_unknown:  return "unknown";
458     case mir_internal:          return "internal";
459     case mir_external:          return "external";
460     default:                    return "< ??? >";
461     }
462
463
464
465 const char *mir_node_type_str(mir_node_type type)
466 {
467     switch (type) {
468     case mir_node_type_unknown:   return "Unknown";
469     case mir_radio:               return "Radio";
470     case mir_player:              return "Player";
471     case mir_navigator:           return "Navigator";
472     case mir_game:                return "Game";
473     case mir_browser:             return "Browser";
474     case mir_camera:              return "Camera";
475     case mir_phone:               return "Phone";
476     case mir_alert:               return "Alert";
477     case mir_event:               return "Event";
478     case mir_system:              return "System";
479     case mir_speakers:            return "Speakers";
480     case mir_microphone:          return "Microphone";
481     case mir_jack:                return "Line";
482     case mir_spdif:               return "SPDIF";
483     case mir_hdmi:                return "HDMI";
484     case mir_wired_headset:       return "Wired Headset";
485     case mir_wired_headphone:     return "Wired Headphone";
486     case mir_usb_headset:         return "USB Headset";
487     case mir_bluetooth_sco:       return "Bluetooth Mono Handsfree";
488     case mir_bluetooth_carkit:    return "Car Kit";
489     case mir_bluetooth_a2dp:      return "Bluetooth Stereo Headphone";
490     case mir_bluetooth_source:    return "Bluetooth Source";
491     case mir_bluetooth_sink:      return "Bluetooth Sink";
492     default:                      return "<user defined>";
493     }
494 }
495
496
497 const char *mir_privacy_str(mir_privacy privacy)
498 {
499     switch (privacy) {
500     case mir_privacy_unknown:  return "<unknown>";
501     case mir_public:           return "public";
502     case mir_private:          return "private";
503     default:                   return "< ??? >";
504     }
505 }
506
507
508 static void free_map_cb(void *void_map)
509 {
510     pa_nodeset_map  *map = (pa_nodeset_map *)void_map;
511
512     pa_xfree((void *)map->name);
513     pa_xfree((void *)map->resdef);
514
515     pa_xfree(map);
516 }
517
518 static int print_map(pa_hashmap *map, const char *name, char *buf, int len)
519 {
520 #define PRINT(fmt,args...) \
521     do { if (p < e) p += snprintf(p, e-p, fmt "\n", args); } while (0)
522
523     pa_nodeset_map *m;
524     pa_nodeset_resdef *r;
525     const char *type;
526     void *state;
527     char *p, *e;
528
529     e = (p = buf) + len;
530
531     if (buf && len > 0) {
532         PRINT("%s mappings:", name);
533
534         PA_HASHMAP_FOREACH(m, map, state) {
535             type = mir_node_type_str(m->type);
536
537             if (!(r = m->resdef))
538                 PRINT("    %-15s => %-10s", m->name, type);
539             else {
540                 PRINT("    %-15s => %-10s resource: priority %u, flags rset "
541                       "0x%x, audio 0x%x", m->name, type, r->priority,
542                       r->flags.rset, r->flags.audio);
543             }
544         }
545     }
546     
547     return p - buf;
548
549 #undef PRINT
550 }
551                                   
552 /*
553  * Local Variables:
554  * c-basic-offset: 4
555  * indent-tabs-mode: nil
556  * End:
557  *
558  */