format: Make pa_format_info_valid() stricter for PCM
[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 <json.h>
27
28 #include <pulse/internal.h>
29 #include <pulse/xmalloc.h>
30
31 #include <pulsecore/core-format.h>
32 #include <pulsecore/core-util.h>
33 #include <pulsecore/i18n.h>
34 #include <pulsecore/macro.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     pa_sample_spec ss;
105
106     if (pa_format_info_is_pcm(f)) {
107         pa_format_info_to_sample_spec(f, &ss, NULL);
108         return pa_sample_spec_valid(&ss);
109     } else
110         return (f->encoding >= 0 && f->encoding < PA_ENCODING_MAX && f->plist != NULL);
111 }
112
113 int pa_format_info_is_pcm(const pa_format_info *f) {
114     return f->encoding == PA_ENCODING_PCM;
115 }
116
117 char *pa_format_info_snprint(char *s, size_t l, const pa_format_info *f) {
118     char *tmp;
119
120     pa_assert(s);
121     pa_assert(l > 0);
122     pa_assert(f);
123
124     pa_init_i18n();
125
126     if (!pa_format_info_valid(f))
127         pa_snprintf(s, l, _("(invalid)"));
128     else {
129         tmp = pa_proplist_to_string_sep(f->plist, "  ");
130         if (tmp[0])
131             pa_snprintf(s, l, "%s, %s", pa_encoding_to_string(f->encoding), tmp);
132         else
133             pa_snprintf(s, l, "%s", pa_encoding_to_string(f->encoding));
134         pa_xfree(tmp);
135     }
136
137     return s;
138 }
139
140 pa_format_info* pa_format_info_from_string(const char *str) {
141     pa_format_info *f = pa_format_info_new();
142     char *encoding = NULL, *properties = NULL;
143     size_t pos;
144
145     pos = strcspn(str, ",");
146
147     encoding = pa_xstrndup(str, pos);
148     f->encoding = pa_encoding_from_string(pa_strip(encoding));
149     if (f->encoding == PA_ENCODING_INVALID)
150         goto error;
151
152     if (pos != strlen(str)) {
153         pa_proplist *plist;
154
155         properties = pa_xstrdup(&str[pos+1]);
156         plist = pa_proplist_from_string(properties);
157
158         if (!plist)
159             goto error;
160
161         pa_proplist_free(f->plist);
162         f->plist = plist;
163     }
164
165 out:
166     if (encoding)
167         pa_xfree(encoding);
168     if (properties)
169         pa_xfree(properties);
170     return f;
171
172 error:
173     pa_format_info_free(f);
174     f = NULL;
175     goto out;
176 }
177
178 int pa_format_info_is_compatible(const pa_format_info *first, const pa_format_info *second) {
179     const char *key;
180     void *state = NULL;
181
182     pa_assert(first);
183     pa_assert(second);
184
185     if (first->encoding != second->encoding)
186         return false;
187
188     while ((key = pa_proplist_iterate(first->plist, &state))) {
189         const char *value_one, *value_two;
190
191         value_one = pa_proplist_gets(first->plist, key);
192         value_two = pa_proplist_gets(second->plist, key);
193
194         if (!value_two || !pa_format_info_prop_compatible(value_one, value_two))
195             return false;
196     }
197
198     return true;
199 }
200
201 pa_format_info* pa_format_info_from_sample_spec(const pa_sample_spec *ss, const pa_channel_map *map) {
202     char cm[PA_CHANNEL_MAP_SNPRINT_MAX];
203     pa_format_info *f;
204
205     pa_assert(ss && pa_sample_spec_valid(ss));
206     pa_assert(!map || pa_channel_map_valid(map));
207
208     f = pa_format_info_new();
209     f->encoding = PA_ENCODING_PCM;
210
211     pa_format_info_set_sample_format(f, ss->format);
212     pa_format_info_set_rate(f, ss->rate);
213     pa_format_info_set_channels(f, ss->channels);
214
215     if (map) {
216         pa_channel_map_snprint(cm, sizeof(cm), map);
217         pa_format_info_set_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, cm);
218     }
219
220     return f;
221 }
222
223 /* For PCM streams */
224 int pa_format_info_to_sample_spec(const pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map) {
225     pa_assert(f);
226     pa_assert(ss);
227
228     if (!pa_format_info_is_pcm(f))
229         return pa_format_info_to_sample_spec_fake(f, ss, map);
230
231     if (pa_format_info_get_sample_format(f, &ss->format) < 0)
232         return -PA_ERR_INVALID;
233     if (pa_format_info_get_rate(f, &ss->rate) < 0)
234         return -PA_ERR_INVALID;
235     if (pa_format_info_get_channels(f, &ss->channels) < 0)
236         return -PA_ERR_INVALID;
237     if (map && pa_format_info_get_channel_map(f, map) < 0)
238         return -PA_ERR_INVALID;
239
240     return 0;
241 }
242
243 pa_prop_type_t pa_format_info_get_prop_type(const pa_format_info *f, const char *key) {
244     const char *str;
245     json_object *o, *o1;
246     pa_prop_type_t type;
247
248     pa_assert(f);
249     pa_assert(key);
250
251     str = pa_proplist_gets(f->plist, key);
252     if (!str)
253         return PA_PROP_TYPE_INVALID;
254
255     o = json_tokener_parse(str);
256     if (!o)
257         return PA_PROP_TYPE_INVALID;
258
259     switch (json_object_get_type(o)) {
260         case json_type_int:
261             type = PA_PROP_TYPE_INT;
262             break;
263
264         case json_type_string:
265             type = PA_PROP_TYPE_STRING;
266             break;
267
268         case json_type_array:
269             if (json_object_array_length(o) == 0) {
270                 /* Unlikely, but let's account for this anyway. We need at
271                  * least one element to figure out the array type. */
272                 type = PA_PROP_TYPE_INVALID;
273                 break;
274             }
275
276             o1 = json_object_array_get_idx(o, 1);
277
278             if (json_object_get_type(o1) == json_type_int)
279                 type = PA_PROP_TYPE_INT_ARRAY;
280             else if (json_object_get_type(o1) == json_type_string)
281                 type = PA_PROP_TYPE_STRING_ARRAY;
282             else
283                 type = PA_PROP_TYPE_INVALID;
284
285             break;
286
287         case json_type_object:
288             /* We actually know at this point that it's a int range, but let's
289              * confirm. */
290             if (!json_object_object_get_ex(o, PA_JSON_MIN_KEY, NULL)) {
291                 type = PA_PROP_TYPE_INVALID;
292                 break;
293             }
294
295             if (!json_object_object_get_ex(o, PA_JSON_MAX_KEY, NULL)) {
296                 type = PA_PROP_TYPE_INVALID;
297                 break;
298             }
299
300             type = PA_PROP_TYPE_INT_RANGE;
301             break;
302
303         default:
304             type = PA_PROP_TYPE_INVALID;
305             break;
306     }
307
308     json_object_put(o);
309     return type;
310 }
311
312 int pa_format_info_get_prop_int(const pa_format_info *f, const char *key, int *v) {
313     const char *str;
314     json_object *o;
315
316     pa_assert(f);
317     pa_assert(key);
318     pa_assert(v);
319
320     str = pa_proplist_gets(f->plist, key);
321     if (!str)
322         return -PA_ERR_NOENTITY;
323
324     o = json_tokener_parse(str);
325     if (!o) {
326         pa_log_debug("Failed to parse format info property '%s'.", key);
327         return -PA_ERR_INVALID;
328     }
329
330     if (json_object_get_type(o) != json_type_int) {
331         pa_log_debug("Format info property '%s' type is not int.", key);
332         json_object_put(o);
333         return -PA_ERR_INVALID;
334     }
335
336     *v = json_object_get_int(o);
337     json_object_put(o);
338
339     return 0;
340 }
341
342 int pa_format_info_get_prop_int_range(const pa_format_info *f, const char *key, int *min, int *max) {
343     const char *str;
344     json_object *o, *o1;
345     int ret = -PA_ERR_INVALID;
346
347     pa_assert(f);
348     pa_assert(key);
349     pa_assert(min);
350     pa_assert(max);
351
352     str = pa_proplist_gets(f->plist, key);
353     if (!str)
354         return -PA_ERR_NOENTITY;
355
356     o = json_tokener_parse(str);
357     if (!o) {
358         pa_log_debug("Failed to parse format info property '%s'.", key);
359         return -PA_ERR_INVALID;
360     }
361
362     if (json_object_get_type(o) != json_type_object)
363         goto out;
364
365     if (!json_object_object_get_ex(o, PA_JSON_MIN_KEY, &o1))
366         goto out;
367
368     *min = json_object_get_int(o1);
369
370     if (!json_object_object_get_ex(o, PA_JSON_MAX_KEY, &o1))
371         goto out;
372
373     *max = json_object_get_int(o1);
374
375     ret = 0;
376
377 out:
378     if (ret < 0)
379         pa_log_debug("Format info property '%s' is not a valid int range.", key);
380
381     json_object_put(o);
382     return ret;
383 }
384
385 int pa_format_info_get_prop_int_array(const pa_format_info *f, const char *key, int **values, int *n_values) {
386     const char *str;
387     json_object *o, *o1;
388     int i, ret = -PA_ERR_INVALID;
389
390     pa_assert(f);
391     pa_assert(key);
392     pa_assert(values);
393     pa_assert(n_values);
394
395     str = pa_proplist_gets(f->plist, key);
396     if (!str)
397         return -PA_ERR_NOENTITY;
398
399     o = json_tokener_parse(str);
400     if (!o) {
401         pa_log_debug("Failed to parse format info property '%s'.", key);
402         return -PA_ERR_INVALID;
403     }
404
405     if (json_object_get_type(o) != json_type_array)
406         goto out;
407
408     *n_values = json_object_array_length(o);
409     *values = pa_xnew(int, *n_values);
410
411     for (i = 0; i < *n_values; i++) {
412         o1 = json_object_array_get_idx(o, i);
413
414         if (json_object_get_type(o1) != json_type_int) {
415             goto out;
416         }
417
418         (*values)[i] = json_object_get_int(o1);
419     }
420
421     ret = 0;
422
423 out:
424     if (ret < 0)
425         pa_log_debug("Format info property '%s' is not a valid int array.", key);
426
427     json_object_put(o);
428     return ret;
429 }
430
431 int pa_format_info_get_prop_string(const pa_format_info *f, const char *key, char **v) {
432     const char *str = NULL;
433     json_object *o;
434
435     pa_assert(f);
436     pa_assert(key);
437     pa_assert(v);
438
439     str = pa_proplist_gets(f->plist, key);
440     if (!str)
441         return -PA_ERR_NOENTITY;
442
443     o = json_tokener_parse(str);
444     if (!o) {
445         pa_log_debug("Failed to parse format info property '%s'.", key);
446         return -PA_ERR_INVALID;
447     }
448
449     if (json_object_get_type(o) != json_type_string) {
450         pa_log_debug("Format info property '%s' type is not string.", key);
451         json_object_put(o);
452         return -PA_ERR_INVALID;
453     }
454
455     *v = pa_xstrdup(json_object_get_string(o));
456     json_object_put(o);
457
458     return 0;
459 }
460
461 int pa_format_info_get_prop_string_array(const pa_format_info *f, const char *key, char ***values, int *n_values) {
462     const char *str;
463     json_object *o, *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 = json_tokener_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 (json_object_get_type(o) != json_type_array)
482         goto out;
483
484     *n_values = json_object_array_length(o);
485     *values = pa_xnew(char *, *n_values);
486
487     for (i = 0; i < *n_values; i++) {
488         o1 = json_object_array_get_idx(o, i);
489
490         if (json_object_get_type(o1) != json_type_string) {
491             goto out;
492         }
493
494         (*values)[i] = pa_xstrdup(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     json_object_put(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     json_object *o;
538
539     pa_assert(f);
540     pa_assert(key);
541
542     o = json_object_new_int(value);
543
544     pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
545
546     json_object_put(o);
547 }
548
549 void pa_format_info_set_prop_int_array(pa_format_info *f, const char *key, const int *values, int n_values) {
550     json_object *o;
551     int i;
552
553     pa_assert(f);
554     pa_assert(key);
555
556     o = json_object_new_array();
557
558     for (i = 0; i < n_values; i++)
559         json_object_array_add(o, json_object_new_int(values[i]));
560
561     pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
562
563     json_object_put(o);
564 }
565
566 void pa_format_info_set_prop_int_range(pa_format_info *f, const char *key, int min, int max) {
567     json_object *o;
568
569     pa_assert(f);
570     pa_assert(key);
571
572     o = json_object_new_object();
573
574     json_object_object_add(o, PA_JSON_MIN_KEY, json_object_new_int(min));
575     json_object_object_add(o, PA_JSON_MAX_KEY, json_object_new_int(max));
576
577     pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
578
579     json_object_put(o);
580 }
581
582 void pa_format_info_set_prop_string(pa_format_info *f, const char *key, const char *value) {
583     json_object *o;
584
585     pa_assert(f);
586     pa_assert(key);
587
588     o = json_object_new_string(value);
589
590     pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
591
592     json_object_put(o);
593 }
594
595 void pa_format_info_set_prop_string_array(pa_format_info *f, const char *key, const char **values, int n_values) {
596     json_object *o;
597     int i;
598
599     pa_assert(f);
600     pa_assert(key);
601
602     o = json_object_new_array();
603
604     for (i = 0; i < n_values; i++)
605         json_object_array_add(o, json_object_new_string(values[i]));
606
607     pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
608
609     json_object_put(o);
610 }
611
612 static bool pa_json_is_fixed_type(json_object *o) {
613     switch(json_object_get_type(o)) {
614         case json_type_object:
615         case json_type_array:
616             return false;
617
618         default:
619             return true;
620     }
621 }
622
623 static int pa_json_value_equal(json_object *o1, json_object *o2) {
624     return (json_object_get_type(o1) == json_object_get_type(o2)) &&
625         pa_streq(json_object_to_json_string(o1), json_object_to_json_string(o2));
626 }
627
628 static int pa_format_info_prop_compatible(const char *one, const char *two) {
629     json_object *o1 = NULL, *o2 = NULL;
630     int i, ret = 0;
631
632     o1 = json_tokener_parse(one);
633     if (!o1)
634         goto out;
635
636     o2 = json_tokener_parse(two);
637     if (!o2)
638         goto out;
639
640     /* We don't deal with both values being non-fixed - just because there is no immediate need (FIXME) */
641     pa_return_val_if_fail(pa_json_is_fixed_type(o1) || pa_json_is_fixed_type(o2), false);
642
643     if (pa_json_is_fixed_type(o1) && pa_json_is_fixed_type(o2)) {
644         ret = pa_json_value_equal(o1, o2);
645         goto out;
646     }
647
648     if (pa_json_is_fixed_type(o1)) {
649         json_object *tmp = o2;
650         o2 = o1;
651         o1 = tmp;
652     }
653
654     /* o2 is now a fixed type, and o1 is not */
655
656     if (json_object_get_type(o1) == json_type_array) {
657         for (i = 0; i < json_object_array_length(o1); i++) {
658             if (pa_json_value_equal(json_object_array_get_idx(o1, i), o2)) {
659                 ret = 1;
660                 break;
661             }
662         }
663     } else if (json_object_get_type(o1) == json_type_object) {
664         /* o1 should be a range type */
665         int min, max, v;
666         json_object *o_min = NULL, *o_max = NULL;
667
668         if (json_object_get_type(o2) != json_type_int) {
669             /* We don't support non-integer ranges */
670             goto out;
671         }
672
673         if (!json_object_object_get_ex(o1, PA_JSON_MIN_KEY, &o_min) ||
674             json_object_get_type(o_min) != json_type_int)
675             goto out;
676
677         if (!json_object_object_get_ex(o1, PA_JSON_MAX_KEY, &o_max) ||
678             json_object_get_type(o_max) != json_type_int)
679             goto out;
680
681         v = json_object_get_int(o2);
682         min = json_object_get_int(o_min);
683         max = json_object_get_int(o_max);
684
685         ret = v >= min && v <= max;
686     } else {
687         pa_log_warn("Got a format type that we don't support");
688     }
689
690 out:
691     if (o1)
692         json_object_put(o1);
693     if (o2)
694         json_object_put(o2);
695
696     return ret;
697 }