pump up version number and update changelog
[profile/ivi/pulseaudio-module-murphy-ivi.git] / murphy / utils.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 <stdlib.h>
22 #include <sys/stat.h>
23 #include <stdio.h>
24 #include <errno.h>
25 #include <string.h>
26 #include <fcntl.h>
27 #include <unistd.h>
28 #include <limits.h>
29
30 #include <sys/types.h>
31 #include <sys/socket.h>
32
33 #include <pulsecore/pulsecore-config.h>
34
35 #include <pulsecore/core-util.h>
36 #include <pulsecore/sink.h>
37 #include <pulsecore/card.h>
38 #include <pulsecore/source.h>
39 #include <pulsecore/sink-input.h>
40 #include <pulsecore/source-output.h>
41
42 #include "userdata.h"
43 #include "utils.h"
44 #include "node.h"
45
46
47 #define DEFAULT_NULL_SINK_NAME "null.mir"
48
49 struct pa_null_sink {
50     char      *name;
51     uint32_t   module_index;
52     uint32_t   sink_index;
53 };
54
55
56 static uint32_t stamp;
57
58 static char *stream_name(pa_proplist *);
59 static bool get_unsigned_property(pa_proplist *, const char *,uint32_t *);
60
61
62 pa_null_sink *pa_utils_create_null_sink(struct userdata *u, const char *name)
63 {
64     pa_core      *core;
65     pa_module    *module;
66     pa_null_sink *ns;
67     pa_sink      *sink;
68     pa_sink      *s;
69     uint32_t      idx;
70     char          args[256];
71
72     pa_assert(u);
73     pa_assert_se((core = u->core));
74
75
76     if (!name)
77         name = DEFAULT_NULL_SINK_NAME;
78
79
80     snprintf(args, sizeof(args), "sink_name=\"%s\" channels=2", name);
81     module = pa_module_load(core, "module-null-sink", args);
82     sink = NULL;
83
84     if (!module)
85         pa_log("failed to load null sink '%s'", name);
86     else {
87         PA_IDXSET_FOREACH(s, core->sinks, idx) {
88             if (s->module && s->module == module) {
89                 sink = s;
90                 pa_log_info("mir null sink is '%s'", name);
91                 break;
92             }
93         }
94     }
95
96     ns = pa_xnew0(pa_null_sink, 1);
97     ns->name = pa_xstrdup(name);
98     ns->module_index = module ? module->index : PA_IDXSET_INVALID;
99     ns->sink_index = sink ? sink->index : PA_IDXSET_INVALID;
100
101     return ns;
102 }
103
104 void pa_utils_destroy_null_sink(struct userdata *u)
105 {
106     pa_core      *core;
107     pa_module    *module;
108     pa_null_sink *ns;
109
110     if (u && (ns = u->nullsink) && (core = u->core)) {
111         if ((module = pa_idxset_get_by_index(core->modules,ns->module_index))){
112             pa_log_info("unloading null sink '%s'", ns->name);
113             pa_module_unload(core, module, false);
114         }
115
116         pa_xfree(ns->name);
117         pa_xfree(ns);
118     }
119 }
120
121 pa_sink *pa_utils_get_null_sink(struct userdata *u)
122 {
123     pa_core *core;
124     pa_null_sink *ns;
125
126     pa_assert(u);
127     pa_assert_se((core = u->core));
128     pa_assert_se((ns = u->nullsink));
129
130     return pa_idxset_get_by_index(core->sinks, ns->sink_index);
131 }
132
133 pa_source *pa_utils_get_null_source(struct userdata *u)
134 {
135     pa_sink *ns = pa_utils_get_null_sink(u);
136
137     return ns ? ns->monitor_source : NULL;
138 }
139
140
141
142 const char *pa_utils_get_card_name(pa_card *card)
143 {
144     return (card && card->name) ? card->name : "<unknown>";
145 }
146
147 const char *pa_utils_get_card_bus(pa_card *card)
148 {
149     const char *bus = NULL;
150     const char *name;
151
152     if (card && !(bus = pa_proplist_gets(card->proplist,PA_PROP_DEVICE_BUS))) {
153         name = pa_utils_get_card_name(card);
154         if (!strncmp(name, "alsa_card.", 10)) {
155             if (!strncmp(name + 10, "pci-", 4))
156                 bus = "pci";
157             else if (!strncmp(name + 10, "platform-", 9))
158                 bus = "platform";
159             else if (!strncmp(name + 10, "usb-", 4))
160                 bus = "usb";
161         }
162     }
163
164     return (char *)bus;
165 }
166
167 const char *pa_utils_get_sink_name(pa_sink *sink)
168 {
169     return (sink && sink->name) ? sink->name : "<unknown>";
170 }
171
172 const char *pa_utils_get_source_name(pa_source *source)
173 {
174     return (source && source->name) ? source->name : "<unknown>";
175 }
176
177 const char *pa_utils_get_sink_input_name(pa_sink_input *sinp)
178 {
179     char *name;
180
181     if (sinp && sinp->proplist && (name = stream_name(sinp->proplist)))
182         return name;
183
184     return "<unknown>";
185 }
186
187 const char *pa_utils_get_sink_input_name_from_data(pa_sink_input_new_data *data)
188 {
189     char *name;
190
191     if (data && (name = stream_name(data->proplist)))
192         return name;
193
194     return "<unknown>";
195 }
196
197
198 const char *pa_utils_get_source_output_name(pa_source_output *sout)
199 {
200     char *name;
201
202     if (sout && sout->proplist && (name = stream_name(sout->proplist)))
203         return name;
204
205     return "<unknown>";
206 }
207
208 const char *pa_utils_get_source_output_name_from_data(pa_source_output_new_data*data)
209 {
210     char *name;
211
212     if (data && (name = stream_name(data->proplist)))
213         return name;
214
215     return "<unknown>";
216 }
217
218 char *pa_utils_get_zone(pa_proplist *pl, pa_proplist *client_props)
219 {
220     const char *zone;
221
222     pa_assert(pl);
223
224     if (!(zone = pa_proplist_gets(pl, PA_PROP_ZONE_NAME))) {
225         if (!client_props || !(zone = pa_proplist_gets(client_props, PA_PROP_ENV_ZONE)))
226             zone = PA_ZONE_NAME_DEFAULT;
227     }
228
229     return (char *)zone;
230 }
231
232
233 const char *pa_utils_get_appid(pa_proplist *pl)
234 {
235     const char *appid;
236
237     if (pl && (appid = pa_proplist_gets(pl, PA_PROP_RESOURCE_SET_APPID)))
238         return appid;
239
240     return "<unknown>";
241 }
242
243 bool pa_utils_set_stream_routing_properties(pa_proplist *pl,
244                                                  int          styp,
245                                                  void        *target)
246 {
247     const char    *clnam;
248     const char    *method;
249     char           clid[32];
250
251     pa_assert(pl);
252     pa_assert(styp >= 0);
253
254     snprintf(clid, sizeof(clid), "%d", styp);
255     clnam  = mir_node_type_str(styp);
256     method = target ? PA_ROUTING_EXPLICIT : PA_ROUTING_DEFAULT;
257
258     if (pa_proplist_sets(pl, PA_PROP_ROUTING_CLASS_NAME, clnam ) < 0 ||
259         pa_proplist_sets(pl, PA_PROP_ROUTING_CLASS_ID  , clid  ) < 0 ||
260         pa_proplist_sets(pl, PA_PROP_ROUTING_METHOD    , method) < 0  )
261     {
262         pa_log("failed to set some stream property");
263         return false;
264     }
265
266     return true;
267 }
268
269 bool pa_utils_unset_stream_routing_properties(pa_proplist *pl)
270 {
271     pa_assert(pl);
272
273     if (pa_proplist_unset(pl, PA_PROP_ROUTING_CLASS_NAME) < 0 ||
274         pa_proplist_unset(pl, PA_PROP_ROUTING_CLASS_ID  ) < 0 ||
275         pa_proplist_unset(pl, PA_PROP_ROUTING_METHOD    ) < 0  )
276     {
277         pa_log("failed to unset some stream property");
278         return false;
279     }
280
281     return true;
282 }
283
284 void pa_utils_set_stream_routing_method_property(pa_proplist *pl,
285                                                  bool explicit)
286 {
287     const char *method = explicit ? PA_ROUTING_EXPLICIT : PA_ROUTING_DEFAULT;
288
289     pa_assert(pl);
290
291     if (pa_proplist_sets(pl, PA_PROP_ROUTING_METHOD, method) < 0) {
292         pa_log("failed to set routing method property on sink-input");
293     }
294 }
295
296 bool pa_utils_stream_has_default_route(pa_proplist *pl)
297 {
298     const char *method;
299
300     pa_assert(pl);
301
302     method = pa_proplist_gets(pl, PA_PROP_ROUTING_METHOD);
303
304     if (method && pa_streq(method, PA_ROUTING_DEFAULT))
305         return true;
306
307     return false;
308 }
309
310 int pa_utils_get_stream_class(pa_proplist *pl)
311 {
312     const char *clid_str;
313     char *e;
314     unsigned long int clid = 0;
315
316     pa_assert(pl);
317
318     if ((clid_str = pa_proplist_gets(pl, PA_PROP_ROUTING_CLASS_ID))) {
319         clid = strtoul(clid_str, &e, 10);
320
321         if (*e)
322             clid = 0;
323     }
324
325     return (int)clid;
326 }
327
328
329
330 char *pa_utils_get_rsetid(pa_proplist *pl, char *buf, int length)
331 {
332     const char *prop;
333
334     if (buf && length >= 2) {
335         if ((prop = pa_proplist_gets(pl, PA_PROP_RESOURCE_SET_NAME))) {
336             snprintf(buf, (size_t)length, "#%s", prop);
337             return buf;
338         }
339
340         if ((prop = pa_proplist_gets(pl, PA_PROP_RESOURCE_SET_ID))) {
341             strncpy(buf, prop, (size_t)length);
342             buf[length-1] = '\0';
343             return buf;
344         }
345     }
346
347     return NULL;
348 }
349
350 bool pa_utils_set_resource_properties(pa_proplist *pl,
351                                            pa_nodeset_resdef *resdef)
352 {
353     char priority[32];
354     char rsetflags[32];
355     char audioflags[32];
356
357     pa_assert(pl);
358
359     if (!resdef)
360         return false;
361
362     snprintf(priority  , sizeof(priority)  , "%d", resdef->priority   );
363     snprintf(rsetflags , sizeof(rsetflags) , "%d", resdef->flags.rset );
364     snprintf(audioflags, sizeof(audioflags), "%d", resdef->flags.audio);
365
366     if (pa_proplist_sets(pl, PA_PROP_RESOURCE_PRIORITY   , priority  ) < 0 ||
367         pa_proplist_sets(pl, PA_PROP_RESOURCE_SET_FLAGS  , rsetflags ) < 0 ||
368         pa_proplist_sets(pl, PA_PROP_RESOURCE_AUDIO_FLAGS, audioflags) < 0  )
369     {
370         pa_log("failed to set some resource property");
371         return false;
372     }
373
374     return true;
375 }
376
377 bool pa_utils_unset_resource_properties(pa_proplist *pl)
378 {
379     pa_assert(pl);
380
381     if (pa_proplist_unset(pl, PA_PROP_RESOURCE_PRIORITY   ) < 0 ||
382         pa_proplist_unset(pl, PA_PROP_RESOURCE_SET_FLAGS  ) < 0 ||
383         pa_proplist_unset(pl, PA_PROP_RESOURCE_AUDIO_FLAGS) < 0  )
384     {
385         pa_log("failed to unset some resource property");
386         return false;
387     }
388
389     return true;
390 }
391
392 pa_nodeset_resdef *pa_utils_get_resource_properties(pa_proplist *pl,
393                                                     pa_nodeset_resdef *rd)
394 {
395     int success;
396
397     pa_assert(pl);
398     pa_assert(rd);
399
400     memset(rd, 0, sizeof(pa_nodeset_resdef));
401
402     success  = get_unsigned_property(pl, PA_PROP_RESOURCE_PRIORITY,
403                                      &rd->priority);
404     success |= get_unsigned_property(pl, PA_PROP_RESOURCE_SET_FLAGS,
405                                      &rd->flags.rset);
406     success |= get_unsigned_property(pl, PA_PROP_RESOURCE_AUDIO_FLAGS,
407                                      &rd->flags.audio);
408     
409     return success ? rd : NULL;
410 }
411
412
413 static bool get_unsigned_property(pa_proplist *pl,
414                                        const char *name,
415                                        uint32_t *value)
416 {
417     const char *str;
418     char *e;
419
420     pa_assert(pl);
421     pa_assert(name);
422     pa_assert(value);
423
424     if (!(str = pa_proplist_gets(pl, name))) {
425         *value = 0;
426         return false;
427     }
428
429     *value = strtoul(str, &e, 10);
430
431     if (e == str || *e) {
432         *value = 0;
433         return false;
434     }
435
436     return true;
437 }
438
439
440 void pa_utils_set_port_properties(pa_device_port *port, mir_node *node)
441 {
442     const char *profile;
443     char propnam[512];
444     char nodeidx[256];
445
446     pa_assert(port);
447     pa_assert(port->proplist);
448     pa_assert(node);
449     pa_assert_se((profile = node->pacard.profile));
450
451     snprintf(propnam, sizeof(propnam), "%s.%s", PA_PROP_NODE_INDEX, profile);
452     snprintf(nodeidx, sizeof(nodeidx), "%u", node->index);
453
454     pa_proplist_sets(port->proplist, propnam, nodeidx);
455 }
456
457
458 pa_sink_input *pa_utils_get_stream_origin(struct userdata *u, pa_sink_input *sinp)
459 {
460     pa_sink_input *origin = sinp;
461     pa_core *core;
462     pa_module *module;
463     pa_sink *sink;
464     pa_muxnode *mux;
465
466     pa_assert(u);
467     pa_assert(sinp);
468     pa_assert_se((core = u->core) == sinp->core);
469
470     if ((module = sinp->module) && !strcmp(module->name, "module-combine-sink")) {
471         if (!(mux = pa_multiplex_find_by_module(u->multiplex, module)) ||
472             !(sink = pa_idxset_get_by_index(core->sinks, mux->sink_index)) ||
473             !(origin = pa_idxset_first(sink->inputs, NULL)))
474         {
475             pa_log("failed to find origin for sink-input %u", sinp->index);
476         }
477     }
478
479     return origin;
480 }
481
482
483 mir_node *pa_utils_get_node_from_port(struct userdata *u,
484                                       pa_device_port *port,
485                                       void **state)
486 {
487     const char *name;
488     const char *value;
489     char *e;
490     uint32_t index = PA_IDXSET_INVALID;
491     mir_node *node = NULL;
492
493     pa_assert(u);
494     pa_assert(port);
495     pa_assert(port->proplist);
496
497     while ((name = pa_proplist_iterate(port->proplist, state))) {
498         if (!strncmp(name, PA_PROP_NODE_INDEX, sizeof(PA_PROP_NODE_INDEX)-1)) {
499             if ((value = pa_proplist_gets(port->proplist, name))) {
500                 index = strtoul(value, &e, 10);
501                 node = NULL;
502
503                 if (value[0] && !e[0])
504                     node = mir_node_find_by_index(u, index);
505                 
506                 if (node)
507                     return node;
508
509                 pa_log("Can't find node %u for port %s", index, port->name);
510             }
511         }
512     }
513
514     return NULL;
515 }
516
517 mir_node *pa_utils_get_node_from_stream(struct userdata *u,
518                                         mir_direction    type,
519                                         void            *ptr)
520 {
521     pa_sink_input    *sinp;
522     pa_source_output *sout;
523     pa_proplist      *pl;
524     mir_node         *node;
525     const char       *index_str;
526     uint32_t          index = PA_IDXSET_INVALID;
527     char             *e;
528     char              name[256];
529
530     pa_assert(u);
531     pa_assert(ptr);
532     pa_assert(type == mir_input || type == mir_output);
533
534     if (type == mir_input) {
535         sinp = (pa_sink_input *)ptr;
536         pl = sinp->proplist;
537         snprintf(name, sizeof(name), "sink-input.%u", sinp->index);
538     }
539     else {
540         sout = (pa_source_output *)ptr;
541         pl = sout->proplist;
542         snprintf(name, sizeof(name), "source-output.%u", sout->index);
543     }
544
545
546     if ((index_str = pa_proplist_gets(pl, PA_PROP_NODE_INDEX))) {
547         index = strtoul(index_str, &e, 10);
548         if (e != index_str && *e == '\0') {
549             if ((node = mir_node_find_by_index(u, index)))
550                 return node;
551
552             pa_log_debug("can't find find node for %s", name);
553         }
554     }
555
556     return NULL;
557 }
558
559 mir_node *pa_utils_get_node_from_data(struct userdata *u,
560                                       mir_direction    type,
561                                       void            *ptr)
562 {
563     pa_sink_input_new_data *sinp;
564     pa_source_output_new_data *sout;
565     pa_proplist  *pl;
566     mir_node     *node;
567     const char   *index_str;
568     uint32_t      index = PA_IDXSET_INVALID;
569     char         *e;
570     char          name[256];
571
572     pa_assert(u);
573     pa_assert(ptr);
574     pa_assert(type == mir_input || type == mir_output);
575
576     if (type == mir_input) {
577         sinp = (pa_sink_input_new_data *)ptr;
578         pl = sinp->proplist;
579         snprintf(name, sizeof(name), "sink-input");
580     }
581     else {
582         sout = (pa_source_output_new_data *)ptr;
583         pl = sout->proplist;
584         snprintf(name, sizeof(name), "source-output");
585     }
586
587
588     if ((index_str = pa_proplist_gets(pl, PA_PROP_NODE_INDEX))) {
589         index = strtoul(index_str, &e, 10);
590         if (e != index_str && *e == '\0') {
591             if ((node = mir_node_find_by_index(u, index)))
592                 return node;
593
594             pa_log_debug("can't find find node for %s", name);
595         }
596     }
597
598     return NULL;
599 }
600
601 static char *stream_name(pa_proplist *pl)
602 {
603     const char  *appnam;
604     const char  *binnam;
605
606     if ((appnam = pa_proplist_gets(pl, PA_PROP_APPLICATION_NAME)))
607         return (char *)appnam;
608
609     if ((binnam = pa_proplist_gets(pl, PA_PROP_APPLICATION_PROCESS_BINARY)))
610         return (char *)binnam;
611
612     return NULL;
613 }
614
615
616 const char *pa_utils_file_path(const char *dir, const char *file,
617                                char *buf, size_t len)
618 {
619     pa_assert(file);
620     pa_assert(buf);
621     pa_assert(len > 0);
622
623     snprintf(buf, len, "%s/%s", dir, file);
624
625     return buf;
626 }
627
628
629 uint32_t pa_utils_new_stamp(void)
630 {
631     return ++stamp;
632 }
633
634 uint32_t pa_utils_get_stamp(void)
635 {
636     return stamp;
637 }
638
639
640
641 /*
642  * Local Variables:
643  * c-basic-offset: 4
644  * indent-tabs-mode: nil
645  * End:
646  *
647  */
648
649