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