format: Simplify pa_format_info_to_sample_spec()
[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     pa_assert(f);
222     pa_assert(ss);
223
224     if (!pa_format_info_is_pcm(f))
225         return pa_format_info_to_sample_spec_fake(f, ss, map);
226
227     if (pa_format_info_get_sample_format(f, &ss->format) < 0)
228         return -PA_ERR_INVALID;
229     if (pa_format_info_get_rate(f, &ss->rate) < 0)
230         return -PA_ERR_INVALID;
231     if (pa_format_info_get_channels(f, &ss->channels) < 0)
232         return -PA_ERR_INVALID;
233     if (map && pa_format_info_get_channel_map(f, map) < 0)
234         return -PA_ERR_INVALID;
235
236     return 0;
237 }
238
239 pa_prop_type_t pa_format_info_get_prop_type(pa_format_info *f, const char *key) {
240     const char *str;
241     json_object *o, *o1;
242     pa_prop_type_t type;
243
244     pa_assert(f);
245     pa_assert(key);
246
247     str = pa_proplist_gets(f->plist, key);
248     if (!str)
249         return PA_PROP_TYPE_INVALID;
250
251     o = json_tokener_parse(str);
252     if (is_error(o))
253         return PA_PROP_TYPE_INVALID;
254
255     switch (json_object_get_type(o)) {
256         case json_type_int:
257             type = PA_PROP_TYPE_INT;
258             break;
259
260         case json_type_string:
261             type = PA_PROP_TYPE_STRING;
262             break;
263
264         case json_type_array:
265             if (json_object_array_length(o) == 0) {
266                 /* Unlikely, but let's account for this anyway. We need at
267                  * least one element to figure out the array type. */
268                 type = PA_PROP_TYPE_INVALID;
269                 break;
270             }
271
272             o1 = json_object_array_get_idx(o, 1);
273
274             if (json_object_get_type(o1) == json_type_int)
275                 type = PA_PROP_TYPE_INT_ARRAY;
276             else if (json_object_get_type(o1) == json_type_string)
277                 type = PA_PROP_TYPE_STRING_ARRAY;
278             else
279                 type = PA_PROP_TYPE_INVALID;
280
281             json_object_put(o1);
282             break;
283
284         case json_type_object:
285             /* We actually know at this point that it's a int range, but let's
286              * confirm. */
287             o1 = json_object_object_get(o, PA_JSON_MIN_KEY);
288             if (!o1) {
289                 type = PA_PROP_TYPE_INVALID;
290                 break;
291             }
292             json_object_put(o1);
293
294             o1 = json_object_object_get(o, PA_JSON_MAX_KEY);
295             if (!o1) {
296                 type = PA_PROP_TYPE_INVALID;
297                 break;
298             }
299             json_object_put(o1);
300
301             type = PA_PROP_TYPE_INT_RANGE;
302             break;
303
304         default:
305             type = PA_PROP_TYPE_INVALID;
306             break;
307     }
308
309     json_object_put(o);
310     return type;
311 }
312
313 int pa_format_info_get_prop_int(pa_format_info *f, const char *key, int *v) {
314     const char *str;
315     json_object *o;
316
317     pa_assert(f);
318     pa_assert(key);
319     pa_assert(v);
320
321     str = pa_proplist_gets(f->plist, key);
322     if (!str)
323         return -PA_ERR_NOENTITY;
324
325     o = json_tokener_parse(str);
326     if (is_error(o))
327         return -PA_ERR_INVALID;
328
329     if (json_object_get_type(o) != json_type_int) {
330         json_object_put(o);
331         return -PA_ERR_INVALID;
332     }
333
334     *v = json_object_get_int(o);
335     json_object_put(o);
336
337     return 0;
338 }
339
340 int pa_format_info_get_prop_int_range(pa_format_info *f, const char *key, int *min, int *max) {
341     const char *str;
342     json_object *o, *o1;
343     int ret = -PA_ERR_INVALID;
344
345     pa_assert(f);
346     pa_assert(key);
347     pa_assert(min);
348     pa_assert(max);
349
350     str = pa_proplist_gets(f->plist, key);
351     if (!str)
352         return -PA_ERR_NOENTITY;
353
354     o = json_tokener_parse(str);
355     if (is_error(o))
356         return -PA_ERR_INVALID;
357
358     if (json_object_get_type(o) != json_type_object)
359         goto out;
360
361     if (!(o1 = json_object_object_get(o, PA_JSON_MIN_KEY)))
362         goto out;
363
364     *min = json_object_get_int(o1);
365     json_object_put(o1);
366
367     if (!(o1 = json_object_object_get(o, PA_JSON_MAX_KEY)))
368         goto out;
369
370     *max = json_object_get_int(o1);
371     json_object_put(o1);
372
373     ret = 0;
374
375 out:
376     json_object_put(o);
377     return ret;
378 }
379
380 int pa_format_info_get_prop_int_array(pa_format_info *f, const char *key, int **values, int *n_values) {
381     const char *str;
382     json_object *o, *o1;
383     int i, ret = -PA_ERR_INVALID;
384
385     pa_assert(f);
386     pa_assert(key);
387     pa_assert(values);
388     pa_assert(n_values);
389
390     str = pa_proplist_gets(f->plist, key);
391     if (!str)
392         return -PA_ERR_NOENTITY;
393
394     o = json_tokener_parse(str);
395     if (is_error(o))
396         return -PA_ERR_INVALID;
397
398     if (json_object_get_type(o) != json_type_array)
399         goto out;
400
401     *n_values = json_object_array_length(o);
402     *values = pa_xnew(int, *n_values);
403
404     for (i = 0; i < *n_values; i++) {
405         o1 = json_object_array_get_idx(o, i);
406
407         if (json_object_get_type(o1) != json_type_int) {
408             json_object_put(o1);
409             goto out;
410         }
411
412         (*values)[i] = json_object_get_int(o1);
413         json_object_put(o1);
414     }
415
416     ret = 0;
417
418 out:
419     json_object_put(o);
420     return ret;
421 }
422
423 int pa_format_info_get_prop_string(pa_format_info *f, const char *key, char **v) {
424     const char *str = NULL;
425     json_object *o;
426
427     pa_assert(f);
428     pa_assert(key);
429     pa_assert(v);
430
431     str = pa_proplist_gets(f->plist, key);
432     if (!str)
433         return -PA_ERR_NOENTITY;
434
435     o = json_tokener_parse(str);
436     if (is_error(o))
437         return -PA_ERR_INVALID;
438
439     if (json_object_get_type(o) != json_type_string) {
440         json_object_put(o);
441         return -PA_ERR_INVALID;
442     }
443
444     *v = pa_xstrdup(json_object_get_string(o));
445     json_object_put(o);
446
447     return 0;
448 }
449
450 int pa_format_info_get_prop_string_array(pa_format_info *f, const char *key, char ***values, int *n_values) {
451     const char *str;
452     json_object *o, *o1;
453     int i, ret = -PA_ERR_INVALID;
454
455     pa_assert(f);
456     pa_assert(key);
457     pa_assert(values);
458     pa_assert(n_values);
459
460     str = pa_proplist_gets(f->plist, key);
461     if (!str)
462         return -PA_ERR_NOENTITY;
463
464     o = json_tokener_parse(str);
465     if (is_error(o))
466         return -PA_ERR_INVALID;
467
468     if (json_object_get_type(o) != json_type_array)
469         goto out;
470
471     *n_values = json_object_array_length(o);
472     *values = pa_xnew(char *, *n_values);
473
474     for (i = 0; i < *n_values; i++) {
475         o1 = json_object_array_get_idx(o, i);
476
477         if (json_object_get_type(o1) != json_type_string) {
478             json_object_put(o1);
479             goto out;
480         }
481
482         (*values)[i] = pa_xstrdup(json_object_get_string(o1));
483         json_object_put(o1);
484     }
485
486     ret = 0;
487
488 out:
489     json_object_put(o);
490     return ret;
491 }
492
493 void pa_format_info_free_string_array(char **values, int n_values) {
494     int i;
495
496     for (i = 0; i < n_values; i++)
497         pa_xfree(values[i]);
498
499     pa_xfree(values);
500 }
501
502 void pa_format_info_set_sample_format(pa_format_info *f, pa_sample_format_t sf) {
503     pa_format_info_set_prop_string(f, PA_PROP_FORMAT_SAMPLE_FORMAT, pa_sample_format_to_string(sf));
504 }
505
506 void pa_format_info_set_rate(pa_format_info *f, int rate) {
507     pa_format_info_set_prop_int(f, PA_PROP_FORMAT_RATE, rate);
508 }
509
510 void pa_format_info_set_channels(pa_format_info *f, int channels) {
511     pa_format_info_set_prop_int(f, PA_PROP_FORMAT_CHANNELS, channels);
512 }
513
514 void pa_format_info_set_channel_map(pa_format_info *f, const pa_channel_map *map) {
515     char map_str[PA_CHANNEL_MAP_SNPRINT_MAX];
516
517     pa_channel_map_snprint(map_str, sizeof(map_str), map);
518
519     pa_format_info_set_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, map_str);
520 }
521
522 void pa_format_info_set_prop_int(pa_format_info *f, const char *key, int value) {
523     json_object *o;
524
525     pa_assert(f);
526     pa_assert(key);
527
528     o = json_object_new_int(value);
529
530     pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
531
532     json_object_put(o);
533 }
534
535 void pa_format_info_set_prop_int_array(pa_format_info *f, const char *key, const int *values, int n_values) {
536     json_object *o;
537     int i;
538
539     pa_assert(f);
540     pa_assert(key);
541
542     o = json_object_new_array();
543
544     for (i = 0; i < n_values; i++)
545         json_object_array_add(o, json_object_new_int(values[i]));
546
547     pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
548
549     json_object_put(o);
550 }
551
552 void pa_format_info_set_prop_int_range(pa_format_info *f, const char *key, int min, int max) {
553     json_object *o;
554
555     pa_assert(f);
556     pa_assert(key);
557
558     o = json_object_new_object();
559
560     json_object_object_add(o, PA_JSON_MIN_KEY, json_object_new_int(min));
561     json_object_object_add(o, PA_JSON_MAX_KEY, json_object_new_int(max));
562
563     pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
564
565     json_object_put(o);
566 }
567
568 void pa_format_info_set_prop_string(pa_format_info *f, const char *key, const char *value) {
569     json_object *o;
570
571     pa_assert(f);
572     pa_assert(key);
573
574     o = json_object_new_string(value);
575
576     pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
577
578     json_object_put(o);
579 }
580
581 void pa_format_info_set_prop_string_array(pa_format_info *f, const char *key, const char **values, int n_values) {
582     json_object *o;
583     int i;
584
585     pa_assert(f);
586     pa_assert(key);
587
588     o = json_object_new_array();
589
590     for (i = 0; i < n_values; i++)
591         json_object_array_add(o, json_object_new_string(values[i]));
592
593     pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
594
595     json_object_put(o);
596 }
597
598 static bool pa_json_is_fixed_type(json_object *o) {
599     switch(json_object_get_type(o)) {
600         case json_type_object:
601         case json_type_array:
602             return false;
603
604         default:
605             return true;
606     }
607 }
608
609 static int pa_json_value_equal(json_object *o1, json_object *o2) {
610     return (json_object_get_type(o1) == json_object_get_type(o2)) &&
611         pa_streq(json_object_to_json_string(o1), json_object_to_json_string(o2));
612 }
613
614 static int pa_format_info_prop_compatible(const char *one, const char *two) {
615     json_object *o1 = NULL, *o2 = NULL;
616     int i, ret = 0;
617
618     o1 = json_tokener_parse(one);
619     if (is_error(o1))
620         goto out;
621
622     o2 = json_tokener_parse(two);
623     if (is_error(o2))
624         goto out;
625
626     /* We don't deal with both values being non-fixed - just because there is no immediate need (FIXME) */
627     pa_return_val_if_fail(pa_json_is_fixed_type(o1) || pa_json_is_fixed_type(o2), false);
628
629     if (pa_json_is_fixed_type(o1) && pa_json_is_fixed_type(o2)) {
630         ret = pa_json_value_equal(o1, o2);
631         goto out;
632     }
633
634     if (pa_json_is_fixed_type(o1)) {
635         json_object *tmp = o2;
636         o2 = o1;
637         o1 = tmp;
638     }
639
640     /* o2 is now a fixed type, and o1 is not */
641
642     if (json_object_get_type(o1) == json_type_array) {
643         for (i = 0; i < json_object_array_length(o1); i++) {
644             if (pa_json_value_equal(json_object_array_get_idx(o1, i), o2)) {
645                 ret = 1;
646                 break;
647             }
648         }
649     } else if (json_object_get_type(o1) == json_type_object) {
650         /* o1 should be a range type */
651         int min, max, v;
652         json_object *o_min = NULL, *o_max = NULL;
653
654         if (json_object_get_type(o2) != json_type_int) {
655             /* We don't support non-integer ranges */
656             goto out;
657         }
658
659         o_min = json_object_object_get(o1, PA_JSON_MIN_KEY);
660         if (!o_min || json_object_get_type(o_min) != json_type_int)
661             goto out;
662
663         o_max = json_object_object_get(o1, PA_JSON_MAX_KEY);
664         if (!o_max || json_object_get_type(o_max) != json_type_int)
665             goto out;
666
667         v = json_object_get_int(o2);
668         min = json_object_get_int(o_min);
669         max = json_object_get_int(o_max);
670
671         ret = v >= min && v <= max;
672     } else {
673         pa_log_warn("Got a format type that we don't support");
674     }
675
676 out:
677     if (o1)
678         json_object_put(o1);
679     if (o2)
680         json_object_put(o2);
681
682     return ret;
683 }