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, see <http://www.gnu.org/licenses/>.
28 #include <pulse/internal.h>
29 #include <pulse/xmalloc.h>
31 #include <pulsecore/core-format.h>
32 #include <pulsecore/core-util.h>
33 #include <pulsecore/i18n.h>
34 #include <pulsecore/macro.h>
38 #define PA_JSON_MIN_KEY "min"
39 #define PA_JSON_MAX_KEY "max"
41 static int pa_format_info_prop_compatible(const char *one, const char *two);
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",
53 const char *pa_encoding_to_string(pa_encoding_t e) {
54 if (e < 0 || e >= PA_ENCODING_MAX)
57 return _encoding_str_table[e];
60 pa_encoding_t pa_encoding_from_string(const char *encoding) {
63 for (e = PA_ENCODING_ANY; e < PA_ENCODING_MAX; e++)
64 if (pa_streq(_encoding_str_table[e], encoding))
67 return PA_ENCODING_INVALID;
70 pa_format_info* pa_format_info_new(void) {
71 pa_format_info *f = pa_xnew(pa_format_info, 1);
73 f->encoding = PA_ENCODING_INVALID;
74 f->plist = pa_proplist_new();
79 pa_format_info* pa_format_info_copy(const pa_format_info *src) {
84 dest = pa_xnew(pa_format_info, 1);
86 dest->encoding = src->encoding;
89 dest->plist = pa_proplist_copy(src->plist);
96 void pa_format_info_free(pa_format_info *f) {
99 pa_proplist_free(f->plist);
103 int pa_format_info_valid(const pa_format_info *f) {
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);
110 return (f->encoding >= 0 && f->encoding < PA_ENCODING_MAX && f->plist != NULL);
113 int pa_format_info_is_pcm(const pa_format_info *f) {
114 return f->encoding == PA_ENCODING_PCM;
117 char *pa_format_info_snprint(char *s, size_t l, const pa_format_info *f) {
126 if (!pa_format_info_valid(f))
127 pa_snprintf(s, l, _("(invalid)"));
129 tmp = pa_proplist_to_string_sep(f->plist, " ");
131 pa_snprintf(s, l, "%s, %s", pa_encoding_to_string(f->encoding), tmp);
133 pa_snprintf(s, l, "%s", pa_encoding_to_string(f->encoding));
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;
145 pos = strcspn(str, ",");
147 encoding = pa_xstrndup(str, pos);
148 f->encoding = pa_encoding_from_string(pa_strip(encoding));
149 if (f->encoding == PA_ENCODING_INVALID)
152 if (pos != strlen(str)) {
155 properties = pa_xstrdup(&str[pos+1]);
156 plist = pa_proplist_from_string(properties);
161 pa_proplist_free(f->plist);
169 pa_xfree(properties);
173 pa_format_info_free(f);
178 int pa_format_info_is_compatible(const pa_format_info *first, const pa_format_info *second) {
185 if (first->encoding != second->encoding)
188 while ((key = pa_proplist_iterate(first->plist, &state))) {
189 const char *value_one, *value_two;
191 value_one = pa_proplist_gets(first->plist, key);
192 value_two = pa_proplist_gets(second->plist, key);
194 if (!value_two || !pa_format_info_prop_compatible(value_one, value_two))
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];
205 pa_assert(ss && pa_sample_spec_valid(ss));
206 pa_assert(!map || pa_channel_map_valid(map));
208 f = pa_format_info_new();
209 f->encoding = PA_ENCODING_PCM;
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);
216 pa_channel_map_snprint(cm, sizeof(cm), map);
217 pa_format_info_set_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, cm);
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) {
228 if (!pa_format_info_is_pcm(f))
229 return pa_format_info_to_sample_spec_fake(f, ss, map);
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;
243 pa_prop_type_t pa_format_info_get_prop_type(const pa_format_info *f, const char *key) {
251 str = pa_proplist_gets(f->plist, key);
253 return PA_PROP_TYPE_INVALID;
255 o = json_tokener_parse(str);
257 return PA_PROP_TYPE_INVALID;
259 switch (json_object_get_type(o)) {
261 type = PA_PROP_TYPE_INT;
264 case json_type_string:
265 type = PA_PROP_TYPE_STRING;
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;
276 o1 = json_object_array_get_idx(o, 1);
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;
283 type = PA_PROP_TYPE_INVALID;
287 case json_type_object:
288 /* We actually know at this point that it's a int range, but let's
290 if (!json_object_object_get_ex(o, PA_JSON_MIN_KEY, NULL)) {
291 type = PA_PROP_TYPE_INVALID;
295 if (!json_object_object_get_ex(o, PA_JSON_MAX_KEY, NULL)) {
296 type = PA_PROP_TYPE_INVALID;
300 type = PA_PROP_TYPE_INT_RANGE;
304 type = PA_PROP_TYPE_INVALID;
312 int pa_format_info_get_prop_int(const pa_format_info *f, const char *key, int *v) {
320 str = pa_proplist_gets(f->plist, key);
322 return -PA_ERR_NOENTITY;
324 o = json_tokener_parse(str);
326 pa_log_debug("Failed to parse format info property '%s'.", key);
327 return -PA_ERR_INVALID;
330 if (json_object_get_type(o) != json_type_int) {
331 pa_log_debug("Format info property '%s' type is not int.", key);
333 return -PA_ERR_INVALID;
336 *v = json_object_get_int(o);
342 int pa_format_info_get_prop_int_range(const pa_format_info *f, const char *key, int *min, int *max) {
345 int ret = -PA_ERR_INVALID;
352 str = pa_proplist_gets(f->plist, key);
354 return -PA_ERR_NOENTITY;
356 o = json_tokener_parse(str);
358 pa_log_debug("Failed to parse format info property '%s'.", key);
359 return -PA_ERR_INVALID;
362 if (json_object_get_type(o) != json_type_object)
365 if (!json_object_object_get_ex(o, PA_JSON_MIN_KEY, &o1))
368 *min = json_object_get_int(o1);
370 if (!json_object_object_get_ex(o, PA_JSON_MAX_KEY, &o1))
373 *max = json_object_get_int(o1);
379 pa_log_debug("Format info property '%s' is not a valid int range.", key);
385 int pa_format_info_get_prop_int_array(const pa_format_info *f, const char *key, int **values, int *n_values) {
388 int i, ret = -PA_ERR_INVALID;
395 str = pa_proplist_gets(f->plist, key);
397 return -PA_ERR_NOENTITY;
399 o = json_tokener_parse(str);
401 pa_log_debug("Failed to parse format info property '%s'.", key);
402 return -PA_ERR_INVALID;
405 if (json_object_get_type(o) != json_type_array)
408 *n_values = json_object_array_length(o);
409 *values = pa_xnew(int, *n_values);
411 for (i = 0; i < *n_values; i++) {
412 o1 = json_object_array_get_idx(o, i);
414 if (json_object_get_type(o1) != json_type_int) {
418 (*values)[i] = json_object_get_int(o1);
425 pa_log_debug("Format info property '%s' is not a valid int array.", key);
431 int pa_format_info_get_prop_string(const pa_format_info *f, const char *key, char **v) {
432 const char *str = NULL;
439 str = pa_proplist_gets(f->plist, key);
441 return -PA_ERR_NOENTITY;
443 o = json_tokener_parse(str);
445 pa_log_debug("Failed to parse format info property '%s'.", key);
446 return -PA_ERR_INVALID;
449 if (json_object_get_type(o) != json_type_string) {
450 pa_log_debug("Format info property '%s' type is not string.", key);
452 return -PA_ERR_INVALID;
455 *v = pa_xstrdup(json_object_get_string(o));
461 int pa_format_info_get_prop_string_array(const pa_format_info *f, const char *key, char ***values, int *n_values) {
464 int i, ret = -PA_ERR_INVALID;
471 str = pa_proplist_gets(f->plist, key);
473 return -PA_ERR_NOENTITY;
475 o = json_tokener_parse(str);
477 pa_log_debug("Failed to parse format info property '%s'.", key);
478 return -PA_ERR_INVALID;
481 if (json_object_get_type(o) != json_type_array)
484 *n_values = json_object_array_length(o);
485 *values = pa_xnew(char *, *n_values);
487 for (i = 0; i < *n_values; i++) {
488 o1 = json_object_array_get_idx(o, i);
490 if (json_object_get_type(o1) != json_type_string) {
494 (*values)[i] = pa_xstrdup(json_object_get_string(o1));
501 pa_log_debug("Format info property '%s' is not a valid string array.", key);
507 void pa_format_info_free_string_array(char **values, int n_values) {
510 for (i = 0; i < n_values; i++)
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));
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);
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);
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];
531 pa_channel_map_snprint(map_str, sizeof(map_str), map);
533 pa_format_info_set_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, map_str);
536 void pa_format_info_set_prop_int(pa_format_info *f, const char *key, int value) {
542 o = json_object_new_int(value);
544 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
549 void pa_format_info_set_prop_int_array(pa_format_info *f, const char *key, const int *values, int n_values) {
556 o = json_object_new_array();
558 for (i = 0; i < n_values; i++)
559 json_object_array_add(o, json_object_new_int(values[i]));
561 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
566 void pa_format_info_set_prop_int_range(pa_format_info *f, const char *key, int min, int max) {
572 o = json_object_new_object();
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));
577 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
582 void pa_format_info_set_prop_string(pa_format_info *f, const char *key, const char *value) {
588 o = json_object_new_string(value);
590 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
595 void pa_format_info_set_prop_string_array(pa_format_info *f, const char *key, const char **values, int n_values) {
602 o = json_object_new_array();
604 for (i = 0; i < n_values; i++)
605 json_object_array_add(o, json_object_new_string(values[i]));
607 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
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:
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));
628 static int pa_format_info_prop_compatible(const char *one, const char *two) {
629 json_object *o1 = NULL, *o2 = NULL;
632 o1 = json_tokener_parse(one);
636 o2 = json_tokener_parse(two);
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);
643 if (pa_json_is_fixed_type(o1) && pa_json_is_fixed_type(o2)) {
644 ret = pa_json_value_equal(o1, o2);
648 if (pa_json_is_fixed_type(o1)) {
649 json_object *tmp = o2;
654 /* o2 is now a fixed type, and o1 is not */
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)) {
663 } else if (json_object_get_type(o1) == json_type_object) {
664 /* o1 should be a range type */
666 json_object *o_min = NULL, *o_max = NULL;
668 if (json_object_get_type(o2) != json_type_int) {
669 /* We don't support non-integer ranges */
673 if (!json_object_object_get_ex(o1, PA_JSON_MIN_KEY, &o_min) ||
674 json_object_get_type(o_min) != json_type_int)
677 if (!json_object_object_get_ex(o1, PA_JSON_MAX_KEY, &o_max) ||
678 json_object_get_type(o_max) != json_type_int)
681 v = json_object_get_int(o2);
682 min = json_object_get_int(o_min);
683 max = json_object_get_int(o_max);
685 ret = v >= min && v <= max;
687 pa_log_warn("Got a format type that we don't support");