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-format.h>
34 #include <pulsecore/core-util.h>
35 #include <pulsecore/i18n.h>
36 #include <pulsecore/macro.h>
40 #define PA_JSON_MIN_KEY "min"
41 #define PA_JSON_MAX_KEY "max"
43 static int pa_format_info_prop_compatible(const char *one
, const char *two
);
45 static const char* const _encoding_str_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_MPEG2_AAC_IEC61937
] = "mpeg2-aac-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
) {
247 str
= pa_proplist_gets(f
->plist
, key
);
249 return PA_PROP_TYPE_INVALID
;
251 o
= json_tokener_parse(str
);
253 return PA_PROP_TYPE_INVALID
;
255 switch (json_object_get_type(o
)) {
257 type
= PA_PROP_TYPE_INT
;
260 case json_type_string
:
261 type
= PA_PROP_TYPE_STRING
;
264 case json_type_array
:
265 if (json_object_array_length(o
) == 0) {
266 /* Unlikely, but let's account for this anyway. We need at
267 * least one element to figure out the array type. */
268 type
= PA_PROP_TYPE_INVALID
;
272 o1
= json_object_array_get_idx(o
, 1);
274 if (json_object_get_type(o1
) == json_type_int
)
275 type
= PA_PROP_TYPE_INT_ARRAY
;
276 else if (json_object_get_type(o1
) == json_type_string
)
277 type
= PA_PROP_TYPE_STRING_ARRAY
;
279 type
= PA_PROP_TYPE_INVALID
;
284 case json_type_object
:
285 /* We actually know at this point that it's a int range, but let's
287 o1
= json_object_object_get(o
, PA_JSON_MIN_KEY
);
289 type
= PA_PROP_TYPE_INVALID
;
294 o1
= json_object_object_get(o
, PA_JSON_MAX_KEY
);
296 type
= PA_PROP_TYPE_INVALID
;
301 type
= PA_PROP_TYPE_INT_RANGE
;
305 type
= PA_PROP_TYPE_INVALID
;
313 int pa_format_info_get_prop_int(const pa_format_info
*f
, const char *key
, int *v
) {
321 str
= pa_proplist_gets(f
->plist
, key
);
323 return -PA_ERR_NOENTITY
;
325 o
= json_tokener_parse(str
);
327 pa_log_debug("Failed to parse format info property '%s'.", key
);
328 return -PA_ERR_INVALID
;
331 if (json_object_get_type(o
) != json_type_int
) {
332 pa_log_debug("Format info property '%s' type is not int.", key
);
334 return -PA_ERR_INVALID
;
337 *v
= json_object_get_int(o
);
343 int pa_format_info_get_prop_int_range(const pa_format_info
*f
, const char *key
, int *min
, int *max
) {
346 int ret
= -PA_ERR_INVALID
;
353 str
= pa_proplist_gets(f
->plist
, key
);
355 return -PA_ERR_NOENTITY
;
357 o
= json_tokener_parse(str
);
359 pa_log_debug("Failed to parse format info property '%s'.", key
);
360 return -PA_ERR_INVALID
;
363 if (json_object_get_type(o
) != json_type_object
)
366 if (!(o1
= json_object_object_get(o
, PA_JSON_MIN_KEY
)))
369 *min
= json_object_get_int(o1
);
372 if (!(o1
= json_object_object_get(o
, PA_JSON_MAX_KEY
)))
375 *max
= json_object_get_int(o1
);
382 pa_log_debug("Format info property '%s' is not a valid int range.", key
);
388 int pa_format_info_get_prop_int_array(const pa_format_info
*f
, const char *key
, int **values
, int *n_values
) {
391 int i
, ret
= -PA_ERR_INVALID
;
398 str
= pa_proplist_gets(f
->plist
, key
);
400 return -PA_ERR_NOENTITY
;
402 o
= json_tokener_parse(str
);
404 pa_log_debug("Failed to parse format info property '%s'.", key
);
405 return -PA_ERR_INVALID
;
408 if (json_object_get_type(o
) != json_type_array
)
411 *n_values
= json_object_array_length(o
);
412 *values
= pa_xnew(int, *n_values
);
414 for (i
= 0; i
< *n_values
; i
++) {
415 o1
= json_object_array_get_idx(o
, i
);
417 if (json_object_get_type(o1
) != json_type_int
) {
422 (*values
)[i
] = json_object_get_int(o1
);
430 pa_log_debug("Format info property '%s' is not a valid int array.", key
);
436 int pa_format_info_get_prop_string(const pa_format_info
*f
, const char *key
, char **v
) {
437 const char *str
= NULL
;
444 str
= pa_proplist_gets(f
->plist
, key
);
446 return -PA_ERR_NOENTITY
;
448 o
= json_tokener_parse(str
);
450 pa_log_debug("Failed to parse format info property '%s'.", key
);
451 return -PA_ERR_INVALID
;
454 if (json_object_get_type(o
) != json_type_string
) {
455 pa_log_debug("Format info property '%s' type is not string.", key
);
457 return -PA_ERR_INVALID
;
460 *v
= pa_xstrdup(json_object_get_string(o
));
466 int pa_format_info_get_prop_string_array(const pa_format_info
*f
, const char *key
, char ***values
, int *n_values
) {
469 int i
, ret
= -PA_ERR_INVALID
;
476 str
= pa_proplist_gets(f
->plist
, key
);
478 return -PA_ERR_NOENTITY
;
480 o
= json_tokener_parse(str
);
482 pa_log_debug("Failed to parse format info property '%s'.", key
);
483 return -PA_ERR_INVALID
;
486 if (json_object_get_type(o
) != json_type_array
)
489 *n_values
= json_object_array_length(o
);
490 *values
= pa_xnew(char *, *n_values
);
492 for (i
= 0; i
< *n_values
; i
++) {
493 o1
= json_object_array_get_idx(o
, i
);
495 if (json_object_get_type(o1
) != json_type_string
) {
500 (*values
)[i
] = pa_xstrdup(json_object_get_string(o1
));
508 pa_log_debug("Format info property '%s' is not a valid string array.", key
);
514 void pa_format_info_free_string_array(char **values
, int n_values
) {
517 for (i
= 0; i
< n_values
; i
++)
523 void pa_format_info_set_sample_format(pa_format_info
*f
, pa_sample_format_t sf
) {
524 pa_format_info_set_prop_string(f
, PA_PROP_FORMAT_SAMPLE_FORMAT
, pa_sample_format_to_string(sf
));
527 void pa_format_info_set_rate(pa_format_info
*f
, int rate
) {
528 pa_format_info_set_prop_int(f
, PA_PROP_FORMAT_RATE
, rate
);
531 void pa_format_info_set_channels(pa_format_info
*f
, int channels
) {
532 pa_format_info_set_prop_int(f
, PA_PROP_FORMAT_CHANNELS
, channels
);
535 void pa_format_info_set_channel_map(pa_format_info
*f
, const pa_channel_map
*map
) {
536 char map_str
[PA_CHANNEL_MAP_SNPRINT_MAX
];
538 pa_channel_map_snprint(map_str
, sizeof(map_str
), map
);
540 pa_format_info_set_prop_string(f
, PA_PROP_FORMAT_CHANNEL_MAP
, map_str
);
543 void pa_format_info_set_prop_int(pa_format_info
*f
, const char *key
, int value
) {
549 o
= json_object_new_int(value
);
551 pa_proplist_sets(f
->plist
, key
, json_object_to_json_string(o
));
556 void pa_format_info_set_prop_int_array(pa_format_info
*f
, const char *key
, const int *values
, int n_values
) {
563 o
= json_object_new_array();
565 for (i
= 0; i
< n_values
; i
++)
566 json_object_array_add(o
, json_object_new_int(values
[i
]));
568 pa_proplist_sets(f
->plist
, key
, json_object_to_json_string(o
));
573 void pa_format_info_set_prop_int_range(pa_format_info
*f
, const char *key
, int min
, int max
) {
579 o
= json_object_new_object();
581 json_object_object_add(o
, PA_JSON_MIN_KEY
, json_object_new_int(min
));
582 json_object_object_add(o
, PA_JSON_MAX_KEY
, json_object_new_int(max
));
584 pa_proplist_sets(f
->plist
, key
, json_object_to_json_string(o
));
589 void pa_format_info_set_prop_string(pa_format_info
*f
, const char *key
, const char *value
) {
595 o
= json_object_new_string(value
);
597 pa_proplist_sets(f
->plist
, key
, json_object_to_json_string(o
));
602 void pa_format_info_set_prop_string_array(pa_format_info
*f
, const char *key
, const char **values
, int n_values
) {
609 o
= json_object_new_array();
611 for (i
= 0; i
< n_values
; i
++)
612 json_object_array_add(o
, json_object_new_string(values
[i
]));
614 pa_proplist_sets(f
->plist
, key
, json_object_to_json_string(o
));
619 static bool pa_json_is_fixed_type(json_object
*o
) {
620 switch(json_object_get_type(o
)) {
621 case json_type_object
:
622 case json_type_array
:
630 static int pa_json_value_equal(json_object
*o1
, json_object
*o2
) {
631 return (json_object_get_type(o1
) == json_object_get_type(o2
)) &&
632 pa_streq(json_object_to_json_string(o1
), json_object_to_json_string(o2
));
635 static int pa_format_info_prop_compatible(const char *one
, const char *two
) {
636 json_object
*o1
= NULL
, *o2
= NULL
;
639 o1
= json_tokener_parse(one
);
643 o2
= json_tokener_parse(two
);
647 /* We don't deal with both values being non-fixed - just because there is no immediate need (FIXME) */
648 pa_return_val_if_fail(pa_json_is_fixed_type(o1
) || pa_json_is_fixed_type(o2
), false);
650 if (pa_json_is_fixed_type(o1
) && pa_json_is_fixed_type(o2
)) {
651 ret
= pa_json_value_equal(o1
, o2
);
655 if (pa_json_is_fixed_type(o1
)) {
656 json_object
*tmp
= o2
;
661 /* o2 is now a fixed type, and o1 is not */
663 if (json_object_get_type(o1
) == json_type_array
) {
664 for (i
= 0; i
< json_object_array_length(o1
); i
++) {
665 if (pa_json_value_equal(json_object_array_get_idx(o1
, i
), o2
)) {
670 } else if (json_object_get_type(o1
) == json_type_object
) {
671 /* o1 should be a range type */
673 json_object
*o_min
= NULL
, *o_max
= NULL
;
675 if (json_object_get_type(o2
) != json_type_int
) {
676 /* We don't support non-integer ranges */
680 o_min
= json_object_object_get(o1
, PA_JSON_MIN_KEY
);
681 if (!o_min
|| json_object_get_type(o_min
) != json_type_int
)
684 o_max
= json_object_object_get(o1
, PA_JSON_MAX_KEY
);
685 if (!o_max
|| json_object_get_type(o_max
) != json_type_int
)
688 v
= json_object_get_int(o2
);
689 min
= json_object_get_int(o_min
);
690 max
= json_object_get_int(o_max
);
692 ret
= v
>= min
&& v
<= max
;
694 pa_log_warn("Got a format type that we don't support");