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