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) {
222 int ret = -PA_ERR_INVALID;
227 if (!pa_format_info_is_pcm(f))
228 return pa_format_info_to_sample_spec_fake(f, ss, map);
230 if (pa_format_info_get_sample_format(f, &ss->format) < 0)
232 if (pa_format_info_get_rate(f, &ss->rate) < 0)
234 if (pa_format_info_get_channels(f, &ss->channels) < 0)
238 pa_channel_map_init(map);
240 if (pa_format_info_get_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, &m) == 0)
241 if (pa_channel_map_parse(map, m) == NULL)
254 pa_prop_type_t pa_format_info_get_prop_type(pa_format_info *f, const char *key) {
262 str = pa_proplist_gets(f->plist, key);
264 return PA_PROP_TYPE_INVALID;
266 o = json_tokener_parse(str);
268 return PA_PROP_TYPE_INVALID;
270 switch (json_object_get_type(o)) {
272 type = PA_PROP_TYPE_INT;
275 case json_type_string:
276 type = PA_PROP_TYPE_STRING;
279 case json_type_array:
280 if (json_object_array_length(o) == 0) {
281 /* Unlikely, but let's account for this anyway. We need at
282 * least one element to figure out the array type. */
283 type = PA_PROP_TYPE_INVALID;
287 o1 = json_object_array_get_idx(o, 1);
289 if (json_object_get_type(o1) == json_type_int)
290 type = PA_PROP_TYPE_INT_ARRAY;
291 else if (json_object_get_type(o1) == json_type_string)
292 type = PA_PROP_TYPE_STRING_ARRAY;
294 type = PA_PROP_TYPE_INVALID;
299 case json_type_object:
300 /* We actually know at this point that it's a int range, but let's
302 o1 = json_object_object_get(o, PA_JSON_MIN_KEY);
304 type = PA_PROP_TYPE_INVALID;
309 o1 = json_object_object_get(o, PA_JSON_MAX_KEY);
311 type = PA_PROP_TYPE_INVALID;
316 type = PA_PROP_TYPE_INT_RANGE;
320 type = PA_PROP_TYPE_INVALID;
328 int pa_format_info_get_prop_int(pa_format_info *f, const char *key, int *v) {
336 str = pa_proplist_gets(f->plist, key);
338 return -PA_ERR_NOENTITY;
340 o = json_tokener_parse(str);
342 return -PA_ERR_INVALID;
344 if (json_object_get_type(o) != json_type_int) {
346 return -PA_ERR_INVALID;
349 *v = json_object_get_int(o);
355 int pa_format_info_get_prop_int_range(pa_format_info *f, const char *key, int *min, int *max) {
358 int ret = -PA_ERR_INVALID;
365 str = pa_proplist_gets(f->plist, key);
367 return -PA_ERR_NOENTITY;
369 o = json_tokener_parse(str);
371 return -PA_ERR_INVALID;
373 if (json_object_get_type(o) != json_type_object)
376 if (!(o1 = json_object_object_get(o, PA_JSON_MIN_KEY)))
379 *min = json_object_get_int(o1);
382 if (!(o1 = json_object_object_get(o, PA_JSON_MAX_KEY)))
385 *max = json_object_get_int(o1);
395 int pa_format_info_get_prop_int_array(pa_format_info *f, const char *key, int **values, int *n_values) {
398 int i, ret = -PA_ERR_INVALID;
405 str = pa_proplist_gets(f->plist, key);
407 return -PA_ERR_NOENTITY;
409 o = json_tokener_parse(str);
411 return -PA_ERR_INVALID;
413 if (json_object_get_type(o) != json_type_array)
416 *n_values = json_object_array_length(o);
417 *values = pa_xnew(int, *n_values);
419 for (i = 0; i < *n_values; i++) {
420 o1 = json_object_array_get_idx(o, i);
422 if (json_object_get_type(o1) != json_type_int) {
427 (*values)[i] = json_object_get_int(o1);
438 int pa_format_info_get_prop_string(pa_format_info *f, const char *key, char **v) {
439 const char *str = NULL;
446 str = pa_proplist_gets(f->plist, key);
448 return -PA_ERR_NOENTITY;
450 o = json_tokener_parse(str);
452 return -PA_ERR_INVALID;
454 if (json_object_get_type(o) != json_type_string) {
456 return -PA_ERR_INVALID;
459 *v = pa_xstrdup(json_object_get_string(o));
465 int pa_format_info_get_prop_string_array(pa_format_info *f, const char *key, char ***values, int *n_values) {
468 int i, ret = -PA_ERR_INVALID;
475 str = pa_proplist_gets(f->plist, key);
477 return -PA_ERR_NOENTITY;
479 o = json_tokener_parse(str);
481 return -PA_ERR_INVALID;
483 if (json_object_get_type(o) != json_type_array)
486 *n_values = json_object_array_length(o);
487 *values = pa_xnew(char *, *n_values);
489 for (i = 0; i < *n_values; i++) {
490 o1 = json_object_array_get_idx(o, i);
492 if (json_object_get_type(o1) != json_type_string) {
497 (*values)[i] = pa_xstrdup(json_object_get_string(o1));
508 void pa_format_info_free_string_array(char **values, int n_values) {
511 for (i = 0; i < n_values; i++)
517 void pa_format_info_set_sample_format(pa_format_info *f, pa_sample_format_t sf) {
518 pa_format_info_set_prop_string(f, PA_PROP_FORMAT_SAMPLE_FORMAT, pa_sample_format_to_string(sf));
521 void pa_format_info_set_rate(pa_format_info *f, int rate) {
522 pa_format_info_set_prop_int(f, PA_PROP_FORMAT_RATE, rate);
525 void pa_format_info_set_channels(pa_format_info *f, int channels) {
526 pa_format_info_set_prop_int(f, PA_PROP_FORMAT_CHANNELS, channels);
529 void pa_format_info_set_channel_map(pa_format_info *f, const pa_channel_map *map) {
530 char map_str[PA_CHANNEL_MAP_SNPRINT_MAX];
532 pa_channel_map_snprint(map_str, sizeof(map_str), map);
534 pa_format_info_set_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, map_str);
537 void pa_format_info_set_prop_int(pa_format_info *f, const char *key, int value) {
543 o = json_object_new_int(value);
545 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
550 void pa_format_info_set_prop_int_array(pa_format_info *f, const char *key, const int *values, int n_values) {
557 o = json_object_new_array();
559 for (i = 0; i < n_values; i++)
560 json_object_array_add(o, json_object_new_int(values[i]));
562 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
567 void pa_format_info_set_prop_int_range(pa_format_info *f, const char *key, int min, int max) {
573 o = json_object_new_object();
575 json_object_object_add(o, PA_JSON_MIN_KEY, json_object_new_int(min));
576 json_object_object_add(o, PA_JSON_MAX_KEY, json_object_new_int(max));
578 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
583 void pa_format_info_set_prop_string(pa_format_info *f, const char *key, const char *value) {
589 o = json_object_new_string(value);
591 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
596 void pa_format_info_set_prop_string_array(pa_format_info *f, const char *key, const char **values, int n_values) {
603 o = json_object_new_array();
605 for (i = 0; i < n_values; i++)
606 json_object_array_add(o, json_object_new_string(values[i]));
608 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
613 static bool pa_json_is_fixed_type(json_object *o) {
614 switch(json_object_get_type(o)) {
615 case json_type_object:
616 case json_type_array:
624 static int pa_json_value_equal(json_object *o1, json_object *o2) {
625 return (json_object_get_type(o1) == json_object_get_type(o2)) &&
626 pa_streq(json_object_to_json_string(o1), json_object_to_json_string(o2));
629 static int pa_format_info_prop_compatible(const char *one, const char *two) {
630 json_object *o1 = NULL, *o2 = NULL;
633 o1 = json_tokener_parse(one);
637 o2 = json_tokener_parse(two);
641 /* We don't deal with both values being non-fixed - just because there is no immediate need (FIXME) */
642 pa_return_val_if_fail(pa_json_is_fixed_type(o1) || pa_json_is_fixed_type(o2), false);
644 if (pa_json_is_fixed_type(o1) && pa_json_is_fixed_type(o2)) {
645 ret = pa_json_value_equal(o1, o2);
649 if (pa_json_is_fixed_type(o1)) {
650 json_object *tmp = o2;
655 /* o2 is now a fixed type, and o1 is not */
657 if (json_object_get_type(o1) == json_type_array) {
658 for (i = 0; i < json_object_array_length(o1); i++) {
659 if (pa_json_value_equal(json_object_array_get_idx(o1, i), o2)) {
664 } else if (json_object_get_type(o1) == json_type_object) {
665 /* o1 should be a range type */
667 json_object *o_min = NULL, *o_max = NULL;
669 if (json_object_get_type(o2) != json_type_int) {
670 /* We don't support non-integer ranges */
674 o_min = json_object_object_get(o1, PA_JSON_MIN_KEY);
675 if (!o_min || json_object_get_type(o_min) != json_type_int)
678 o_max = json_object_object_get(o1, PA_JSON_MAX_KEY);
679 if (!o_max || json_object_get_type(o_max) != json_type_int)
682 v = json_object_get_int(o2);
683 min = json_object_get_int(o_min);
684 max = json_object_get_int(o_max);
686 ret = v >= min && v <= max;
688 pa_log_warn("Got a format type that we don't support");