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/>.
26 #include <pulse/json.h>
27 #include <pulse/internal.h>
28 #include <pulse/xmalloc.h>
30 #include <pulsecore/core-format.h>
31 #include <pulsecore/core-util.h>
32 #include <pulsecore/i18n.h>
33 #include <pulsecore/macro.h>
34 #include <pulsecore/strbuf.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) {
240 const pa_json_object *o1;
246 str = pa_proplist_gets(f->plist, key);
248 return PA_PROP_TYPE_INVALID;
250 o = pa_json_parse(str);
252 return PA_PROP_TYPE_INVALID;
254 switch (pa_json_object_get_type(o)) {
255 case PA_JSON_TYPE_INT:
256 type = PA_PROP_TYPE_INT;
259 case PA_JSON_TYPE_STRING:
260 type = PA_PROP_TYPE_STRING;
263 case PA_JSON_TYPE_ARRAY:
264 if (pa_json_object_get_array_length(o) == 0) {
265 /* Unlikely, but let's account for this anyway. We need at
266 * least one element to figure out the array type. */
267 type = PA_PROP_TYPE_INVALID;
271 o1 = pa_json_object_get_array_member(o, 0);
273 if (pa_json_object_get_type(o1) == PA_JSON_TYPE_INT)
274 type = PA_PROP_TYPE_INT_ARRAY;
275 else if (pa_json_object_get_type(o1) == PA_JSON_TYPE_STRING)
276 type = PA_PROP_TYPE_STRING_ARRAY;
278 type = PA_PROP_TYPE_INVALID;
282 case PA_JSON_TYPE_OBJECT:
283 /* We actually know at this point that it's a int range, but let's
285 if (!pa_json_object_get_object_member(o, PA_JSON_MIN_KEY)) {
286 type = PA_PROP_TYPE_INVALID;
290 if (!pa_json_object_get_object_member(o, PA_JSON_MAX_KEY)) {
291 type = PA_PROP_TYPE_INVALID;
295 type = PA_PROP_TYPE_INT_RANGE;
299 type = PA_PROP_TYPE_INVALID;
303 pa_json_object_unref(o);
307 int pa_format_info_get_prop_int(const pa_format_info *f, const char *key, int *v) {
315 str = pa_proplist_gets(f->plist, key);
317 return -PA_ERR_NOENTITY;
319 o = pa_json_parse(str);
321 pa_log_debug("Failed to parse format info property '%s'.", key);
322 return -PA_ERR_INVALID;
325 if (pa_json_object_get_type(o) != PA_JSON_TYPE_INT) {
326 pa_log_debug("Format info property '%s' type is not int.", key);
327 pa_json_object_unref(o);
328 return -PA_ERR_INVALID;
331 *v = pa_json_object_get_int(o);
332 pa_json_object_unref(o);
337 int pa_format_info_get_prop_int_range(const pa_format_info *f, const char *key, int *min, int *max) {
340 const pa_json_object *o1;
341 int ret = -PA_ERR_INVALID;
348 str = pa_proplist_gets(f->plist, key);
350 return -PA_ERR_NOENTITY;
352 o = pa_json_parse(str);
354 pa_log_debug("Failed to parse format info property '%s'.", key);
355 return -PA_ERR_INVALID;
358 if (pa_json_object_get_type(o) != PA_JSON_TYPE_OBJECT)
361 if (!(o1 = pa_json_object_get_object_member(o, PA_JSON_MIN_KEY)) ||
362 (pa_json_object_get_type(o1) != PA_JSON_TYPE_INT))
365 *min = pa_json_object_get_int(o1);
367 if (!(o1 = pa_json_object_get_object_member(o, PA_JSON_MAX_KEY)) ||
368 (pa_json_object_get_type(o1) != PA_JSON_TYPE_INT))
371 *max = pa_json_object_get_int(o1);
377 pa_log_debug("Format info property '%s' is not a valid int range.", key);
379 pa_json_object_unref(o);
383 int pa_format_info_get_prop_int_array(const pa_format_info *f, const char *key, int **values, int *n_values) {
386 const pa_json_object *o1;
387 int i, ret = -PA_ERR_INVALID;
394 str = pa_proplist_gets(f->plist, key);
396 return -PA_ERR_NOENTITY;
398 o = pa_json_parse(str);
400 pa_log_debug("Failed to parse format info property '%s'.", key);
401 return -PA_ERR_INVALID;
404 if (pa_json_object_get_type(o) != PA_JSON_TYPE_ARRAY)
407 *n_values = pa_json_object_get_array_length(o);
408 *values = pa_xnew(int, *n_values);
410 for (i = 0; i < *n_values; i++) {
411 o1 = pa_json_object_get_array_member(o, i);
413 if (pa_json_object_get_type(o1) != PA_JSON_TYPE_INT) {
417 (*values)[i] = pa_json_object_get_int(o1);
424 pa_log_debug("Format info property '%s' is not a valid int array.", key);
426 pa_json_object_unref(o);
430 int pa_format_info_get_prop_string(const pa_format_info *f, const char *key, char **v) {
431 const char *str = NULL;
438 str = pa_proplist_gets(f->plist, key);
440 return -PA_ERR_NOENTITY;
442 o = pa_json_parse(str);
444 pa_log_debug("Failed to parse format info property '%s'.", key);
445 return -PA_ERR_INVALID;
448 if (pa_json_object_get_type(o) != PA_JSON_TYPE_STRING) {
449 pa_log_debug("Format info property '%s' type is not string.", key);
450 pa_json_object_unref(o);
451 return -PA_ERR_INVALID;
454 *v = pa_xstrdup(pa_json_object_get_string(o));
455 pa_json_object_unref(o);
460 int pa_format_info_get_prop_string_array(const pa_format_info *f, const char *key, char ***values, int *n_values) {
463 const pa_json_object *o1;
464 int i, ret = -PA_ERR_INVALID;
471 str = pa_proplist_gets(f->plist, key);
473 return -PA_ERR_NOENTITY;
475 o = pa_json_parse(str);
477 pa_log_debug("Failed to parse format info property '%s'.", key);
478 return -PA_ERR_INVALID;
481 if (pa_json_object_get_type(o) != PA_JSON_TYPE_ARRAY)
484 *n_values = pa_json_object_get_array_length(o);
485 *values = pa_xnew(char *, *n_values);
487 for (i = 0; i < *n_values; i++) {
488 o1 = pa_json_object_get_array_member(o, i);
490 if (pa_json_object_get_type(o1) != PA_JSON_TYPE_STRING) {
494 (*values)[i] = pa_xstrdup(pa_json_object_get_string(o1));
501 pa_log_debug("Format info property '%s' is not a valid string array.", key);
503 pa_json_object_unref(o);
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) {
540 pa_proplist_setf(f->plist, key, "%d", value);
543 void pa_format_info_set_prop_int_array(pa_format_info *f, const char *key, const int *values, int n_values) {
550 pa_assert(n_values > 0);
552 buf = pa_strbuf_new();
554 pa_strbuf_printf(buf, "[ %d", values[0]);
556 for (i = 1; i < n_values; i++)
557 pa_strbuf_printf(buf, ", %d", values[i]);
559 pa_strbuf_printf(buf, " ]");
560 str = pa_strbuf_to_string_free(buf);
562 pa_proplist_sets(f->plist, key, str);
566 void pa_format_info_set_prop_int_range(pa_format_info *f, const char *key, int min, int max) {
570 pa_proplist_setf(f->plist, key, "{ \"" PA_JSON_MIN_KEY "\": %d, \"" PA_JSON_MAX_KEY "\": %d }",
574 void pa_format_info_set_prop_string(pa_format_info *f, const char *key, const char *value) {
578 pa_proplist_setf(f->plist, key, "\"%s\"", value);
581 void pa_format_info_set_prop_string_array(pa_format_info *f, const char *key, const char **values, int n_values) {
589 buf = pa_strbuf_new();
591 pa_strbuf_printf(buf, "[ \"%s\"", values[0]);
593 for (i = 1; i < n_values; i++)
594 pa_strbuf_printf(buf, ", \"%s\"", values[i]);
596 pa_strbuf_printf(buf, " ]");
597 str = pa_strbuf_to_string_free(buf);
599 pa_proplist_sets(f->plist, key, str);
603 static bool pa_json_is_fixed_type(pa_json_object *o) {
604 switch(pa_json_object_get_type(o)) {
605 case PA_JSON_TYPE_OBJECT:
606 case PA_JSON_TYPE_ARRAY:
614 static int pa_format_info_prop_compatible(const char *one, const char *two) {
615 pa_json_object *o1 = NULL, *o2 = NULL;
618 o1 = pa_json_parse(one);
622 o2 = pa_json_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_object_equal(o1, o2);
634 if (pa_json_is_fixed_type(o1)) {
635 pa_json_object *tmp = o2;
640 /* o2 is now a fixed type, and o1 is not */
642 if (pa_json_object_get_type(o1) == PA_JSON_TYPE_ARRAY) {
643 for (i = 0; i < pa_json_object_get_array_length(o1); i++) {
644 if (pa_json_object_equal(pa_json_object_get_array_member(o1, i), o2)) {
649 } else if (pa_json_object_get_type(o1) == PA_JSON_TYPE_OBJECT) {
650 /* o1 should be a range type */
652 const pa_json_object *o_min = NULL, *o_max = NULL;
654 if (pa_json_object_get_type(o2) != PA_JSON_TYPE_INT) {
655 /* We don't support non-integer ranges */
659 if (!(o_min = pa_json_object_get_object_member(o1, PA_JSON_MIN_KEY)) ||
660 pa_json_object_get_type(o_min) != PA_JSON_TYPE_INT)
663 if (!(o_max = pa_json_object_get_object_member(o1, PA_JSON_MAX_KEY)) ||
664 pa_json_object_get_type(o_max) != PA_JSON_TYPE_INT)
667 v = pa_json_object_get_int(o2);
668 min = pa_json_object_get_int(o_min);
669 max = pa_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");
678 pa_json_object_unref(o1);
680 pa_json_object_unref(o2);