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/internal.h>
27 #include <pulse/xmalloc.h>
29 #include <pulsecore/core-format.h>
30 #include <pulsecore/core-util.h>
31 #include <pulsecore/i18n.h>
32 #include <pulsecore/json.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_TRUEHD_IEC61937] = "truehd-iec61937",
51 [PA_ENCODING_DTSHD_IEC61937] = "dtshd-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(const pa_format_info *first, const 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(const pa_sample_spec *ss, const 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(const 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(const pa_format_info *f, const char *key) {
242 const pa_json_object *o1;
248 str = pa_proplist_gets(f->plist, key);
250 return PA_PROP_TYPE_INVALID;
252 o = pa_json_parse(str);
254 return PA_PROP_TYPE_INVALID;
256 switch (pa_json_object_get_type(o)) {
257 case PA_JSON_TYPE_INT:
258 type = PA_PROP_TYPE_INT;
261 case PA_JSON_TYPE_STRING:
262 type = PA_PROP_TYPE_STRING;
265 case PA_JSON_TYPE_ARRAY:
266 if (pa_json_object_get_array_length(o) == 0) {
267 /* Unlikely, but let's account for this anyway. We need at
268 * least one element to figure out the array type. */
269 type = PA_PROP_TYPE_INVALID;
273 o1 = pa_json_object_get_array_member(o, 0);
275 if (pa_json_object_get_type(o1) == PA_JSON_TYPE_INT)
276 type = PA_PROP_TYPE_INT_ARRAY;
277 else if (pa_json_object_get_type(o1) == PA_JSON_TYPE_STRING)
278 type = PA_PROP_TYPE_STRING_ARRAY;
280 type = PA_PROP_TYPE_INVALID;
284 case PA_JSON_TYPE_OBJECT:
285 /* We actually know at this point that it's a int range, but let's
287 if (!pa_json_object_get_object_member(o, PA_JSON_MIN_KEY)) {
288 type = PA_PROP_TYPE_INVALID;
292 if (!pa_json_object_get_object_member(o, PA_JSON_MAX_KEY)) {
293 type = PA_PROP_TYPE_INVALID;
297 type = PA_PROP_TYPE_INT_RANGE;
301 type = PA_PROP_TYPE_INVALID;
305 pa_json_object_free(o);
309 int pa_format_info_get_prop_int(const pa_format_info *f, const char *key, int *v) {
317 str = pa_proplist_gets(f->plist, key);
319 return -PA_ERR_NOENTITY;
321 o = pa_json_parse(str);
323 pa_log_debug("Failed to parse format info property '%s'.", key);
324 return -PA_ERR_INVALID;
327 if (pa_json_object_get_type(o) != PA_JSON_TYPE_INT) {
328 pa_log_debug("Format info property '%s' type is not int.", key);
329 pa_json_object_free(o);
330 return -PA_ERR_INVALID;
333 *v = pa_json_object_get_int(o);
334 pa_json_object_free(o);
339 int pa_format_info_get_prop_int_range(const pa_format_info *f, const char *key, int *min, int *max) {
342 const pa_json_object *o1;
343 int ret = -PA_ERR_INVALID;
350 str = pa_proplist_gets(f->plist, key);
352 return -PA_ERR_NOENTITY;
354 o = pa_json_parse(str);
356 pa_log_debug("Failed to parse format info property '%s'.", key);
357 return -PA_ERR_INVALID;
360 if (pa_json_object_get_type(o) != PA_JSON_TYPE_OBJECT)
363 if (!(o1 = pa_json_object_get_object_member(o, PA_JSON_MIN_KEY)) ||
364 (pa_json_object_get_type(o1) != PA_JSON_TYPE_INT))
367 *min = pa_json_object_get_int(o1);
369 if (!(o1 = pa_json_object_get_object_member(o, PA_JSON_MAX_KEY)) ||
370 (pa_json_object_get_type(o1) != PA_JSON_TYPE_INT))
373 *max = pa_json_object_get_int(o1);
379 pa_log_debug("Format info property '%s' is not a valid int range.", key);
381 pa_json_object_free(o);
385 int pa_format_info_get_prop_int_array(const pa_format_info *f, const char *key, int **values, int *n_values) {
388 const pa_json_object *o1;
389 int i, ret = -PA_ERR_INVALID;
396 str = pa_proplist_gets(f->plist, key);
398 return -PA_ERR_NOENTITY;
400 o = pa_json_parse(str);
402 pa_log_debug("Failed to parse format info property '%s'.", key);
403 return -PA_ERR_INVALID;
406 if (pa_json_object_get_type(o) != PA_JSON_TYPE_ARRAY)
409 *n_values = pa_json_object_get_array_length(o);
410 *values = pa_xnew(int, *n_values);
412 for (i = 0; i < *n_values; i++) {
413 o1 = pa_json_object_get_array_member(o, i);
415 if (pa_json_object_get_type(o1) != PA_JSON_TYPE_INT) {
419 (*values)[i] = pa_json_object_get_int(o1);
426 pa_log_debug("Format info property '%s' is not a valid int array.", key);
428 pa_json_object_free(o);
432 int pa_format_info_get_prop_string(const pa_format_info *f, const char *key, char **v) {
433 const char *str = NULL;
440 str = pa_proplist_gets(f->plist, key);
442 return -PA_ERR_NOENTITY;
444 o = pa_json_parse(str);
446 pa_log_debug("Failed to parse format info property '%s'.", key);
447 return -PA_ERR_INVALID;
450 if (pa_json_object_get_type(o) != PA_JSON_TYPE_STRING) {
451 pa_log_debug("Format info property '%s' type is not string.", key);
452 pa_json_object_free(o);
453 return -PA_ERR_INVALID;
456 *v = pa_xstrdup(pa_json_object_get_string(o));
457 pa_json_object_free(o);
462 int pa_format_info_get_prop_string_array(const pa_format_info *f, const char *key, char ***values, int *n_values) {
465 const pa_json_object *o1;
466 int i, ret = -PA_ERR_INVALID;
473 str = pa_proplist_gets(f->plist, key);
475 return -PA_ERR_NOENTITY;
477 o = pa_json_parse(str);
479 pa_log_debug("Failed to parse format info property '%s'.", key);
480 return -PA_ERR_INVALID;
483 if (pa_json_object_get_type(o) != PA_JSON_TYPE_ARRAY)
486 *n_values = pa_json_object_get_array_length(o);
487 *values = pa_xnew(char *, *n_values);
489 for (i = 0; i < *n_values; i++) {
490 o1 = pa_json_object_get_array_member(o, i);
492 if (pa_json_object_get_type(o1) != PA_JSON_TYPE_STRING) {
496 (*values)[i] = pa_xstrdup(pa_json_object_get_string(o1));
503 pa_log_debug("Format info property '%s' is not a valid string array.", key);
505 pa_json_object_free(o);
509 void pa_format_info_free_string_array(char **values, int n_values) {
512 for (i = 0; i < n_values; i++)
518 int pa_format_info_get_sample_format(const pa_format_info *f, pa_sample_format_t *sf) {
521 pa_sample_format_t sf_local;
526 r = pa_format_info_get_prop_string(f, PA_PROP_FORMAT_SAMPLE_FORMAT, &sf_str);
530 sf_local = pa_parse_sample_format(sf_str);
533 if (!pa_sample_format_valid(sf_local)) {
534 pa_log_debug("Invalid sample format.");
535 return -PA_ERR_INVALID;
543 int pa_format_info_get_rate(const pa_format_info *f, uint32_t *rate) {
550 r = pa_format_info_get_prop_int(f, PA_PROP_FORMAT_RATE, &rate_local);
554 if (!pa_sample_rate_valid(rate_local)) {
555 pa_log_debug("Invalid sample rate: %i", rate_local);
556 return -PA_ERR_INVALID;
564 int pa_format_info_get_channels(const pa_format_info *f, uint8_t *channels) {
571 r = pa_format_info_get_prop_int(f, PA_PROP_FORMAT_CHANNELS, &channels_local);
575 if (!pa_channels_valid(channels_local)) {
576 pa_log_debug("Invalid channel count: %i", channels_local);
577 return -PA_ERR_INVALID;
580 *channels = channels_local;
585 int pa_format_info_get_channel_map(const pa_format_info *f, pa_channel_map *map) {
592 r = pa_format_info_get_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, &map_str);
596 map = pa_channel_map_parse(map, map_str);
600 pa_log_debug("Failed to parse channel map.");
601 return -PA_ERR_INVALID;
607 void pa_format_info_set_sample_format(pa_format_info *f, pa_sample_format_t sf) {
608 pa_format_info_set_prop_string(f, PA_PROP_FORMAT_SAMPLE_FORMAT, pa_sample_format_to_string(sf));
611 void pa_format_info_set_rate(pa_format_info *f, int rate) {
612 pa_format_info_set_prop_int(f, PA_PROP_FORMAT_RATE, rate);
615 void pa_format_info_set_channels(pa_format_info *f, int channels) {
616 pa_format_info_set_prop_int(f, PA_PROP_FORMAT_CHANNELS, channels);
619 void pa_format_info_set_channel_map(pa_format_info *f, const pa_channel_map *map) {
620 char map_str[PA_CHANNEL_MAP_SNPRINT_MAX];
622 pa_channel_map_snprint(map_str, sizeof(map_str), map);
624 pa_format_info_set_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, map_str);
627 void pa_format_info_set_prop_int(pa_format_info *f, const char *key, int value) {
631 pa_proplist_setf(f->plist, key, "%d", value);
634 void pa_format_info_set_prop_int_array(pa_format_info *f, const char *key, const int *values, int n_values) {
641 pa_assert(n_values > 0);
643 buf = pa_strbuf_new();
645 pa_strbuf_printf(buf, "[ %d", values[0]);
647 for (i = 1; i < n_values; i++)
648 pa_strbuf_printf(buf, ", %d", values[i]);
650 pa_strbuf_printf(buf, " ]");
651 str = pa_strbuf_to_string_free(buf);
653 pa_proplist_sets(f->plist, key, str);
657 void pa_format_info_set_prop_int_range(pa_format_info *f, const char *key, int min, int max) {
661 pa_proplist_setf(f->plist, key, "{ \"" PA_JSON_MIN_KEY "\": %d, \"" PA_JSON_MAX_KEY "\": %d }",
665 void pa_format_info_set_prop_string(pa_format_info *f, const char *key, const char *value) {
669 pa_proplist_setf(f->plist, key, "\"%s\"", value);
672 void pa_format_info_set_prop_string_array(pa_format_info *f, const char *key, const char **values, int n_values) {
680 buf = pa_strbuf_new();
682 pa_strbuf_printf(buf, "[ \"%s\"", values[0]);
684 for (i = 1; i < n_values; i++)
685 pa_strbuf_printf(buf, ", \"%s\"", values[i]);
687 pa_strbuf_printf(buf, " ]");
688 str = pa_strbuf_to_string_free(buf);
690 pa_proplist_sets(f->plist, key, str);
694 static bool pa_json_is_fixed_type(pa_json_object *o) {
695 switch(pa_json_object_get_type(o)) {
696 case PA_JSON_TYPE_OBJECT:
697 case PA_JSON_TYPE_ARRAY:
705 static int pa_format_info_prop_compatible(const char *one, const char *two) {
706 pa_json_object *o1 = NULL, *o2 = NULL;
709 o1 = pa_json_parse(one);
713 o2 = pa_json_parse(two);
717 /* We don't deal with both values being non-fixed - just because there is no immediate need (FIXME) */
718 pa_return_val_if_fail(pa_json_is_fixed_type(o1) || pa_json_is_fixed_type(o2), false);
720 if (pa_json_is_fixed_type(o1) && pa_json_is_fixed_type(o2)) {
721 ret = pa_json_object_equal(o1, o2);
725 if (pa_json_is_fixed_type(o1)) {
726 pa_json_object *tmp = o2;
731 /* o2 is now a fixed type, and o1 is not */
733 if (pa_json_object_get_type(o1) == PA_JSON_TYPE_ARRAY) {
734 for (i = 0; i < pa_json_object_get_array_length(o1); i++) {
735 if (pa_json_object_equal(pa_json_object_get_array_member(o1, i), o2)) {
740 } else if (pa_json_object_get_type(o1) == PA_JSON_TYPE_OBJECT) {
741 /* o1 should be a range type */
743 const pa_json_object *o_min = NULL, *o_max = NULL;
745 if (pa_json_object_get_type(o2) != PA_JSON_TYPE_INT) {
746 /* We don't support non-integer ranges */
750 if (!(o_min = pa_json_object_get_object_member(o1, PA_JSON_MIN_KEY)) ||
751 pa_json_object_get_type(o_min) != PA_JSON_TYPE_INT)
754 if (!(o_max = pa_json_object_get_object_member(o1, PA_JSON_MAX_KEY)) ||
755 pa_json_object_get_type(o_max) != PA_JSON_TYPE_INT)
758 v = pa_json_object_get_int(o2);
759 min = pa_json_object_get_int(o_min);
760 max = pa_json_object_get_int(o_max);
762 ret = v >= min && v <= max;
764 pa_log_warn("Got a format type that we don't support");
769 pa_json_object_free(o1);
771 pa_json_object_free(o2);