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