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