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 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
))
197 if (pa_channel_map_parse(map
, m
) == NULL
)
212 /* For compressed streams */
213 pa_bool_t
pa_format_info_to_sample_spec_fake(pa_format_info
*f
, pa_sample_spec
*ss
) {
218 pa_return_val_if_fail(f
->encoding
!= PA_ENCODING_PCM
, FALSE
);
220 ss
->format
= PA_SAMPLE_S16LE
;
223 pa_return_val_if_fail(pa_format_info_get_prop_int(f
, PA_PROP_FORMAT_RATE
, &rate
), FALSE
);
224 ss
->rate
= (uint32_t) rate
;
226 if (f
->encoding
== PA_ENCODING_EAC3_IEC61937
)
232 void pa_format_info_set_sample_format(pa_format_info
*f
, pa_sample_format_t sf
) {
233 pa_format_info_set_prop_string(f
, PA_PROP_FORMAT_SAMPLE_FORMAT
, pa_sample_format_to_string(sf
));
236 void pa_format_info_set_rate(pa_format_info
*f
, int rate
) {
237 pa_format_info_set_prop_int(f
, PA_PROP_FORMAT_RATE
, rate
);
240 void pa_format_info_set_channels(pa_format_info
*f
, int channels
) {
241 pa_format_info_set_prop_int(f
, PA_PROP_FORMAT_CHANNELS
, channels
);
244 void pa_format_info_set_channel_map(pa_format_info
*f
, const pa_channel_map
*map
) {
245 char map_str
[PA_CHANNEL_MAP_SNPRINT_MAX
];
247 pa_channel_map_snprint(map_str
, sizeof(map_str
), map
);
249 pa_format_info_set_prop_string(f
, PA_PROP_FORMAT_CHANNEL_MAP
, map_str
);
252 pa_bool_t
pa_format_info_get_prop_int(pa_format_info
*f
, const char *key
, int *v
) {
260 pa_return_val_if_fail(str
= pa_proplist_gets(f
->plist
, key
), FALSE
);
261 o
= json_tokener_parse(str
);
262 pa_return_val_if_fail(!is_error(o
), FALSE
);
263 if (json_object_get_type(o
) != json_type_int
) {
268 *v
= json_object_get_int(o
);
274 pa_bool_t
pa_format_info_get_prop_string(pa_format_info
*f
, const char *key
, char **v
) {
275 const char *str
= NULL
;
282 str
= pa_proplist_gets(f
->plist
, key
), FALSE
;
286 o
= json_tokener_parse(str
);
287 pa_return_val_if_fail(!is_error(o
), FALSE
);
288 if (json_object_get_type(o
) != json_type_string
) {
293 *v
= pa_xstrdup(json_object_get_string(o
));
299 void pa_format_info_set_prop_int(pa_format_info
*f
, const char *key
, int value
) {
305 o
= json_object_new_int(value
);
307 pa_proplist_sets(f
->plist
, key
, json_object_to_json_string(o
));
312 void pa_format_info_set_prop_int_array(pa_format_info
*f
, const char *key
, const int *values
, int n_values
) {
319 o
= json_object_new_array();
321 for (i
= 0; i
< n_values
; i
++)
322 json_object_array_add(o
, json_object_new_int(values
[i
]));
324 pa_proplist_sets(f
->plist
, key
, json_object_to_json_string(o
));
329 void pa_format_info_set_prop_int_range(pa_format_info
*f
, const char *key
, int min
, int max
) {
335 o
= json_object_new_object();
337 json_object_object_add(o
, PA_JSON_MIN_KEY
, json_object_new_int(min
));
338 json_object_object_add(o
, PA_JSON_MAX_KEY
, json_object_new_int(max
));
340 pa_proplist_sets(f
->plist
, key
, json_object_to_json_string(o
));
345 void pa_format_info_set_prop_string(pa_format_info
*f
, const char *key
, const char *value
) {
351 o
= json_object_new_string(value
);
353 pa_proplist_sets(f
->plist
, key
, json_object_to_json_string(o
));
358 void pa_format_info_set_prop_string_array(pa_format_info
*f
, const char *key
, const char **values
, int n_values
) {
365 o
= json_object_new_array();
367 for (i
= 0; i
< n_values
; i
++)
368 json_object_array_add(o
, json_object_new_string(values
[i
]));
370 pa_proplist_sets(f
->plist
, key
, json_object_to_json_string(o
));
375 static pa_bool_t
pa_json_is_fixed_type(json_object
*o
)
377 switch(json_object_get_type(o
)) {
378 case json_type_object
:
379 case json_type_array
:
387 static int pa_json_value_equal(json_object
*o1
, json_object
*o2
) {
388 return (json_object_get_type(o1
) == json_object_get_type(o2
)) &&
389 pa_streq(json_object_to_json_string(o1
), json_object_to_json_string(o2
));
392 static int pa_format_info_prop_compatible(const char *one
, const char *two
) {
393 json_object
*o1
= NULL
, *o2
= NULL
;
396 o1
= json_tokener_parse(one
);
400 o2
= json_tokener_parse(two
);
404 /* We don't deal with both values being non-fixed - just because there is no immediate need (FIXME) */
405 pa_return_val_if_fail(pa_json_is_fixed_type(o1
) || pa_json_is_fixed_type(o2
), FALSE
);
407 if (pa_json_is_fixed_type(o1
) && pa_json_is_fixed_type(o2
)) {
408 ret
= pa_json_value_equal(o1
, o2
);
412 if (pa_json_is_fixed_type(o1
)) {
413 json_object
*tmp
= o2
;
418 /* o2 is now a fixed type, and o1 is not */
420 if (json_object_get_type(o1
) == json_type_array
) {
421 for (i
= 0; i
< json_object_array_length(o1
); i
++) {
422 if (pa_json_value_equal(json_object_array_get_idx(o1
, i
), o2
)) {
427 } else if (json_object_get_type(o1
) == json_type_object
) {
428 /* o1 should be a range type */
430 json_object
*o_min
= NULL
, *o_max
= NULL
;
432 if (json_object_get_type(o2
) != json_type_int
) {
433 /* We don't support non-integer ranges */
437 o_min
= json_object_object_get(o1
, PA_JSON_MIN_KEY
);
438 if (!o_min
|| json_object_get_type(o_min
) != json_type_int
)
441 o_max
= json_object_object_get(o1
, PA_JSON_MAX_KEY
);
442 if (!o_max
|| json_object_get_type(o_max
) != json_type_int
)
445 v
= json_object_get_int(o2
);
446 min
= json_object_get_int(o_min
);
447 max
= json_object_get_int(o_max
);
449 ret
= v
>= min
&& v
<= max
;
451 pa_log_warn("Got a format type that we don't support");