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_sample_format(f, ss->format);
159 pa_format_info_set_rate(f, ss->rate);
160 pa_format_info_set_channels(f, 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 void pa_format_info_set_sample_format(pa_format_info *f, pa_sample_format_t sf) {
235 pa_format_info_set_prop_string(f, PA_PROP_FORMAT_SAMPLE_FORMAT, pa_sample_format_to_string(sf));
238 void pa_format_info_set_rate(pa_format_info *f, int rate) {
239 pa_format_info_set_prop_int(f, PA_PROP_FORMAT_RATE, rate);
242 void pa_format_info_set_channels(pa_format_info *f, int channels) {
243 pa_format_info_set_prop_int(f, PA_PROP_FORMAT_CHANNELS, channels);
246 void pa_format_info_set_channel_map(pa_format_info *f, const pa_channel_map *map) {
247 char map_str[PA_CHANNEL_MAP_SNPRINT_MAX];
249 pa_channel_map_snprint(map_str, sizeof(map_str), map);
251 pa_format_info_set_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, map_str);
254 pa_bool_t pa_format_info_get_prop_int(pa_format_info *f, const char *key, int *v) {
262 pa_return_val_if_fail(str = pa_proplist_gets(f->plist, key), FALSE);
263 o = json_tokener_parse(str);
264 pa_return_val_if_fail(!is_error(o), FALSE);
265 if (json_object_get_type(o) != json_type_int) {
270 *v = json_object_get_int(o);
276 pa_bool_t pa_format_info_get_prop_string(pa_format_info *f, const char *key, char **v) {
277 const char *str = NULL;
284 pa_return_val_if_fail(str = pa_proplist_gets(f->plist, key), FALSE);
285 o = json_tokener_parse(str);
286 pa_return_val_if_fail(!is_error(o), FALSE);
287 if (json_object_get_type(o) != json_type_string) {
292 *v = pa_xstrdup(json_object_get_string(o));
298 void pa_format_info_set_prop_int(pa_format_info *f, const char *key, int value) {
304 o = json_object_new_int(value);
306 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
311 void pa_format_info_set_prop_int_array(pa_format_info *f, const char *key, const int *values, int n_values) {
318 o = json_object_new_array();
320 for (i = 0; i < n_values; i++)
321 json_object_array_add(o, json_object_new_int(values[i]));
323 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
328 void pa_format_info_set_prop_int_range(pa_format_info *f, const char *key, int min, int max) {
334 o = json_object_new_object();
336 json_object_object_add(o, PA_JSON_MIN_KEY, json_object_new_int(min));
337 json_object_object_add(o, PA_JSON_MAX_KEY, json_object_new_int(max));
339 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
344 void pa_format_info_set_prop_string(pa_format_info *f, const char *key, const char *value) {
350 o = json_object_new_string(value);
352 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
357 void pa_format_info_set_prop_string_array(pa_format_info *f, const char *key, const char **values, int n_values) {
364 o = json_object_new_array();
366 for (i = 0; i < n_values; i++)
367 json_object_array_add(o, json_object_new_string(values[i]));
369 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
374 static pa_bool_t pa_json_is_fixed_type(json_object *o)
376 switch(json_object_get_type(o)) {
377 case json_type_object:
378 case json_type_array:
386 static int pa_json_value_equal(json_object *o1, json_object *o2) {
387 return (json_object_get_type(o1) == json_object_get_type(o2)) &&
388 pa_streq(json_object_to_json_string(o1), json_object_to_json_string(o2));
391 static int pa_format_info_prop_compatible(const char *one, const char *two) {
392 json_object *o1 = NULL, *o2 = NULL;
395 o1 = json_tokener_parse(one);
399 o2 = json_tokener_parse(two);
403 /* We don't deal with both values being non-fixed - just because there is no immediate need (FIXME) */
404 pa_return_val_if_fail(pa_json_is_fixed_type(o1) || pa_json_is_fixed_type(o2), FALSE);
406 if (pa_json_is_fixed_type(o1) && pa_json_is_fixed_type(o2)) {
407 ret = pa_json_value_equal(o1, o2);
411 if (pa_json_is_fixed_type(o1)) {
412 json_object *tmp = o2;
417 /* o2 is now a fixed type, and o1 is not */
419 if (json_object_get_type(o1) == json_type_array) {
420 for (i = 0; i < json_object_array_length(o1); i++) {
421 if (pa_json_value_equal(json_object_array_get_idx(o1, i), o2)) {
426 } else if (json_object_get_type(o1) == json_type_object) {
427 /* o1 should be a range type */
429 json_object *o_min = NULL, *o_max = NULL;
431 if (json_object_get_type(o2) != json_type_int) {
432 /* We don't support non-integer ranges */
436 o_min = json_object_object_get(o1, PA_JSON_MIN_KEY);
437 if (!o_min || json_object_get_type(o_min) != json_type_int)
440 o_max = json_object_object_get(o1, PA_JSON_MAX_KEY);
441 if (!o_max || json_object_get_type(o_max) != json_type_int)
444 v = json_object_get_int(o2);
445 min = json_object_get_int(o_min);
446 max = json_object_get_int(o_max);
448 ret = v >= min && v <= max;
450 pa_log_warn("Got a format type that we don't support");