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(pa_format_info
*first
, 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(pa_sample_spec
*ss
, 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(pa_format_info
*f
, pa_sample_spec
*ss
, pa_channel_map
*map
) {
223 int ret
= -PA_ERR_INVALID
;
228 if (!pa_format_info_is_pcm(f
))
229 return pa_format_info_to_sample_spec_fake(f
, ss
, map
);
231 if (pa_format_info_get_sample_format(f
, &ss
->format
) < 0)
233 if (pa_format_info_get_rate(f
, &ss
->rate
) < 0)
235 if (pa_format_info_get_prop_int(f
, PA_PROP_FORMAT_CHANNELS
, &channels
))
238 ss
->channels
= (uint8_t) channels
;
241 pa_channel_map_init(map
);
243 if (pa_format_info_get_prop_string(f
, PA_PROP_FORMAT_CHANNEL_MAP
, &m
) == 0)
244 if (pa_channel_map_parse(map
, m
) == NULL
)
257 pa_prop_type_t
pa_format_info_get_prop_type(pa_format_info
*f
, const char *key
) {
265 str
= pa_proplist_gets(f
->plist
, key
);
267 return PA_PROP_TYPE_INVALID
;
269 o
= json_tokener_parse(str
);
271 return PA_PROP_TYPE_INVALID
;
273 switch (json_object_get_type(o
)) {
275 type
= PA_PROP_TYPE_INT
;
278 case json_type_string
:
279 type
= PA_PROP_TYPE_STRING
;
282 case json_type_array
:
283 if (json_object_array_length(o
) == 0) {
284 /* Unlikely, but let's account for this anyway. We need at
285 * least one element to figure out the array type. */
286 type
= PA_PROP_TYPE_INVALID
;
290 o1
= json_object_array_get_idx(o
, 1);
292 if (json_object_get_type(o1
) == json_type_int
)
293 type
= PA_PROP_TYPE_INT_ARRAY
;
294 else if (json_object_get_type(o1
) == json_type_string
)
295 type
= PA_PROP_TYPE_STRING_ARRAY
;
297 type
= PA_PROP_TYPE_INVALID
;
302 case json_type_object
:
303 /* We actually know at this point that it's a int range, but let's
305 o1
= json_object_object_get(o
, PA_JSON_MIN_KEY
);
307 type
= PA_PROP_TYPE_INVALID
;
312 o1
= json_object_object_get(o
, PA_JSON_MAX_KEY
);
314 type
= PA_PROP_TYPE_INVALID
;
319 type
= PA_PROP_TYPE_INT_RANGE
;
323 type
= PA_PROP_TYPE_INVALID
;
331 int pa_format_info_get_prop_int(pa_format_info
*f
, const char *key
, int *v
) {
339 str
= pa_proplist_gets(f
->plist
, key
);
341 return -PA_ERR_NOENTITY
;
343 o
= json_tokener_parse(str
);
345 return -PA_ERR_INVALID
;
347 if (json_object_get_type(o
) != json_type_int
) {
349 return -PA_ERR_INVALID
;
352 *v
= json_object_get_int(o
);
358 int pa_format_info_get_prop_int_range(pa_format_info
*f
, const char *key
, int *min
, int *max
) {
361 int ret
= -PA_ERR_INVALID
;
368 str
= pa_proplist_gets(f
->plist
, key
);
370 return -PA_ERR_NOENTITY
;
372 o
= json_tokener_parse(str
);
374 return -PA_ERR_INVALID
;
376 if (json_object_get_type(o
) != json_type_object
)
379 if (!(o1
= json_object_object_get(o
, PA_JSON_MIN_KEY
)))
382 *min
= json_object_get_int(o1
);
385 if (!(o1
= json_object_object_get(o
, PA_JSON_MAX_KEY
)))
388 *max
= json_object_get_int(o1
);
398 int pa_format_info_get_prop_int_array(pa_format_info
*f
, const char *key
, int **values
, int *n_values
) {
401 int i
, ret
= -PA_ERR_INVALID
;
408 str
= pa_proplist_gets(f
->plist
, key
);
410 return -PA_ERR_NOENTITY
;
412 o
= json_tokener_parse(str
);
414 return -PA_ERR_INVALID
;
416 if (json_object_get_type(o
) != json_type_array
)
419 *n_values
= json_object_array_length(o
);
420 *values
= pa_xnew(int, *n_values
);
422 for (i
= 0; i
< *n_values
; i
++) {
423 o1
= json_object_array_get_idx(o
, i
);
425 if (json_object_get_type(o1
) != json_type_int
) {
430 (*values
)[i
] = json_object_get_int(o1
);
441 int pa_format_info_get_prop_string(pa_format_info
*f
, const char *key
, char **v
) {
442 const char *str
= NULL
;
449 str
= pa_proplist_gets(f
->plist
, key
);
451 return -PA_ERR_NOENTITY
;
453 o
= json_tokener_parse(str
);
455 return -PA_ERR_INVALID
;
457 if (json_object_get_type(o
) != json_type_string
) {
459 return -PA_ERR_INVALID
;
462 *v
= pa_xstrdup(json_object_get_string(o
));
468 int pa_format_info_get_prop_string_array(pa_format_info
*f
, const char *key
, char ***values
, int *n_values
) {
471 int i
, ret
= -PA_ERR_INVALID
;
478 str
= pa_proplist_gets(f
->plist
, key
);
480 return -PA_ERR_NOENTITY
;
482 o
= json_tokener_parse(str
);
484 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
));
511 void pa_format_info_free_string_array(char **values
, int n_values
) {
514 for (i
= 0; i
< n_values
; i
++)
520 void pa_format_info_set_sample_format(pa_format_info
*f
, pa_sample_format_t sf
) {
521 pa_format_info_set_prop_string(f
, PA_PROP_FORMAT_SAMPLE_FORMAT
, pa_sample_format_to_string(sf
));
524 void pa_format_info_set_rate(pa_format_info
*f
, int rate
) {
525 pa_format_info_set_prop_int(f
, PA_PROP_FORMAT_RATE
, rate
);
528 void pa_format_info_set_channels(pa_format_info
*f
, int channels
) {
529 pa_format_info_set_prop_int(f
, PA_PROP_FORMAT_CHANNELS
, channels
);
532 void pa_format_info_set_channel_map(pa_format_info
*f
, const pa_channel_map
*map
) {
533 char map_str
[PA_CHANNEL_MAP_SNPRINT_MAX
];
535 pa_channel_map_snprint(map_str
, sizeof(map_str
), map
);
537 pa_format_info_set_prop_string(f
, PA_PROP_FORMAT_CHANNEL_MAP
, map_str
);
540 void pa_format_info_set_prop_int(pa_format_info
*f
, const char *key
, int value
) {
546 o
= json_object_new_int(value
);
548 pa_proplist_sets(f
->plist
, key
, json_object_to_json_string(o
));
553 void pa_format_info_set_prop_int_array(pa_format_info
*f
, const char *key
, const int *values
, int n_values
) {
560 o
= json_object_new_array();
562 for (i
= 0; i
< n_values
; i
++)
563 json_object_array_add(o
, json_object_new_int(values
[i
]));
565 pa_proplist_sets(f
->plist
, key
, json_object_to_json_string(o
));
570 void pa_format_info_set_prop_int_range(pa_format_info
*f
, const char *key
, int min
, int max
) {
576 o
= json_object_new_object();
578 json_object_object_add(o
, PA_JSON_MIN_KEY
, json_object_new_int(min
));
579 json_object_object_add(o
, PA_JSON_MAX_KEY
, json_object_new_int(max
));
581 pa_proplist_sets(f
->plist
, key
, json_object_to_json_string(o
));
586 void pa_format_info_set_prop_string(pa_format_info
*f
, const char *key
, const char *value
) {
592 o
= json_object_new_string(value
);
594 pa_proplist_sets(f
->plist
, key
, json_object_to_json_string(o
));
599 void pa_format_info_set_prop_string_array(pa_format_info
*f
, const char *key
, const char **values
, int n_values
) {
606 o
= json_object_new_array();
608 for (i
= 0; i
< n_values
; i
++)
609 json_object_array_add(o
, json_object_new_string(values
[i
]));
611 pa_proplist_sets(f
->plist
, key
, json_object_to_json_string(o
));
616 static bool pa_json_is_fixed_type(json_object
*o
) {
617 switch(json_object_get_type(o
)) {
618 case json_type_object
:
619 case json_type_array
:
627 static int pa_json_value_equal(json_object
*o1
, json_object
*o2
) {
628 return (json_object_get_type(o1
) == json_object_get_type(o2
)) &&
629 pa_streq(json_object_to_json_string(o1
), json_object_to_json_string(o2
));
632 static int pa_format_info_prop_compatible(const char *one
, const char *two
) {
633 json_object
*o1
= NULL
, *o2
= NULL
;
636 o1
= json_tokener_parse(one
);
640 o2
= json_tokener_parse(two
);
644 /* We don't deal with both values being non-fixed - just because there is no immediate need (FIXME) */
645 pa_return_val_if_fail(pa_json_is_fixed_type(o1
) || pa_json_is_fixed_type(o2
), false);
647 if (pa_json_is_fixed_type(o1
) && pa_json_is_fixed_type(o2
)) {
648 ret
= pa_json_value_equal(o1
, o2
);
652 if (pa_json_is_fixed_type(o1
)) {
653 json_object
*tmp
= o2
;
658 /* o2 is now a fixed type, and o1 is not */
660 if (json_object_get_type(o1
) == json_type_array
) {
661 for (i
= 0; i
< json_object_array_length(o1
); i
++) {
662 if (pa_json_value_equal(json_object_array_get_idx(o1
, i
), o2
)) {
667 } else if (json_object_get_type(o1
) == json_type_object
) {
668 /* o1 should be a range type */
670 json_object
*o_min
= NULL
, *o_max
= NULL
;
672 if (json_object_get_type(o2
) != json_type_int
) {
673 /* We don't support non-integer ranges */
677 o_min
= json_object_object_get(o1
, PA_JSON_MIN_KEY
);
678 if (!o_min
|| json_object_get_type(o_min
) != json_type_int
)
681 o_max
= json_object_object_get(o1
, PA_JSON_MAX_KEY
);
682 if (!o_max
|| json_object_get_type(o_max
) != json_type_int
)
685 v
= json_object_get_int(o2
);
686 min
= json_object_get_int(o_min
);
687 max
= json_object_get_int(o_max
);
689 ret
= v
>= min
&& v
<= max
;
691 pa_log_warn("Got a format type that we don't support");