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) {
104 return (f->encoding >= 0 && f->encoding < PA_ENCODING_MAX && f->plist != NULL);
107 int pa_format_info_is_pcm(const pa_format_info *f) {
108 return f->encoding == PA_ENCODING_PCM;
111 char *pa_format_info_snprint(char *s, size_t l, const pa_format_info *f) {
120 if (!pa_format_info_valid(f))
121 pa_snprintf(s, l, _("(invalid)"));
123 tmp = pa_proplist_to_string_sep(f->plist, " ");
125 pa_snprintf(s, l, "%s, %s", pa_encoding_to_string(f->encoding), tmp);
127 pa_snprintf(s, l, "%s", pa_encoding_to_string(f->encoding));
134 pa_format_info* pa_format_info_from_string(const char *str) {
135 pa_format_info *f = pa_format_info_new();
136 char *encoding = NULL, *properties = NULL;
139 pos = strcspn(str, ",");
141 encoding = pa_xstrndup(str, pos);
142 f->encoding = pa_encoding_from_string(pa_strip(encoding));
143 if (f->encoding == PA_ENCODING_INVALID)
146 if (pos != strlen(str)) {
149 properties = pa_xstrdup(&str[pos+1]);
150 plist = pa_proplist_from_string(properties);
155 pa_proplist_free(f->plist);
163 pa_xfree(properties);
167 pa_format_info_free(f);
172 int pa_format_info_is_compatible(const pa_format_info *first, const pa_format_info *second) {
179 if (first->encoding != second->encoding)
182 while ((key = pa_proplist_iterate(first->plist, &state))) {
183 const char *value_one, *value_two;
185 value_one = pa_proplist_gets(first->plist, key);
186 value_two = pa_proplist_gets(second->plist, key);
188 if (!value_two || !pa_format_info_prop_compatible(value_one, value_two))
195 pa_format_info* pa_format_info_from_sample_spec(const pa_sample_spec *ss, const pa_channel_map *map) {
196 char cm[PA_CHANNEL_MAP_SNPRINT_MAX];
199 pa_assert(ss && pa_sample_spec_valid(ss));
200 pa_assert(!map || pa_channel_map_valid(map));
202 f = pa_format_info_new();
203 f->encoding = PA_ENCODING_PCM;
205 pa_format_info_set_sample_format(f, ss->format);
206 pa_format_info_set_rate(f, ss->rate);
207 pa_format_info_set_channels(f, ss->channels);
210 pa_channel_map_snprint(cm, sizeof(cm), map);
211 pa_format_info_set_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, cm);
217 /* For PCM streams */
218 int pa_format_info_to_sample_spec(const pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map) {
222 if (!pa_format_info_is_pcm(f))
223 return pa_format_info_to_sample_spec_fake(f, ss, map);
225 if (pa_format_info_get_sample_format(f, &ss->format) < 0)
226 return -PA_ERR_INVALID;
227 if (pa_format_info_get_rate(f, &ss->rate) < 0)
228 return -PA_ERR_INVALID;
229 if (pa_format_info_get_channels(f, &ss->channels) < 0)
230 return -PA_ERR_INVALID;
231 if (map && pa_format_info_get_channel_map(f, map) < 0)
232 return -PA_ERR_INVALID;
237 pa_prop_type_t pa_format_info_get_prop_type(const pa_format_info *f, const char *key) {
245 str = pa_proplist_gets(f->plist, key);
247 return PA_PROP_TYPE_INVALID;
249 o = json_tokener_parse(str);
251 return PA_PROP_TYPE_INVALID;
253 switch (json_object_get_type(o)) {
255 type = PA_PROP_TYPE_INT;
258 case json_type_string:
259 type = PA_PROP_TYPE_STRING;
262 case json_type_array:
263 if (json_object_array_length(o) == 0) {
264 /* Unlikely, but let's account for this anyway. We need at
265 * least one element to figure out the array type. */
266 type = PA_PROP_TYPE_INVALID;
270 o1 = json_object_array_get_idx(o, 1);
272 if (json_object_get_type(o1) == json_type_int)
273 type = PA_PROP_TYPE_INT_ARRAY;
274 else if (json_object_get_type(o1) == json_type_string)
275 type = PA_PROP_TYPE_STRING_ARRAY;
277 type = PA_PROP_TYPE_INVALID;
281 case json_type_object:
282 /* We actually know at this point that it's a int range, but let's
284 if (!json_object_object_get_ex(o, PA_JSON_MIN_KEY, NULL)) {
285 type = PA_PROP_TYPE_INVALID;
289 if (!json_object_object_get_ex(o, PA_JSON_MAX_KEY, NULL)) {
290 type = PA_PROP_TYPE_INVALID;
294 type = PA_PROP_TYPE_INT_RANGE;
298 type = PA_PROP_TYPE_INVALID;
306 int pa_format_info_get_prop_int(const pa_format_info *f, const char *key, int *v) {
314 str = pa_proplist_gets(f->plist, key);
316 return -PA_ERR_NOENTITY;
318 o = json_tokener_parse(str);
320 pa_log_debug("Failed to parse format info property '%s'.", key);
321 return -PA_ERR_INVALID;
324 if (json_object_get_type(o) != json_type_int) {
325 pa_log_debug("Format info property '%s' type is not int.", key);
327 return -PA_ERR_INVALID;
330 *v = json_object_get_int(o);
336 int pa_format_info_get_prop_int_range(const pa_format_info *f, const char *key, int *min, int *max) {
339 int ret = -PA_ERR_INVALID;
346 str = pa_proplist_gets(f->plist, key);
348 return -PA_ERR_NOENTITY;
350 o = json_tokener_parse(str);
352 pa_log_debug("Failed to parse format info property '%s'.", key);
353 return -PA_ERR_INVALID;
356 if (json_object_get_type(o) != json_type_object)
359 if (!json_object_object_get_ex(o, PA_JSON_MIN_KEY, &o1))
362 *min = json_object_get_int(o1);
364 if (!json_object_object_get_ex(o, PA_JSON_MAX_KEY, &o1))
367 *max = json_object_get_int(o1);
373 pa_log_debug("Format info property '%s' is not a valid int range.", key);
379 int pa_format_info_get_prop_int_array(const pa_format_info *f, const char *key, int **values, int *n_values) {
382 int i, ret = -PA_ERR_INVALID;
389 str = pa_proplist_gets(f->plist, key);
391 return -PA_ERR_NOENTITY;
393 o = json_tokener_parse(str);
395 pa_log_debug("Failed to parse format info property '%s'.", key);
396 return -PA_ERR_INVALID;
399 if (json_object_get_type(o) != json_type_array)
402 *n_values = json_object_array_length(o);
403 *values = pa_xnew(int, *n_values);
405 for (i = 0; i < *n_values; i++) {
406 o1 = json_object_array_get_idx(o, i);
408 if (json_object_get_type(o1) != json_type_int) {
412 (*values)[i] = json_object_get_int(o1);
419 pa_log_debug("Format info property '%s' is not a valid int array.", key);
425 int pa_format_info_get_prop_string(const pa_format_info *f, const char *key, char **v) {
426 const char *str = NULL;
433 str = pa_proplist_gets(f->plist, key);
435 return -PA_ERR_NOENTITY;
437 o = json_tokener_parse(str);
439 pa_log_debug("Failed to parse format info property '%s'.", key);
440 return -PA_ERR_INVALID;
443 if (json_object_get_type(o) != json_type_string) {
444 pa_log_debug("Format info property '%s' type is not string.", key);
446 return -PA_ERR_INVALID;
449 *v = pa_xstrdup(json_object_get_string(o));
455 int pa_format_info_get_prop_string_array(const pa_format_info *f, const char *key, char ***values, int *n_values) {
458 int i, ret = -PA_ERR_INVALID;
465 str = pa_proplist_gets(f->plist, key);
467 return -PA_ERR_NOENTITY;
469 o = json_tokener_parse(str);
471 pa_log_debug("Failed to parse format info property '%s'.", key);
472 return -PA_ERR_INVALID;
475 if (json_object_get_type(o) != json_type_array)
478 *n_values = json_object_array_length(o);
479 *values = pa_xnew(char *, *n_values);
481 for (i = 0; i < *n_values; i++) {
482 o1 = json_object_array_get_idx(o, i);
484 if (json_object_get_type(o1) != json_type_string) {
488 (*values)[i] = pa_xstrdup(json_object_get_string(o1));
495 pa_log_debug("Format info property '%s' is not a valid string array.", key);
501 void pa_format_info_free_string_array(char **values, int n_values) {
504 for (i = 0; i < n_values; i++)
510 void pa_format_info_set_sample_format(pa_format_info *f, pa_sample_format_t sf) {
511 pa_format_info_set_prop_string(f, PA_PROP_FORMAT_SAMPLE_FORMAT, pa_sample_format_to_string(sf));
514 void pa_format_info_set_rate(pa_format_info *f, int rate) {
515 pa_format_info_set_prop_int(f, PA_PROP_FORMAT_RATE, rate);
518 void pa_format_info_set_channels(pa_format_info *f, int channels) {
519 pa_format_info_set_prop_int(f, PA_PROP_FORMAT_CHANNELS, channels);
522 void pa_format_info_set_channel_map(pa_format_info *f, const pa_channel_map *map) {
523 char map_str[PA_CHANNEL_MAP_SNPRINT_MAX];
525 pa_channel_map_snprint(map_str, sizeof(map_str), map);
527 pa_format_info_set_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, map_str);
530 void pa_format_info_set_prop_int(pa_format_info *f, const char *key, int value) {
536 o = json_object_new_int(value);
538 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
543 void pa_format_info_set_prop_int_array(pa_format_info *f, const char *key, const int *values, int n_values) {
550 o = json_object_new_array();
552 for (i = 0; i < n_values; i++)
553 json_object_array_add(o, json_object_new_int(values[i]));
555 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
560 void pa_format_info_set_prop_int_range(pa_format_info *f, const char *key, int min, int max) {
566 o = json_object_new_object();
568 json_object_object_add(o, PA_JSON_MIN_KEY, json_object_new_int(min));
569 json_object_object_add(o, PA_JSON_MAX_KEY, json_object_new_int(max));
571 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
576 void pa_format_info_set_prop_string(pa_format_info *f, const char *key, const char *value) {
582 o = json_object_new_string(value);
584 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
589 void pa_format_info_set_prop_string_array(pa_format_info *f, const char *key, const char **values, int n_values) {
596 o = json_object_new_array();
598 for (i = 0; i < n_values; i++)
599 json_object_array_add(o, json_object_new_string(values[i]));
601 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
606 static bool pa_json_is_fixed_type(json_object *o) {
607 switch(json_object_get_type(o)) {
608 case json_type_object:
609 case json_type_array:
617 static int pa_json_value_equal(json_object *o1, json_object *o2) {
618 return (json_object_get_type(o1) == json_object_get_type(o2)) &&
619 pa_streq(json_object_to_json_string(o1), json_object_to_json_string(o2));
622 static int pa_format_info_prop_compatible(const char *one, const char *two) {
623 json_object *o1 = NULL, *o2 = NULL;
626 o1 = json_tokener_parse(one);
630 o2 = json_tokener_parse(two);
634 /* We don't deal with both values being non-fixed - just because there is no immediate need (FIXME) */
635 pa_return_val_if_fail(pa_json_is_fixed_type(o1) || pa_json_is_fixed_type(o2), false);
637 if (pa_json_is_fixed_type(o1) && pa_json_is_fixed_type(o2)) {
638 ret = pa_json_value_equal(o1, o2);
642 if (pa_json_is_fixed_type(o1)) {
643 json_object *tmp = o2;
648 /* o2 is now a fixed type, and o1 is not */
650 if (json_object_get_type(o1) == json_type_array) {
651 for (i = 0; i < json_object_array_length(o1); i++) {
652 if (pa_json_value_equal(json_object_array_get_idx(o1, i), o2)) {
657 } else if (json_object_get_type(o1) == json_type_object) {
658 /* o1 should be a range type */
660 json_object *o_min = NULL, *o_max = NULL;
662 if (json_object_get_type(o2) != json_type_int) {
663 /* We don't support non-integer ranges */
667 if (!json_object_object_get_ex(o1, PA_JSON_MIN_KEY, &o_min) ||
668 json_object_get_type(o_min) != json_type_int)
671 if (!json_object_object_get_ex(o1, PA_JSON_MAX_KEY, &o_max) ||
672 json_object_get_type(o_max) != json_type_int)
675 v = json_object_get_int(o2);
676 min = json_object_get_int(o_min);
677 max = json_object_get_int(o_max);
679 ret = v >= min && v <= max;
681 pa_log_warn("Got a format type that we don't support");