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-util.h>
34 #include <pulsecore/i18n.h>
35 #include <pulsecore/macro.h>
39 #define PA_JSON_MIN_KEY "min"
40 #define PA_JSON_MAX_KEY "max"
42 static int pa_format_info_prop_compatible(const char *one, const char *two);
44 static const char* const _encoding_str_table[]= {
45 [PA_ENCODING_PCM] = "pcm",
46 [PA_ENCODING_AC3_IEC61937] = "ac3-iec61937",
47 [PA_ENCODING_EAC3_IEC61937] = "eac3-iec61937",
48 [PA_ENCODING_MPEG_IEC61937] = "mpeg-iec61937",
49 [PA_ENCODING_DTS_IEC61937] = "dts-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(pa_format_info *first, 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(pa_sample_spec *ss, 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 compressed streams */
218 static int pa_format_info_to_sample_spec_fake(pa_format_info *f, pa_sample_spec *ss) {
224 /* Note: When we add support for non-IEC61937 encapsulated compressed
225 * formats, this function should return a non-zero values for these. */
227 ss->format = PA_SAMPLE_S16LE;
230 pa_return_val_if_fail(pa_format_info_get_prop_int(f, PA_PROP_FORMAT_RATE, &rate) == 0, -PA_ERR_INVALID);
231 ss->rate = (uint32_t) rate;
233 if (f->encoding == PA_ENCODING_EAC3_IEC61937)
239 /* For PCM streams */
240 int pa_format_info_to_sample_spec(pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map) {
241 char *sf = NULL, *m = NULL;
243 int ret = -PA_ERR_INVALID;
248 if (!pa_format_info_is_pcm(f))
249 return pa_format_info_to_sample_spec_fake(f, ss);
251 if (pa_format_info_get_prop_string(f, PA_PROP_FORMAT_SAMPLE_FORMAT, &sf))
253 if (pa_format_info_get_prop_int(f, PA_PROP_FORMAT_RATE, &rate))
255 if (pa_format_info_get_prop_int(f, PA_PROP_FORMAT_CHANNELS, &channels))
258 if ((ss->format = pa_parse_sample_format(sf)) == PA_SAMPLE_INVALID)
261 ss->rate = (uint32_t) rate;
262 ss->channels = (uint8_t) channels;
265 pa_channel_map_init(map);
267 if (pa_format_info_get_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, &m) == 0)
268 if (pa_channel_map_parse(map, m) == NULL)
283 pa_prop_type_t pa_format_info_get_prop_type(pa_format_info *f, const char *key) {
291 str = pa_proplist_gets(f->plist, key);
293 return PA_PROP_TYPE_INVALID;
295 o = json_tokener_parse(str);
297 return PA_PROP_TYPE_INVALID;
299 switch (json_object_get_type(o)) {
301 type = PA_PROP_TYPE_INT;
304 case json_type_string:
305 type = PA_PROP_TYPE_STRING;
308 case json_type_array:
309 if (json_object_array_length(o) == 0) {
310 /* Unlikely, but let's account for this anyway. We need at
311 * least one element to figure out the array type. */
312 type = PA_PROP_TYPE_INVALID;
316 o1 = json_object_array_get_idx(o, 1);
318 if (json_object_get_type(o1) == json_type_int)
319 type = PA_PROP_TYPE_INT_ARRAY;
320 else if (json_object_get_type(o1) == json_type_string)
321 type = PA_PROP_TYPE_STRING_ARRAY;
323 type = PA_PROP_TYPE_INVALID;
328 case json_type_object:
329 /* We actually know at this point that it's a int range, but let's
331 o1 = json_object_object_get(o, PA_JSON_MIN_KEY);
333 type = PA_PROP_TYPE_INVALID;
338 o1 = json_object_object_get(o, PA_JSON_MAX_KEY);
340 type = PA_PROP_TYPE_INVALID;
345 type = PA_PROP_TYPE_INT_RANGE;
349 type = PA_PROP_TYPE_INVALID;
357 int pa_format_info_get_prop_int(pa_format_info *f, const char *key, int *v) {
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_int) {
375 return -PA_ERR_INVALID;
378 *v = json_object_get_int(o);
384 int pa_format_info_get_prop_int_range(pa_format_info *f, const char *key, int *min, int *max) {
387 int ret = -PA_ERR_INVALID;
394 str = pa_proplist_gets(f->plist, key);
396 return -PA_ERR_NOENTITY;
398 o = json_tokener_parse(str);
400 return -PA_ERR_INVALID;
402 if (json_object_get_type(o) != json_type_object)
405 if (!(o1 = json_object_object_get(o, PA_JSON_MIN_KEY)))
408 *min = json_object_get_int(o1);
411 if (!(o1 = json_object_object_get(o, PA_JSON_MAX_KEY)))
414 *max = json_object_get_int(o1);
424 int pa_format_info_get_prop_int_array(pa_format_info *f, const char *key, int **values, int *n_values)
428 int i, ret = -PA_ERR_INVALID;
435 str = pa_proplist_gets(f->plist, key);
437 return -PA_ERR_NOENTITY;
439 o = json_tokener_parse(str);
441 return -PA_ERR_INVALID;
443 if (json_object_get_type(o) != json_type_array)
446 *n_values = json_object_array_length(o);
447 *values = pa_xnew(int, *n_values);
449 for (i = 0; i < *n_values; i++) {
450 o1 = json_object_array_get_idx(o, i);
452 if (json_object_get_type(o1) != json_type_int) {
457 (*values)[i] = json_object_get_int(o1);
468 int pa_format_info_get_prop_string(pa_format_info *f, const char *key, char **v) {
469 const char *str = NULL;
476 str = pa_proplist_gets(f->plist, key);
478 return -PA_ERR_NOENTITY;
480 o = json_tokener_parse(str);
482 return -PA_ERR_INVALID;
484 if (json_object_get_type(o) != json_type_string) {
486 return -PA_ERR_INVALID;
489 *v = pa_xstrdup(json_object_get_string(o));
495 int pa_format_info_get_prop_string_array(pa_format_info *f, const char *key, char ***values, int *n_values)
499 int i, ret = -PA_ERR_INVALID;
506 str = pa_proplist_gets(f->plist, key);
508 return -PA_ERR_NOENTITY;
510 o = json_tokener_parse(str);
512 return -PA_ERR_INVALID;
514 if (json_object_get_type(o) != json_type_array)
517 *n_values = json_object_array_length(o);
518 *values = pa_xnew(char *, *n_values);
520 for (i = 0; i < *n_values; i++) {
521 o1 = json_object_array_get_idx(o, i);
523 if (json_object_get_type(o1) != json_type_string) {
528 (*values)[i] = pa_xstrdup(json_object_get_string(o1));
539 void pa_format_info_free_string_array(char **values, int n_values) {
542 for (i = 0; i < n_values; i++)
548 void pa_format_info_set_sample_format(pa_format_info *f, pa_sample_format_t sf) {
549 pa_format_info_set_prop_string(f, PA_PROP_FORMAT_SAMPLE_FORMAT, pa_sample_format_to_string(sf));
552 void pa_format_info_set_rate(pa_format_info *f, int rate) {
553 pa_format_info_set_prop_int(f, PA_PROP_FORMAT_RATE, rate);
556 void pa_format_info_set_channels(pa_format_info *f, int channels) {
557 pa_format_info_set_prop_int(f, PA_PROP_FORMAT_CHANNELS, channels);
560 void pa_format_info_set_channel_map(pa_format_info *f, const pa_channel_map *map) {
561 char map_str[PA_CHANNEL_MAP_SNPRINT_MAX];
563 pa_channel_map_snprint(map_str, sizeof(map_str), map);
565 pa_format_info_set_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, map_str);
568 void pa_format_info_set_prop_int(pa_format_info *f, const char *key, int value) {
574 o = json_object_new_int(value);
576 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
581 void pa_format_info_set_prop_int_array(pa_format_info *f, const char *key, const int *values, int n_values) {
588 o = json_object_new_array();
590 for (i = 0; i < n_values; i++)
591 json_object_array_add(o, json_object_new_int(values[i]));
593 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
598 void pa_format_info_set_prop_int_range(pa_format_info *f, const char *key, int min, int max) {
604 o = json_object_new_object();
606 json_object_object_add(o, PA_JSON_MIN_KEY, json_object_new_int(min));
607 json_object_object_add(o, PA_JSON_MAX_KEY, json_object_new_int(max));
609 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
614 void pa_format_info_set_prop_string(pa_format_info *f, const char *key, const char *value) {
620 o = json_object_new_string(value);
622 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
627 void pa_format_info_set_prop_string_array(pa_format_info *f, const char *key, const char **values, int n_values) {
634 o = json_object_new_array();
636 for (i = 0; i < n_values; i++)
637 json_object_array_add(o, json_object_new_string(values[i]));
639 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
644 static pa_bool_t pa_json_is_fixed_type(json_object *o)
646 switch(json_object_get_type(o)) {
647 case json_type_object:
648 case json_type_array:
656 static int pa_json_value_equal(json_object *o1, json_object *o2) {
657 return (json_object_get_type(o1) == json_object_get_type(o2)) &&
658 pa_streq(json_object_to_json_string(o1), json_object_to_json_string(o2));
661 static int pa_format_info_prop_compatible(const char *one, const char *two) {
662 json_object *o1 = NULL, *o2 = NULL;
665 o1 = json_tokener_parse(one);
669 o2 = json_tokener_parse(two);
673 /* We don't deal with both values being non-fixed - just because there is no immediate need (FIXME) */
674 pa_return_val_if_fail(pa_json_is_fixed_type(o1) || pa_json_is_fixed_type(o2), FALSE);
676 if (pa_json_is_fixed_type(o1) && pa_json_is_fixed_type(o2)) {
677 ret = pa_json_value_equal(o1, o2);
681 if (pa_json_is_fixed_type(o1)) {
682 json_object *tmp = o2;
687 /* o2 is now a fixed type, and o1 is not */
689 if (json_object_get_type(o1) == json_type_array) {
690 for (i = 0; i < json_object_array_length(o1); i++) {
691 if (pa_json_value_equal(json_object_array_get_idx(o1, i), o2)) {
696 } else if (json_object_get_type(o1) == json_type_object) {
697 /* o1 should be a range type */
699 json_object *o_min = NULL, *o_max = NULL;
701 if (json_object_get_type(o2) != json_type_int) {
702 /* We don't support non-integer ranges */
706 o_min = json_object_object_get(o1, PA_JSON_MIN_KEY);
707 if (!o_min || json_object_get_type(o_min) != json_type_int)
710 o_max = json_object_object_get(o1, PA_JSON_MAX_KEY);
711 if (!o_max || json_object_get_type(o_max) != json_type_int)
714 v = json_object_get_int(o2);
715 min = json_object_get_int(o_min);
716 max = json_object_get_int(o_max);
718 ret = v >= min && v <= max;
720 pa_log_warn("Got a format type that we don't support");