format: Drop dependency on json-c
[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, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <pulse/json.h>
27 #include <pulse/internal.h>
28 #include <pulse/xmalloc.h>
29
30 #include <pulsecore/core-format.h>
31 #include <pulsecore/core-util.h>
32 #include <pulsecore/i18n.h>
33 #include <pulsecore/macro.h>
34 #include <pulsecore/strbuf.h>
35
36 #include "format.h"
37
38 #define PA_JSON_MIN_KEY "min"
39 #define PA_JSON_MAX_KEY "max"
40
41 static int pa_format_info_prop_compatible(const char *one, const char *two);
42
43 static const char* const _encoding_str_table[]= {
44     [PA_ENCODING_PCM] = "pcm",
45     [PA_ENCODING_AC3_IEC61937] = "ac3-iec61937",
46     [PA_ENCODING_EAC3_IEC61937] = "eac3-iec61937",
47     [PA_ENCODING_MPEG_IEC61937] = "mpeg-iec61937",
48     [PA_ENCODING_DTS_IEC61937] = "dts-iec61937",
49     [PA_ENCODING_MPEG2_AAC_IEC61937] = "mpeg2-aac-iec61937",
50     [PA_ENCODING_ANY] = "any",
51 };
52
53 const char *pa_encoding_to_string(pa_encoding_t e) {
54     if (e < 0 || e >= PA_ENCODING_MAX)
55         return NULL;
56
57     return _encoding_str_table[e];
58 }
59
60 pa_encoding_t pa_encoding_from_string(const char *encoding) {
61     pa_encoding_t e;
62
63     for (e = PA_ENCODING_ANY; e < PA_ENCODING_MAX; e++)
64         if (pa_streq(_encoding_str_table[e], encoding))
65             return e;
66
67     return PA_ENCODING_INVALID;
68 }
69
70 pa_format_info* pa_format_info_new(void) {
71     pa_format_info *f = pa_xnew(pa_format_info, 1);
72
73     f->encoding = PA_ENCODING_INVALID;
74     f->plist = pa_proplist_new();
75
76     return f;
77 }
78
79 pa_format_info* pa_format_info_copy(const pa_format_info *src) {
80     pa_format_info *dest;
81
82     pa_assert(src);
83
84     dest = pa_xnew(pa_format_info, 1);
85
86     dest->encoding = src->encoding;
87
88     if (src->plist)
89         dest->plist = pa_proplist_copy(src->plist);
90     else
91         dest->plist = NULL;
92
93     return dest;
94 }
95
96 void pa_format_info_free(pa_format_info *f) {
97     pa_assert(f);
98
99     pa_proplist_free(f->plist);
100     pa_xfree(f);
101 }
102
103 int pa_format_info_valid(const pa_format_info *f) {
104     return (f->encoding >= 0 && f->encoding < PA_ENCODING_MAX && f->plist != NULL);
105 }
106
107 int pa_format_info_is_pcm(const pa_format_info *f) {
108     return f->encoding == PA_ENCODING_PCM;
109 }
110
111 char *pa_format_info_snprint(char *s, size_t l, const pa_format_info *f) {
112     char *tmp;
113
114     pa_assert(s);
115     pa_assert(l > 0);
116     pa_assert(f);
117
118     pa_init_i18n();
119
120     if (!pa_format_info_valid(f))
121         pa_snprintf(s, l, _("(invalid)"));
122     else {
123         tmp = pa_proplist_to_string_sep(f->plist, "  ");
124         if (tmp[0])
125             pa_snprintf(s, l, "%s, %s", pa_encoding_to_string(f->encoding), tmp);
126         else
127             pa_snprintf(s, l, "%s", pa_encoding_to_string(f->encoding));
128         pa_xfree(tmp);
129     }
130
131     return s;
132 }
133
134 pa_format_info* pa_format_info_from_string(const char *str) {
135     pa_format_info *f = pa_format_info_new();
136     char *encoding = NULL, *properties = NULL;
137     size_t pos;
138
139     pos = strcspn(str, ",");
140
141     encoding = pa_xstrndup(str, pos);
142     f->encoding = pa_encoding_from_string(pa_strip(encoding));
143     if (f->encoding == PA_ENCODING_INVALID)
144         goto error;
145
146     if (pos != strlen(str)) {
147         pa_proplist *plist;
148
149         properties = pa_xstrdup(&str[pos+1]);
150         plist = pa_proplist_from_string(properties);
151
152         if (!plist)
153             goto error;
154
155         pa_proplist_free(f->plist);
156         f->plist = plist;
157     }
158
159 out:
160     if (encoding)
161         pa_xfree(encoding);
162     if (properties)
163         pa_xfree(properties);
164     return f;
165
166 error:
167     pa_format_info_free(f);
168     f = NULL;
169     goto out;
170 }
171
172 int pa_format_info_is_compatible(const pa_format_info *first, const pa_format_info *second) {
173     const char *key;
174     void *state = NULL;
175
176     pa_assert(first);
177     pa_assert(second);
178
179     if (first->encoding != second->encoding)
180         return false;
181
182     while ((key = pa_proplist_iterate(first->plist, &state))) {
183         const char *value_one, *value_two;
184
185         value_one = pa_proplist_gets(first->plist, key);
186         value_two = pa_proplist_gets(second->plist, key);
187
188         if (!value_two || !pa_format_info_prop_compatible(value_one, value_two))
189             return false;
190     }
191
192     return true;
193 }
194
195 pa_format_info* pa_format_info_from_sample_spec(const pa_sample_spec *ss, const pa_channel_map *map) {
196     char cm[PA_CHANNEL_MAP_SNPRINT_MAX];
197     pa_format_info *f;
198
199     pa_assert(ss && pa_sample_spec_valid(ss));
200     pa_assert(!map || pa_channel_map_valid(map));
201
202     f = pa_format_info_new();
203     f->encoding = PA_ENCODING_PCM;
204
205     pa_format_info_set_sample_format(f, ss->format);
206     pa_format_info_set_rate(f, ss->rate);
207     pa_format_info_set_channels(f, ss->channels);
208
209     if (map) {
210         pa_channel_map_snprint(cm, sizeof(cm), map);
211         pa_format_info_set_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, cm);
212     }
213
214     return f;
215 }
216
217 /* For PCM streams */
218 int pa_format_info_to_sample_spec(const pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map) {
219     pa_assert(f);
220     pa_assert(ss);
221
222     if (!pa_format_info_is_pcm(f))
223         return pa_format_info_to_sample_spec_fake(f, ss, map);
224
225     if (pa_format_info_get_sample_format(f, &ss->format) < 0)
226         return -PA_ERR_INVALID;
227     if (pa_format_info_get_rate(f, &ss->rate) < 0)
228         return -PA_ERR_INVALID;
229     if (pa_format_info_get_channels(f, &ss->channels) < 0)
230         return -PA_ERR_INVALID;
231     if (map && pa_format_info_get_channel_map(f, map) < 0)
232         return -PA_ERR_INVALID;
233
234     return 0;
235 }
236
237 pa_prop_type_t pa_format_info_get_prop_type(const pa_format_info *f, const char *key) {
238     const char *str;
239     pa_json_object *o;
240     const pa_json_object *o1;
241     pa_prop_type_t type;
242
243     pa_assert(f);
244     pa_assert(key);
245
246     str = pa_proplist_gets(f->plist, key);
247     if (!str)
248         return PA_PROP_TYPE_INVALID;
249
250     o = pa_json_parse(str);
251     if (!o)
252         return PA_PROP_TYPE_INVALID;
253
254     switch (pa_json_object_get_type(o)) {
255         case PA_JSON_TYPE_INT:
256             type = PA_PROP_TYPE_INT;
257             break;
258
259         case PA_JSON_TYPE_STRING:
260             type = PA_PROP_TYPE_STRING;
261             break;
262
263         case PA_JSON_TYPE_ARRAY:
264             if (pa_json_object_get_array_length(o) == 0) {
265                 /* Unlikely, but let's account for this anyway. We need at
266                  * least one element to figure out the array type. */
267                 type = PA_PROP_TYPE_INVALID;
268                 break;
269             }
270
271             o1 = pa_json_object_get_array_member(o, 0);
272
273             if (pa_json_object_get_type(o1) == PA_JSON_TYPE_INT)
274                 type = PA_PROP_TYPE_INT_ARRAY;
275             else if (pa_json_object_get_type(o1) == PA_JSON_TYPE_STRING)
276                 type = PA_PROP_TYPE_STRING_ARRAY;
277             else
278                 type = PA_PROP_TYPE_INVALID;
279
280             break;
281
282         case PA_JSON_TYPE_OBJECT:
283             /* We actually know at this point that it's a int range, but let's
284              * confirm. */
285             if (!pa_json_object_get_object_member(o, PA_JSON_MIN_KEY)) {
286                 type = PA_PROP_TYPE_INVALID;
287                 break;
288             }
289
290             if (!pa_json_object_get_object_member(o, PA_JSON_MAX_KEY)) {
291                 type = PA_PROP_TYPE_INVALID;
292                 break;
293             }
294
295             type = PA_PROP_TYPE_INT_RANGE;
296             break;
297
298         default:
299             type = PA_PROP_TYPE_INVALID;
300             break;
301     }
302
303     pa_json_object_unref(o);
304     return type;
305 }
306
307 int pa_format_info_get_prop_int(const pa_format_info *f, const char *key, int *v) {
308     const char *str;
309     pa_json_object *o;
310
311     pa_assert(f);
312     pa_assert(key);
313     pa_assert(v);
314
315     str = pa_proplist_gets(f->plist, key);
316     if (!str)
317         return -PA_ERR_NOENTITY;
318
319     o = pa_json_parse(str);
320     if (!o) {
321         pa_log_debug("Failed to parse format info property '%s'.", key);
322         return -PA_ERR_INVALID;
323     }
324
325     if (pa_json_object_get_type(o) != PA_JSON_TYPE_INT) {
326         pa_log_debug("Format info property '%s' type is not int.", key);
327         pa_json_object_unref(o);
328         return -PA_ERR_INVALID;
329     }
330
331     *v = pa_json_object_get_int(o);
332     pa_json_object_unref(o);
333
334     return 0;
335 }
336
337 int pa_format_info_get_prop_int_range(const pa_format_info *f, const char *key, int *min, int *max) {
338     const char *str;
339     pa_json_object *o;
340     const pa_json_object *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 = pa_json_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 (pa_json_object_get_type(o) != PA_JSON_TYPE_OBJECT)
359         goto out;
360
361     if (!(o1 = pa_json_object_get_object_member(o, PA_JSON_MIN_KEY)) ||
362             (pa_json_object_get_type(o1) != PA_JSON_TYPE_INT))
363         goto out;
364
365     *min = pa_json_object_get_int(o1);
366
367     if (!(o1 = pa_json_object_get_object_member(o, PA_JSON_MAX_KEY)) ||
368             (pa_json_object_get_type(o1) != PA_JSON_TYPE_INT))
369         goto out;
370
371     *max = pa_json_object_get_int(o1);
372
373     ret = 0;
374
375 out:
376     if (ret < 0)
377         pa_log_debug("Format info property '%s' is not a valid int range.", key);
378
379     pa_json_object_unref(o);
380     return ret;
381 }
382
383 int pa_format_info_get_prop_int_array(const pa_format_info *f, const char *key, int **values, int *n_values) {
384     const char *str;
385     pa_json_object *o;
386     const pa_json_object *o1;
387     int i, ret = -PA_ERR_INVALID;
388
389     pa_assert(f);
390     pa_assert(key);
391     pa_assert(values);
392     pa_assert(n_values);
393
394     str = pa_proplist_gets(f->plist, key);
395     if (!str)
396         return -PA_ERR_NOENTITY;
397
398     o = pa_json_parse(str);
399     if (!o) {
400         pa_log_debug("Failed to parse format info property '%s'.", key);
401         return -PA_ERR_INVALID;
402     }
403
404     if (pa_json_object_get_type(o) != PA_JSON_TYPE_ARRAY)
405         goto out;
406
407     *n_values = pa_json_object_get_array_length(o);
408     *values = pa_xnew(int, *n_values);
409
410     for (i = 0; i < *n_values; i++) {
411         o1 = pa_json_object_get_array_member(o, i);
412
413         if (pa_json_object_get_type(o1) != PA_JSON_TYPE_INT) {
414             goto out;
415         }
416
417         (*values)[i] = pa_json_object_get_int(o1);
418     }
419
420     ret = 0;
421
422 out:
423     if (ret < 0)
424         pa_log_debug("Format info property '%s' is not a valid int array.", key);
425
426     pa_json_object_unref(o);
427     return ret;
428 }
429
430 int pa_format_info_get_prop_string(const pa_format_info *f, const char *key, char **v) {
431     const char *str = NULL;
432     pa_json_object *o;
433
434     pa_assert(f);
435     pa_assert(key);
436     pa_assert(v);
437
438     str = pa_proplist_gets(f->plist, key);
439     if (!str)
440         return -PA_ERR_NOENTITY;
441
442     o = pa_json_parse(str);
443     if (!o) {
444         pa_log_debug("Failed to parse format info property '%s'.", key);
445         return -PA_ERR_INVALID;
446     }
447
448     if (pa_json_object_get_type(o) != PA_JSON_TYPE_STRING) {
449         pa_log_debug("Format info property '%s' type is not string.", key);
450         pa_json_object_unref(o);
451         return -PA_ERR_INVALID;
452     }
453
454     *v = pa_xstrdup(pa_json_object_get_string(o));
455     pa_json_object_unref(o);
456
457     return 0;
458 }
459
460 int pa_format_info_get_prop_string_array(const pa_format_info *f, const char *key, char ***values, int *n_values) {
461     const char *str;
462     pa_json_object *o;
463     const pa_json_object *o1;
464     int i, ret = -PA_ERR_INVALID;
465
466     pa_assert(f);
467     pa_assert(key);
468     pa_assert(values);
469     pa_assert(n_values);
470
471     str = pa_proplist_gets(f->plist, key);
472     if (!str)
473         return -PA_ERR_NOENTITY;
474
475     o = pa_json_parse(str);
476     if (!o) {
477         pa_log_debug("Failed to parse format info property '%s'.", key);
478         return -PA_ERR_INVALID;
479     }
480
481     if (pa_json_object_get_type(o) != PA_JSON_TYPE_ARRAY)
482         goto out;
483
484     *n_values = pa_json_object_get_array_length(o);
485     *values = pa_xnew(char *, *n_values);
486
487     for (i = 0; i < *n_values; i++) {
488         o1 = pa_json_object_get_array_member(o, i);
489
490         if (pa_json_object_get_type(o1) != PA_JSON_TYPE_STRING) {
491             goto out;
492         }
493
494         (*values)[i] = pa_xstrdup(pa_json_object_get_string(o1));
495     }
496
497     ret = 0;
498
499 out:
500     if (ret < 0)
501         pa_log_debug("Format info property '%s' is not a valid string array.", key);
502
503     pa_json_object_unref(o);
504     return ret;
505 }
506
507 void pa_format_info_free_string_array(char **values, int n_values) {
508     int i;
509
510     for (i = 0; i < n_values; i++)
511         pa_xfree(values[i]);
512
513     pa_xfree(values);
514 }
515
516 void pa_format_info_set_sample_format(pa_format_info *f, pa_sample_format_t sf) {
517     pa_format_info_set_prop_string(f, PA_PROP_FORMAT_SAMPLE_FORMAT, pa_sample_format_to_string(sf));
518 }
519
520 void pa_format_info_set_rate(pa_format_info *f, int rate) {
521     pa_format_info_set_prop_int(f, PA_PROP_FORMAT_RATE, rate);
522 }
523
524 void pa_format_info_set_channels(pa_format_info *f, int channels) {
525     pa_format_info_set_prop_int(f, PA_PROP_FORMAT_CHANNELS, channels);
526 }
527
528 void pa_format_info_set_channel_map(pa_format_info *f, const pa_channel_map *map) {
529     char map_str[PA_CHANNEL_MAP_SNPRINT_MAX];
530
531     pa_channel_map_snprint(map_str, sizeof(map_str), map);
532
533     pa_format_info_set_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, map_str);
534 }
535
536 void pa_format_info_set_prop_int(pa_format_info *f, const char *key, int value) {
537     pa_assert(f);
538     pa_assert(key);
539
540     pa_proplist_setf(f->plist, key, "%d", value);
541 }
542
543 void pa_format_info_set_prop_int_array(pa_format_info *f, const char *key, const int *values, int n_values) {
544     pa_strbuf *buf;
545     char *str;
546     int i;
547
548     pa_assert(f);
549     pa_assert(key);
550     pa_assert(n_values > 0);
551
552     buf = pa_strbuf_new();
553
554     pa_strbuf_printf(buf, "[ %d", values[0]);
555
556     for (i = 1; i < n_values; i++)
557         pa_strbuf_printf(buf, ", %d", values[i]);
558
559     pa_strbuf_printf(buf, " ]");
560     str = pa_strbuf_to_string_free(buf);
561
562     pa_proplist_sets(f->plist, key, str);
563     pa_xfree (str);
564 }
565
566 void pa_format_info_set_prop_int_range(pa_format_info *f, const char *key, int min, int max) {
567     pa_assert(f);
568     pa_assert(key);
569
570     pa_proplist_setf(f->plist, key, "{ \"" PA_JSON_MIN_KEY "\": %d, \"" PA_JSON_MAX_KEY "\": %d }",
571             min, max);
572 }
573
574 void pa_format_info_set_prop_string(pa_format_info *f, const char *key, const char *value) {
575     pa_assert(f);
576     pa_assert(key);
577
578     pa_proplist_setf(f->plist, key, "\"%s\"", value);
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     pa_strbuf *buf;
583     char *str;
584     int i;
585
586     pa_assert(f);
587     pa_assert(key);
588
589     buf = pa_strbuf_new();
590
591     pa_strbuf_printf(buf, "[ \"%s\"", values[0]);
592
593     for (i = 1; i < n_values; i++)
594         pa_strbuf_printf(buf, ", \"%s\"", values[i]);
595
596     pa_strbuf_printf(buf, " ]");
597     str = pa_strbuf_to_string_free(buf);
598
599     pa_proplist_sets(f->plist, key, str);
600     pa_xfree (str);
601 }
602
603 static bool pa_json_is_fixed_type(pa_json_object *o) {
604     switch(pa_json_object_get_type(o)) {
605         case PA_JSON_TYPE_OBJECT:
606         case PA_JSON_TYPE_ARRAY:
607             return false;
608
609         default:
610             return true;
611     }
612 }
613
614 static int pa_format_info_prop_compatible(const char *one, const char *two) {
615     pa_json_object *o1 = NULL, *o2 = NULL;
616     int i, ret = 0;
617
618     o1 = pa_json_parse(one);
619     if (!o1)
620         goto out;
621
622     o2 = pa_json_parse(two);
623     if (!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_object_equal(o1, o2);
631         goto out;
632     }
633
634     if (pa_json_is_fixed_type(o1)) {
635         pa_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 (pa_json_object_get_type(o1) == PA_JSON_TYPE_ARRAY) {
643         for (i = 0; i < pa_json_object_get_array_length(o1); i++) {
644             if (pa_json_object_equal(pa_json_object_get_array_member(o1, i), o2)) {
645                 ret = 1;
646                 break;
647             }
648         }
649     } else if (pa_json_object_get_type(o1) == PA_JSON_TYPE_OBJECT) {
650         /* o1 should be a range type */
651         int min, max, v;
652         const pa_json_object *o_min = NULL, *o_max = NULL;
653
654         if (pa_json_object_get_type(o2) != PA_JSON_TYPE_INT) {
655             /* We don't support non-integer ranges */
656             goto out;
657         }
658
659         if (!(o_min = pa_json_object_get_object_member(o1, PA_JSON_MIN_KEY)) ||
660             pa_json_object_get_type(o_min) != PA_JSON_TYPE_INT)
661             goto out;
662
663         if (!(o_max = pa_json_object_get_object_member(o1, PA_JSON_MAX_KEY)) ||
664             pa_json_object_get_type(o_max) != PA_JSON_TYPE_INT)
665             goto out;
666
667         v = pa_json_object_get_int(o2);
668         min = pa_json_object_get_int(o_min);
669         max = pa_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         pa_json_object_unref(o1);
679     if (o2)
680         pa_json_object_unref(o2);
681
682     return ret;
683 }