2 This file is part of PulseAudio.
4 Copyright 2011 Intel Corporation
5 Copyright 2011 Collabora Multimedia
6 Copyright 2011 Arun Raghavan <arun.raghavan@collabora.co.uk>
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.
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.
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
30 #include <pulse/internal.h>
31 #include <pulse/xmalloc.h>
33 #include <pulsecore/core-format.h>
34 #include <pulsecore/core-util.h>
35 #include <pulsecore/i18n.h>
36 #include <pulsecore/macro.h>
40 #define PA_JSON_MIN_KEY "min"
41 #define PA_JSON_MAX_KEY "max"
43 static int pa_format_info_prop_compatible(const char *one, const char *two);
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",
55 const char *pa_encoding_to_string(pa_encoding_t e) {
56 if (e < 0 || e >= PA_ENCODING_MAX)
59 return _encoding_str_table[e];
62 pa_encoding_t pa_encoding_from_string(const char *encoding) {
65 for (e = PA_ENCODING_ANY; e < PA_ENCODING_MAX; e++)
66 if (pa_streq(_encoding_str_table[e], encoding))
69 return PA_ENCODING_INVALID;
72 pa_format_info* pa_format_info_new(void) {
73 pa_format_info *f = pa_xnew(pa_format_info, 1);
75 f->encoding = PA_ENCODING_INVALID;
76 f->plist = pa_proplist_new();
81 pa_format_info* pa_format_info_copy(const pa_format_info *src) {
86 dest = pa_xnew(pa_format_info, 1);
88 dest->encoding = src->encoding;
91 dest->plist = pa_proplist_copy(src->plist);
98 void pa_format_info_free(pa_format_info *f) {
101 pa_proplist_free(f->plist);
105 int pa_format_info_valid(const pa_format_info *f) {
106 return (f->encoding >= 0 && f->encoding < PA_ENCODING_MAX && f->plist != NULL);
109 int pa_format_info_is_pcm(const pa_format_info *f) {
110 return f->encoding == PA_ENCODING_PCM;
113 char *pa_format_info_snprint(char *s, size_t l, const pa_format_info *f) {
122 if (!pa_format_info_valid(f))
123 pa_snprintf(s, l, _("(invalid)"));
125 tmp = pa_proplist_to_string_sep(f->plist, " ");
127 pa_snprintf(s, l, "%s, %s", pa_encoding_to_string(f->encoding), tmp);
129 pa_snprintf(s, l, "%s", pa_encoding_to_string(f->encoding));
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;
141 pos = strcspn(str, ",");
143 encoding = pa_xstrndup(str, pos);
144 f->encoding = pa_encoding_from_string(pa_strip(encoding));
145 if (f->encoding == PA_ENCODING_INVALID)
148 if (pos != strlen(str)) {
151 properties = pa_xstrdup(&str[pos+1]);
152 plist = pa_proplist_from_string(properties);
157 pa_proplist_free(f->plist);
165 pa_xfree(properties);
169 pa_format_info_free(f);
174 int pa_format_info_is_compatible(pa_format_info *first, pa_format_info *second) {
181 if (first->encoding != second->encoding)
184 while ((key = pa_proplist_iterate(first->plist, &state))) {
185 const char *value_one, *value_two;
187 value_one = pa_proplist_gets(first->plist, key);
188 value_two = pa_proplist_gets(second->plist, key);
190 if (!value_two || !pa_format_info_prop_compatible(value_one, value_two))
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];
201 pa_assert(ss && pa_sample_spec_valid(ss));
202 pa_assert(!map || pa_channel_map_valid(map));
204 f = pa_format_info_new();
205 f->encoding = PA_ENCODING_PCM;
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);
212 pa_channel_map_snprint(cm, sizeof(cm), map);
213 pa_format_info_set_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, cm);
219 /* For PCM streams */
220 int pa_format_info_to_sample_spec(pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map) {
224 if (!pa_format_info_is_pcm(f))
225 return pa_format_info_to_sample_spec_fake(f, ss, map);
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;
239 pa_prop_type_t pa_format_info_get_prop_type(pa_format_info *f, const char *key) {
247 str = pa_proplist_gets(f->plist, key);
249 return PA_PROP_TYPE_INVALID;
251 o = json_tokener_parse(str);
253 return PA_PROP_TYPE_INVALID;
255 switch (json_object_get_type(o)) {
257 type = PA_PROP_TYPE_INT;
260 case json_type_string:
261 type = PA_PROP_TYPE_STRING;
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;
272 o1 = json_object_array_get_idx(o, 1);
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;
279 type = PA_PROP_TYPE_INVALID;
284 case json_type_object:
285 /* We actually know at this point that it's a int range, but let's
287 o1 = json_object_object_get(o, PA_JSON_MIN_KEY);
289 type = PA_PROP_TYPE_INVALID;
294 o1 = json_object_object_get(o, PA_JSON_MAX_KEY);
296 type = PA_PROP_TYPE_INVALID;
301 type = PA_PROP_TYPE_INT_RANGE;
305 type = PA_PROP_TYPE_INVALID;
313 int pa_format_info_get_prop_int(pa_format_info *f, const char *key, int *v) {
321 str = pa_proplist_gets(f->plist, key);
323 return -PA_ERR_NOENTITY;
325 o = json_tokener_parse(str);
327 return -PA_ERR_INVALID;
329 if (json_object_get_type(o) != json_type_int) {
331 return -PA_ERR_INVALID;
334 *v = json_object_get_int(o);
340 int pa_format_info_get_prop_int_range(pa_format_info *f, const char *key, int *min, int *max) {
343 int ret = -PA_ERR_INVALID;
350 str = pa_proplist_gets(f->plist, key);
352 return -PA_ERR_NOENTITY;
354 o = json_tokener_parse(str);
356 return -PA_ERR_INVALID;
358 if (json_object_get_type(o) != json_type_object)
361 if (!(o1 = json_object_object_get(o, PA_JSON_MIN_KEY)))
364 *min = json_object_get_int(o1);
367 if (!(o1 = json_object_object_get(o, PA_JSON_MAX_KEY)))
370 *max = json_object_get_int(o1);
380 int pa_format_info_get_prop_int_array(pa_format_info *f, const char *key, int **values, int *n_values) {
383 int i, ret = -PA_ERR_INVALID;
390 str = pa_proplist_gets(f->plist, key);
392 return -PA_ERR_NOENTITY;
394 o = json_tokener_parse(str);
396 return -PA_ERR_INVALID;
398 if (json_object_get_type(o) != json_type_array)
401 *n_values = json_object_array_length(o);
402 *values = pa_xnew(int, *n_values);
404 for (i = 0; i < *n_values; i++) {
405 o1 = json_object_array_get_idx(o, i);
407 if (json_object_get_type(o1) != json_type_int) {
412 (*values)[i] = json_object_get_int(o1);
423 int pa_format_info_get_prop_string(pa_format_info *f, const char *key, char **v) {
424 const char *str = NULL;
431 str = pa_proplist_gets(f->plist, key);
433 return -PA_ERR_NOENTITY;
435 o = json_tokener_parse(str);
437 return -PA_ERR_INVALID;
439 if (json_object_get_type(o) != json_type_string) {
441 return -PA_ERR_INVALID;
444 *v = pa_xstrdup(json_object_get_string(o));
450 int pa_format_info_get_prop_string_array(pa_format_info *f, const char *key, char ***values, int *n_values) {
453 int i, ret = -PA_ERR_INVALID;
460 str = pa_proplist_gets(f->plist, key);
462 return -PA_ERR_NOENTITY;
464 o = json_tokener_parse(str);
466 return -PA_ERR_INVALID;
468 if (json_object_get_type(o) != json_type_array)
471 *n_values = json_object_array_length(o);
472 *values = pa_xnew(char *, *n_values);
474 for (i = 0; i < *n_values; i++) {
475 o1 = json_object_array_get_idx(o, i);
477 if (json_object_get_type(o1) != json_type_string) {
482 (*values)[i] = pa_xstrdup(json_object_get_string(o1));
493 void pa_format_info_free_string_array(char **values, int n_values) {
496 for (i = 0; i < n_values; i++)
502 void pa_format_info_set_sample_format(pa_format_info *f, pa_sample_format_t sf) {
503 pa_format_info_set_prop_string(f, PA_PROP_FORMAT_SAMPLE_FORMAT, pa_sample_format_to_string(sf));
506 void pa_format_info_set_rate(pa_format_info *f, int rate) {
507 pa_format_info_set_prop_int(f, PA_PROP_FORMAT_RATE, rate);
510 void pa_format_info_set_channels(pa_format_info *f, int channels) {
511 pa_format_info_set_prop_int(f, PA_PROP_FORMAT_CHANNELS, channels);
514 void pa_format_info_set_channel_map(pa_format_info *f, const pa_channel_map *map) {
515 char map_str[PA_CHANNEL_MAP_SNPRINT_MAX];
517 pa_channel_map_snprint(map_str, sizeof(map_str), map);
519 pa_format_info_set_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, map_str);
522 void pa_format_info_set_prop_int(pa_format_info *f, const char *key, int value) {
528 o = json_object_new_int(value);
530 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
535 void pa_format_info_set_prop_int_array(pa_format_info *f, const char *key, const int *values, int n_values) {
542 o = json_object_new_array();
544 for (i = 0; i < n_values; i++)
545 json_object_array_add(o, json_object_new_int(values[i]));
547 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
552 void pa_format_info_set_prop_int_range(pa_format_info *f, const char *key, int min, int max) {
558 o = json_object_new_object();
560 json_object_object_add(o, PA_JSON_MIN_KEY, json_object_new_int(min));
561 json_object_object_add(o, PA_JSON_MAX_KEY, json_object_new_int(max));
563 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
568 void pa_format_info_set_prop_string(pa_format_info *f, const char *key, const char *value) {
574 o = json_object_new_string(value);
576 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
581 void pa_format_info_set_prop_string_array(pa_format_info *f, const char *key, const char **values, int n_values) {
588 o = json_object_new_array();
590 for (i = 0; i < n_values; i++)
591 json_object_array_add(o, json_object_new_string(values[i]));
593 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
598 static bool pa_json_is_fixed_type(json_object *o) {
599 switch(json_object_get_type(o)) {
600 case json_type_object:
601 case json_type_array:
609 static int pa_json_value_equal(json_object *o1, json_object *o2) {
610 return (json_object_get_type(o1) == json_object_get_type(o2)) &&
611 pa_streq(json_object_to_json_string(o1), json_object_to_json_string(o2));
614 static int pa_format_info_prop_compatible(const char *one, const char *two) {
615 json_object *o1 = NULL, *o2 = NULL;
618 o1 = json_tokener_parse(one);
622 o2 = json_tokener_parse(two);
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);
629 if (pa_json_is_fixed_type(o1) && pa_json_is_fixed_type(o2)) {
630 ret = pa_json_value_equal(o1, o2);
634 if (pa_json_is_fixed_type(o1)) {
635 json_object *tmp = o2;
640 /* o2 is now a fixed type, and o1 is not */
642 if (json_object_get_type(o1) == json_type_array) {
643 for (i = 0; i < json_object_array_length(o1); i++) {
644 if (pa_json_value_equal(json_object_array_get_idx(o1, i), o2)) {
649 } else if (json_object_get_type(o1) == json_type_object) {
650 /* o1 should be a range type */
652 json_object *o_min = NULL, *o_max = NULL;
654 if (json_object_get_type(o2) != json_type_int) {
655 /* We don't support non-integer ranges */
659 o_min = json_object_object_get(o1, PA_JSON_MIN_KEY);
660 if (!o_min || json_object_get_type(o_min) != json_type_int)
663 o_max = json_object_object_get(o1, PA_JSON_MAX_KEY);
664 if (!o_max || json_object_get_type(o_max) != json_type_int)
667 v = json_object_get_int(o2);
668 min = json_object_get_int(o_min);
669 max = json_object_get_int(o_max);
671 ret = v >= min && v <= max;
673 pa_log_warn("Got a format type that we don't support");