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