core-format: Add pa_format_info_get_channels()
[platform/upstream/pulseaudio.git] / src / pulse / format.c
1 /***
2   This file is part of PulseAudio.
3
4   Copyright 2011 Intel Corporation
5   Copyright 2011 Collabora Multimedia
6   Copyright 2011 Arun Raghavan <arun.raghavan@collabora.co.uk>
7
8   PulseAudio is free software; you can redistribute it and/or modify
9   it under the terms of the GNU Lesser General Public License as published
10   by the Free Software Foundation; either version 2.1 of the License,
11   or (at your option) any later version.
12
13   PulseAudio is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with PulseAudio; if not, write to the Free Software
20   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21   USA.
22 ***/
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <json.h>
29
30 #include <pulse/internal.h>
31 #include <pulse/xmalloc.h>
32
33 #include <pulsecore/core-format.h>
34 #include <pulsecore/core-util.h>
35 #include <pulsecore/i18n.h>
36 #include <pulsecore/macro.h>
37
38 #include "format.h"
39
40 #define PA_JSON_MIN_KEY "min"
41 #define PA_JSON_MAX_KEY "max"
42
43 static int pa_format_info_prop_compatible(const char *one, const char *two);
44
45 static const char* const _encoding_str_table[]= {
46     [PA_ENCODING_PCM] = "pcm",
47     [PA_ENCODING_AC3_IEC61937] = "ac3-iec61937",
48     [PA_ENCODING_EAC3_IEC61937] = "eac3-iec61937",
49     [PA_ENCODING_MPEG_IEC61937] = "mpeg-iec61937",
50     [PA_ENCODING_DTS_IEC61937] = "dts-iec61937",
51     [PA_ENCODING_MPEG2_AAC_IEC61937] = "mpeg2-aac-iec61937",
52     [PA_ENCODING_ANY] = "any",
53 };
54
55 const char *pa_encoding_to_string(pa_encoding_t e) {
56     if (e < 0 || e >= PA_ENCODING_MAX)
57         return NULL;
58
59     return _encoding_str_table[e];
60 }
61
62 pa_encoding_t pa_encoding_from_string(const char *encoding) {
63     pa_encoding_t e;
64
65     for (e = PA_ENCODING_ANY; e < PA_ENCODING_MAX; e++)
66         if (pa_streq(_encoding_str_table[e], encoding))
67             return e;
68
69     return PA_ENCODING_INVALID;
70 }
71
72 pa_format_info* pa_format_info_new(void) {
73     pa_format_info *f = pa_xnew(pa_format_info, 1);
74
75     f->encoding = PA_ENCODING_INVALID;
76     f->plist = pa_proplist_new();
77
78     return f;
79 }
80
81 pa_format_info* pa_format_info_copy(const pa_format_info *src) {
82     pa_format_info *dest;
83
84     pa_assert(src);
85
86     dest = pa_xnew(pa_format_info, 1);
87
88     dest->encoding = src->encoding;
89
90     if (src->plist)
91         dest->plist = pa_proplist_copy(src->plist);
92     else
93         dest->plist = NULL;
94
95     return dest;
96 }
97
98 void pa_format_info_free(pa_format_info *f) {
99     pa_assert(f);
100
101     pa_proplist_free(f->plist);
102     pa_xfree(f);
103 }
104
105 int pa_format_info_valid(const pa_format_info *f) {
106     return (f->encoding >= 0 && f->encoding < PA_ENCODING_MAX && f->plist != NULL);
107 }
108
109 int pa_format_info_is_pcm(const pa_format_info *f) {
110     return f->encoding == PA_ENCODING_PCM;
111 }
112
113 char *pa_format_info_snprint(char *s, size_t l, const pa_format_info *f) {
114     char *tmp;
115
116     pa_assert(s);
117     pa_assert(l > 0);
118     pa_assert(f);
119
120     pa_init_i18n();
121
122     if (!pa_format_info_valid(f))
123         pa_snprintf(s, l, _("(invalid)"));
124     else {
125         tmp = pa_proplist_to_string_sep(f->plist, "  ");
126         if (tmp[0])
127             pa_snprintf(s, l, "%s, %s", pa_encoding_to_string(f->encoding), tmp);
128         else
129             pa_snprintf(s, l, "%s", pa_encoding_to_string(f->encoding));
130         pa_xfree(tmp);
131     }
132
133     return s;
134 }
135
136 pa_format_info* pa_format_info_from_string(const char *str) {
137     pa_format_info *f = pa_format_info_new();
138     char *encoding = NULL, *properties = NULL;
139     size_t pos;
140
141     pos = strcspn(str, ",");
142
143     encoding = pa_xstrndup(str, pos);
144     f->encoding = pa_encoding_from_string(pa_strip(encoding));
145     if (f->encoding == PA_ENCODING_INVALID)
146         goto error;
147
148     if (pos != strlen(str)) {
149         pa_proplist *plist;
150
151         properties = pa_xstrdup(&str[pos+1]);
152         plist = pa_proplist_from_string(properties);
153
154         if (!plist)
155             goto error;
156
157         pa_proplist_free(f->plist);
158         f->plist = plist;
159     }
160
161 out:
162     if (encoding)
163         pa_xfree(encoding);
164     if (properties)
165         pa_xfree(properties);
166     return f;
167
168 error:
169     pa_format_info_free(f);
170     f = NULL;
171     goto out;
172 }
173
174 int pa_format_info_is_compatible(pa_format_info *first, pa_format_info *second) {
175     const char *key;
176     void *state = NULL;
177
178     pa_assert(first);
179     pa_assert(second);
180
181     if (first->encoding != second->encoding)
182         return false;
183
184     while ((key = pa_proplist_iterate(first->plist, &state))) {
185         const char *value_one, *value_two;
186
187         value_one = pa_proplist_gets(first->plist, key);
188         value_two = pa_proplist_gets(second->plist, key);
189
190         if (!value_two || !pa_format_info_prop_compatible(value_one, value_two))
191             return false;
192     }
193
194     return true;
195 }
196
197 pa_format_info* pa_format_info_from_sample_spec(pa_sample_spec *ss, pa_channel_map *map) {
198     char cm[PA_CHANNEL_MAP_SNPRINT_MAX];
199     pa_format_info *f;
200
201     pa_assert(ss && pa_sample_spec_valid(ss));
202     pa_assert(!map || pa_channel_map_valid(map));
203
204     f = pa_format_info_new();
205     f->encoding = PA_ENCODING_PCM;
206
207     pa_format_info_set_sample_format(f, ss->format);
208     pa_format_info_set_rate(f, ss->rate);
209     pa_format_info_set_channels(f, ss->channels);
210
211     if (map) {
212         pa_channel_map_snprint(cm, sizeof(cm), map);
213         pa_format_info_set_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, cm);
214     }
215
216     return f;
217 }
218
219 /* For PCM streams */
220 int pa_format_info_to_sample_spec(pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map) {
221     char *m = NULL;
222     int ret = -PA_ERR_INVALID;
223
224     pa_assert(f);
225     pa_assert(ss);
226
227     if (!pa_format_info_is_pcm(f))
228         return pa_format_info_to_sample_spec_fake(f, ss, map);
229
230     if (pa_format_info_get_sample_format(f, &ss->format) < 0)
231         goto out;
232     if (pa_format_info_get_rate(f, &ss->rate) < 0)
233         goto out;
234     if (pa_format_info_get_channels(f, &ss->channels) < 0)
235         goto out;
236
237     if (map) {
238         pa_channel_map_init(map);
239
240         if (pa_format_info_get_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, &m) == 0)
241             if (pa_channel_map_parse(map, m) == NULL)
242                 goto out;
243     }
244
245     ret = 0;
246
247 out:
248     if (m)
249         pa_xfree(m);
250
251     return ret;
252 }
253
254 pa_prop_type_t pa_format_info_get_prop_type(pa_format_info *f, const char *key) {
255     const char *str;
256     json_object *o, *o1;
257     pa_prop_type_t type;
258
259     pa_assert(f);
260     pa_assert(key);
261
262     str = pa_proplist_gets(f->plist, key);
263     if (!str)
264         return PA_PROP_TYPE_INVALID;
265
266     o = json_tokener_parse(str);
267     if (is_error(o))
268         return PA_PROP_TYPE_INVALID;
269
270     switch (json_object_get_type(o)) {
271         case json_type_int:
272             type = PA_PROP_TYPE_INT;
273             break;
274
275         case json_type_string:
276             type = PA_PROP_TYPE_STRING;
277             break;
278
279         case json_type_array:
280             if (json_object_array_length(o) == 0) {
281                 /* Unlikely, but let's account for this anyway. We need at
282                  * least one element to figure out the array type. */
283                 type = PA_PROP_TYPE_INVALID;
284                 break;
285             }
286
287             o1 = json_object_array_get_idx(o, 1);
288
289             if (json_object_get_type(o1) == json_type_int)
290                 type = PA_PROP_TYPE_INT_ARRAY;
291             else if (json_object_get_type(o1) == json_type_string)
292                 type = PA_PROP_TYPE_STRING_ARRAY;
293             else
294                 type = PA_PROP_TYPE_INVALID;
295
296             json_object_put(o1);
297             break;
298
299         case json_type_object:
300             /* We actually know at this point that it's a int range, but let's
301              * confirm. */
302             o1 = json_object_object_get(o, PA_JSON_MIN_KEY);
303             if (!o1) {
304                 type = PA_PROP_TYPE_INVALID;
305                 break;
306             }
307             json_object_put(o1);
308
309             o1 = json_object_object_get(o, PA_JSON_MAX_KEY);
310             if (!o1) {
311                 type = PA_PROP_TYPE_INVALID;
312                 break;
313             }
314             json_object_put(o1);
315
316             type = PA_PROP_TYPE_INT_RANGE;
317             break;
318
319         default:
320             type = PA_PROP_TYPE_INVALID;
321             break;
322     }
323
324     json_object_put(o);
325     return type;
326 }
327
328 int pa_format_info_get_prop_int(pa_format_info *f, const char *key, int *v) {
329     const char *str;
330     json_object *o;
331
332     pa_assert(f);
333     pa_assert(key);
334     pa_assert(v);
335
336     str = pa_proplist_gets(f->plist, key);
337     if (!str)
338         return -PA_ERR_NOENTITY;
339
340     o = json_tokener_parse(str);
341     if (is_error(o))
342         return -PA_ERR_INVALID;
343
344     if (json_object_get_type(o) != json_type_int) {
345         json_object_put(o);
346         return -PA_ERR_INVALID;
347     }
348
349     *v = json_object_get_int(o);
350     json_object_put(o);
351
352     return 0;
353 }
354
355 int pa_format_info_get_prop_int_range(pa_format_info *f, const char *key, int *min, int *max) {
356     const char *str;
357     json_object *o, *o1;
358     int ret = -PA_ERR_INVALID;
359
360     pa_assert(f);
361     pa_assert(key);
362     pa_assert(min);
363     pa_assert(max);
364
365     str = pa_proplist_gets(f->plist, key);
366     if (!str)
367         return -PA_ERR_NOENTITY;
368
369     o = json_tokener_parse(str);
370     if (is_error(o))
371         return -PA_ERR_INVALID;
372
373     if (json_object_get_type(o) != json_type_object)
374         goto out;
375
376     if (!(o1 = json_object_object_get(o, PA_JSON_MIN_KEY)))
377         goto out;
378
379     *min = json_object_get_int(o1);
380     json_object_put(o1);
381
382     if (!(o1 = json_object_object_get(o, PA_JSON_MAX_KEY)))
383         goto out;
384
385     *max = json_object_get_int(o1);
386     json_object_put(o1);
387
388     ret = 0;
389
390 out:
391     json_object_put(o);
392     return ret;
393 }
394
395 int pa_format_info_get_prop_int_array(pa_format_info *f, const char *key, int **values, int *n_values) {
396     const char *str;
397     json_object *o, *o1;
398     int i, ret = -PA_ERR_INVALID;
399
400     pa_assert(f);
401     pa_assert(key);
402     pa_assert(values);
403     pa_assert(n_values);
404
405     str = pa_proplist_gets(f->plist, key);
406     if (!str)
407         return -PA_ERR_NOENTITY;
408
409     o = json_tokener_parse(str);
410     if (is_error(o))
411         return -PA_ERR_INVALID;
412
413     if (json_object_get_type(o) != json_type_array)
414         goto out;
415
416     *n_values = json_object_array_length(o);
417     *values = pa_xnew(int, *n_values);
418
419     for (i = 0; i < *n_values; i++) {
420         o1 = json_object_array_get_idx(o, i);
421
422         if (json_object_get_type(o1) != json_type_int) {
423             json_object_put(o1);
424             goto out;
425         }
426
427         (*values)[i] = json_object_get_int(o1);
428         json_object_put(o1);
429     }
430
431     ret = 0;
432
433 out:
434     json_object_put(o);
435     return ret;
436 }
437
438 int pa_format_info_get_prop_string(pa_format_info *f, const char *key, char **v) {
439     const char *str = NULL;
440     json_object *o;
441
442     pa_assert(f);
443     pa_assert(key);
444     pa_assert(v);
445
446     str = pa_proplist_gets(f->plist, key);
447     if (!str)
448         return -PA_ERR_NOENTITY;
449
450     o = json_tokener_parse(str);
451     if (is_error(o))
452         return -PA_ERR_INVALID;
453
454     if (json_object_get_type(o) != json_type_string) {
455         json_object_put(o);
456         return -PA_ERR_INVALID;
457     }
458
459     *v = pa_xstrdup(json_object_get_string(o));
460     json_object_put(o);
461
462     return 0;
463 }
464
465 int pa_format_info_get_prop_string_array(pa_format_info *f, const char *key, char ***values, int *n_values) {
466     const char *str;
467     json_object *o, *o1;
468     int i, ret = -PA_ERR_INVALID;
469
470     pa_assert(f);
471     pa_assert(key);
472     pa_assert(values);
473     pa_assert(n_values);
474
475     str = pa_proplist_gets(f->plist, key);
476     if (!str)
477         return -PA_ERR_NOENTITY;
478
479     o = json_tokener_parse(str);
480     if (is_error(o))
481         return -PA_ERR_INVALID;
482
483     if (json_object_get_type(o) != json_type_array)
484         goto out;
485
486     *n_values = json_object_array_length(o);
487     *values = pa_xnew(char *, *n_values);
488
489     for (i = 0; i < *n_values; i++) {
490         o1 = json_object_array_get_idx(o, i);
491
492         if (json_object_get_type(o1) != json_type_string) {
493             json_object_put(o1);
494             goto out;
495         }
496
497         (*values)[i] = pa_xstrdup(json_object_get_string(o1));
498         json_object_put(o1);
499     }
500
501     ret = 0;
502
503 out:
504     json_object_put(o);
505     return ret;
506 }
507
508 void pa_format_info_free_string_array(char **values, int n_values) {
509     int i;
510
511     for (i = 0; i < n_values; i++)
512         pa_xfree(values[i]);
513
514     pa_xfree(values);
515 }
516
517 void pa_format_info_set_sample_format(pa_format_info *f, pa_sample_format_t sf) {
518     pa_format_info_set_prop_string(f, PA_PROP_FORMAT_SAMPLE_FORMAT, pa_sample_format_to_string(sf));
519 }
520
521 void pa_format_info_set_rate(pa_format_info *f, int rate) {
522     pa_format_info_set_prop_int(f, PA_PROP_FORMAT_RATE, rate);
523 }
524
525 void pa_format_info_set_channels(pa_format_info *f, int channels) {
526     pa_format_info_set_prop_int(f, PA_PROP_FORMAT_CHANNELS, channels);
527 }
528
529 void pa_format_info_set_channel_map(pa_format_info *f, const pa_channel_map *map) {
530     char map_str[PA_CHANNEL_MAP_SNPRINT_MAX];
531
532     pa_channel_map_snprint(map_str, sizeof(map_str), map);
533
534     pa_format_info_set_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, map_str);
535 }
536
537 void pa_format_info_set_prop_int(pa_format_info *f, const char *key, int value) {
538     json_object *o;
539
540     pa_assert(f);
541     pa_assert(key);
542
543     o = json_object_new_int(value);
544
545     pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
546
547     json_object_put(o);
548 }
549
550 void pa_format_info_set_prop_int_array(pa_format_info *f, const char *key, const int *values, int n_values) {
551     json_object *o;
552     int i;
553
554     pa_assert(f);
555     pa_assert(key);
556
557     o = json_object_new_array();
558
559     for (i = 0; i < n_values; i++)
560         json_object_array_add(o, json_object_new_int(values[i]));
561
562     pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
563
564     json_object_put(o);
565 }
566
567 void pa_format_info_set_prop_int_range(pa_format_info *f, const char *key, int min, int max) {
568     json_object *o;
569
570     pa_assert(f);
571     pa_assert(key);
572
573     o = json_object_new_object();
574
575     json_object_object_add(o, PA_JSON_MIN_KEY, json_object_new_int(min));
576     json_object_object_add(o, PA_JSON_MAX_KEY, json_object_new_int(max));
577
578     pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
579
580     json_object_put(o);
581 }
582
583 void pa_format_info_set_prop_string(pa_format_info *f, const char *key, const char *value) {
584     json_object *o;
585
586     pa_assert(f);
587     pa_assert(key);
588
589     o = json_object_new_string(value);
590
591     pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
592
593     json_object_put(o);
594 }
595
596 void pa_format_info_set_prop_string_array(pa_format_info *f, const char *key, const char **values, int n_values) {
597     json_object *o;
598     int i;
599
600     pa_assert(f);
601     pa_assert(key);
602
603     o = json_object_new_array();
604
605     for (i = 0; i < n_values; i++)
606         json_object_array_add(o, json_object_new_string(values[i]));
607
608     pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
609
610     json_object_put(o);
611 }
612
613 static bool pa_json_is_fixed_type(json_object *o) {
614     switch(json_object_get_type(o)) {
615         case json_type_object:
616         case json_type_array:
617             return false;
618
619         default:
620             return true;
621     }
622 }
623
624 static int pa_json_value_equal(json_object *o1, json_object *o2) {
625     return (json_object_get_type(o1) == json_object_get_type(o2)) &&
626         pa_streq(json_object_to_json_string(o1), json_object_to_json_string(o2));
627 }
628
629 static int pa_format_info_prop_compatible(const char *one, const char *two) {
630     json_object *o1 = NULL, *o2 = NULL;
631     int i, ret = 0;
632
633     o1 = json_tokener_parse(one);
634     if (is_error(o1))
635         goto out;
636
637     o2 = json_tokener_parse(two);
638     if (is_error(o2))
639         goto out;
640
641     /* We don't deal with both values being non-fixed - just because there is no immediate need (FIXME) */
642     pa_return_val_if_fail(pa_json_is_fixed_type(o1) || pa_json_is_fixed_type(o2), false);
643
644     if (pa_json_is_fixed_type(o1) && pa_json_is_fixed_type(o2)) {
645         ret = pa_json_value_equal(o1, o2);
646         goto out;
647     }
648
649     if (pa_json_is_fixed_type(o1)) {
650         json_object *tmp = o2;
651         o2 = o1;
652         o1 = tmp;
653     }
654
655     /* o2 is now a fixed type, and o1 is not */
656
657     if (json_object_get_type(o1) == json_type_array) {
658         for (i = 0; i < json_object_array_length(o1); i++) {
659             if (pa_json_value_equal(json_object_array_get_idx(o1, i), o2)) {
660                 ret = 1;
661                 break;
662             }
663         }
664     } else if (json_object_get_type(o1) == json_type_object) {
665         /* o1 should be a range type */
666         int min, max, v;
667         json_object *o_min = NULL, *o_max = NULL;
668
669         if (json_object_get_type(o2) != json_type_int) {
670             /* We don't support non-integer ranges */
671             goto out;
672         }
673
674         o_min = json_object_object_get(o1, PA_JSON_MIN_KEY);
675         if (!o_min || json_object_get_type(o_min) != json_type_int)
676             goto out;
677
678         o_max = json_object_object_get(o1, PA_JSON_MAX_KEY);
679         if (!o_max || json_object_get_type(o_max) != json_type_int)
680             goto out;
681
682         v = json_object_get_int(o2);
683         min = json_object_get_int(o_min);
684         max = json_object_get_int(o_max);
685
686         ret = v >= min && v <= max;
687     } else {
688         pa_log_warn("Got a format type that we don't support");
689     }
690
691 out:
692     if (o1)
693         json_object_put(o1);
694     if (o2)
695         json_object_put(o2);
696
697     return ret;
698 }