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>
32 #include <pulse/i18n.h>
34 #include <pulsecore/core-util.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 const char *pa_encoding_to_string(pa_encoding_t e) {
45 static const char* const 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_ANY] = "any",
54 if (e < 0 || e >= PA_ENCODING_MAX)
60 pa_format_info* pa_format_info_new(void) {
61 pa_format_info *f = pa_xnew(pa_format_info, 1);
63 f->encoding = PA_ENCODING_INVALID;
64 f->plist = pa_proplist_new();
69 pa_format_info* pa_format_info_copy(const pa_format_info *src) {
74 dest = pa_xnew(pa_format_info, 1);
76 dest->encoding = src->encoding;
79 dest->plist = pa_proplist_copy(src->plist);
86 void pa_format_info_free(pa_format_info *f) {
89 pa_proplist_free(f->plist);
93 void pa_format_info_free2(pa_format_info *f, void *userdata) {
94 pa_format_info_free(f);
97 int pa_format_info_valid(const pa_format_info *f) {
98 return (f->encoding >= 0 && f->encoding < PA_ENCODING_MAX && f->plist != NULL);
101 int pa_format_info_is_pcm(const pa_format_info *f) {
102 return f->encoding == PA_ENCODING_PCM;
105 char *pa_format_info_snprint(char *s, size_t l, const pa_format_info *f) {
114 if (!pa_format_info_valid(f))
115 pa_snprintf(s, l, _("(invalid)"));
117 tmp = pa_proplist_to_string_sep(f->plist, ", ");
118 pa_snprintf(s, l, _("%s, %s"), pa_encoding_to_string(f->encoding), tmp[0] ? tmp : _("(no properties)"));
125 int pa_format_info_is_compatible(pa_format_info *first, pa_format_info *second) {
132 if (first->encoding != second->encoding)
135 while ((key = pa_proplist_iterate(first->plist, &state))) {
136 const char *value_one, *value_two;
138 value_one = pa_proplist_gets(first->plist, key);
139 value_two = pa_proplist_gets(second->plist, key);
141 if (!value_two || !pa_format_info_prop_compatible(value_one, value_two))
148 pa_format_info* pa_format_info_from_sample_spec(pa_sample_spec *ss, pa_channel_map *map) {
149 char cm[PA_CHANNEL_MAP_SNPRINT_MAX];
152 pa_assert(ss && pa_sample_spec_valid(ss));
153 pa_assert(!map || pa_channel_map_valid(map));
155 f = pa_format_info_new();
156 f->encoding = PA_ENCODING_PCM;
158 pa_format_info_set_prop_string(f, PA_PROP_FORMAT_SAMPLE_FORMAT, pa_sample_format_to_string(ss->format));
159 pa_format_info_set_prop_int(f, PA_PROP_FORMAT_RATE, ss->rate);
160 pa_format_info_set_prop_int(f, PA_PROP_FORMAT_CHANNELS, ss->channels);
163 pa_channel_map_snprint(cm, sizeof(cm), map);
164 pa_format_info_set_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, cm);
170 /* For PCM streams */
171 pa_bool_t pa_format_info_to_sample_spec(pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map) {
172 char *sf = NULL, *m = NULL;
174 pa_bool_t ret = FALSE;
178 pa_return_val_if_fail(f->encoding == PA_ENCODING_PCM, FALSE);
180 if (!pa_format_info_get_prop_string(f, PA_PROP_FORMAT_SAMPLE_FORMAT, &sf))
182 if (!pa_format_info_get_prop_int(f, PA_PROP_FORMAT_RATE, &rate))
184 if (!pa_format_info_get_prop_int(f, PA_PROP_FORMAT_CHANNELS, &channels))
187 if ((ss->format = pa_parse_sample_format(sf)) == PA_SAMPLE_INVALID)
190 ss->rate = (uint32_t) rate;
191 ss->channels = (uint8_t) channels;
194 pa_channel_map_init(map);
196 if (!pa_format_info_get_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, &m))
199 if (m && pa_channel_map_parse(map, m) == NULL)
214 /* For compressed streams */
215 pa_bool_t pa_format_info_to_sample_spec_fake(pa_format_info *f, pa_sample_spec *ss) {
220 pa_return_val_if_fail(f->encoding != PA_ENCODING_PCM, FALSE);
222 ss->format = PA_SAMPLE_S16LE;
225 pa_return_val_if_fail(pa_format_info_get_prop_int(f, PA_PROP_FORMAT_RATE, &rate), FALSE);
226 ss->rate = (uint32_t) rate;
228 if (f->encoding == PA_ENCODING_EAC3_IEC61937)
234 pa_bool_t pa_format_info_get_prop_int(pa_format_info *f, const char *key, int *v) {
242 pa_return_val_if_fail(str = pa_proplist_gets(f->plist, key), FALSE);
243 o = json_tokener_parse(str);
244 pa_return_val_if_fail(!is_error(o), FALSE);
245 if (json_object_get_type(o) != json_type_int) {
250 *v = json_object_get_int(o);
256 pa_bool_t pa_format_info_get_prop_string(pa_format_info *f, const char *key, char **v) {
257 const char *str = NULL;
264 pa_return_val_if_fail(str = pa_proplist_gets(f->plist, key), FALSE);
265 o = json_tokener_parse(str);
266 pa_return_val_if_fail(!is_error(o), FALSE);
267 if (json_object_get_type(o) != json_type_string) {
272 *v = pa_xstrdup(json_object_get_string(o));
278 void pa_format_info_set_prop_int(pa_format_info *f, const char *key, int value) {
284 o = json_object_new_int(value);
286 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
291 void pa_format_info_set_prop_int_array(pa_format_info *f, const char *key, const int *values, int n_values) {
298 o = json_object_new_array();
300 for (i = 0; i < n_values; i++)
301 json_object_array_add(o, json_object_new_int(values[i]));
303 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
308 void pa_format_info_set_prop_int_range(pa_format_info *f, const char *key, int min, int max) {
314 o = json_object_new_object();
316 json_object_object_add(o, PA_JSON_MIN_KEY, json_object_new_int(min));
317 json_object_object_add(o, PA_JSON_MAX_KEY, json_object_new_int(max));
319 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
324 void pa_format_info_set_prop_string(pa_format_info *f, const char *key, const char *value) {
330 o = json_object_new_string(value);
332 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
337 void pa_format_info_set_prop_string_array(pa_format_info *f, const char *key, const char **values, int n_values) {
344 o = json_object_new_array();
346 for (i = 0; i < n_values; i++)
347 json_object_array_add(o, json_object_new_string(values[i]));
349 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
354 static pa_bool_t pa_json_is_fixed_type(json_object *o)
356 switch(json_object_get_type(o)) {
357 case json_type_object:
358 case json_type_array:
366 static int pa_json_value_equal(json_object *o1, json_object *o2) {
367 return (json_object_get_type(o1) == json_object_get_type(o2)) &&
368 pa_streq(json_object_to_json_string(o1), json_object_to_json_string(o2));
371 static int pa_format_info_prop_compatible(const char *one, const char *two) {
372 json_object *o1 = NULL, *o2 = NULL;
375 o1 = json_tokener_parse(one);
379 o2 = json_tokener_parse(two);
383 /* We don't deal with both values being non-fixed - just because there is no immediate need (FIXME) */
384 pa_return_val_if_fail(pa_json_is_fixed_type(o1) || pa_json_is_fixed_type(o2), FALSE);
386 if (pa_json_is_fixed_type(o1) && pa_json_is_fixed_type(o2)) {
387 ret = pa_json_value_equal(o1, o2);
391 if (pa_json_is_fixed_type(o1)) {
392 json_object *tmp = o2;
397 /* o2 is now a fixed type, and o1 is not */
399 if (json_object_get_type(o1) == json_type_array) {
400 for (i = 0; i < json_object_array_length(o1); i++) {
401 if (pa_json_value_equal(json_object_array_get_idx(o1, i), o2)) {
406 } else if (json_object_get_type(o1) == json_type_object) {
407 /* o1 should be a range type */
409 json_object *o_min = NULL, *o_max = NULL;
411 if (json_object_get_type(o2) != json_type_int) {
412 /* We don't support non-integer ranges */
416 o_min = json_object_object_get(o1, PA_JSON_MIN_KEY);
417 if (!o_min || json_object_get_type(o_min) != json_type_int)
420 o_max = json_object_object_get(o1, PA_JSON_MAX_KEY);
421 if (!o_max || json_object_get_type(o_max) != json_type_int)
424 v = json_object_get_int(o2);
425 min = json_object_get_int(o_min);
426 max = json_object_get_int(o_max);
428 ret = v >= min && v <= max;
430 pa_log_warn("Got a format type that we don't support");