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
) {
221 int ret
= -PA_ERR_INVALID
;
226 if (!pa_format_info_is_pcm(f
))
227 return pa_format_info_to_sample_spec_fake(f
, ss
, map
);
229 if (pa_format_info_get_sample_format(f
, &ss
->format
) < 0)
231 if (pa_format_info_get_rate(f
, &ss
->rate
) < 0)
233 if (pa_format_info_get_channels(f
, &ss
->channels
) < 0)
235 if (map
&& pa_format_info_get_channel_map(f
, map
) < 0)
244 pa_prop_type_t
pa_format_info_get_prop_type(pa_format_info
*f
, const char *key
) {
252 str
= pa_proplist_gets(f
->plist
, key
);
254 return PA_PROP_TYPE_INVALID
;
256 o
= json_tokener_parse(str
);
258 return PA_PROP_TYPE_INVALID
;
260 switch (json_object_get_type(o
)) {
262 type
= PA_PROP_TYPE_INT
;
265 case json_type_string
:
266 type
= PA_PROP_TYPE_STRING
;
269 case json_type_array
:
270 if (json_object_array_length(o
) == 0) {
271 /* Unlikely, but let's account for this anyway. We need at
272 * least one element to figure out the array type. */
273 type
= PA_PROP_TYPE_INVALID
;
277 o1
= json_object_array_get_idx(o
, 1);
279 if (json_object_get_type(o1
) == json_type_int
)
280 type
= PA_PROP_TYPE_INT_ARRAY
;
281 else if (json_object_get_type(o1
) == json_type_string
)
282 type
= PA_PROP_TYPE_STRING_ARRAY
;
284 type
= PA_PROP_TYPE_INVALID
;
289 case json_type_object
:
290 /* We actually know at this point that it's a int range, but let's
292 o1
= json_object_object_get(o
, PA_JSON_MIN_KEY
);
294 type
= PA_PROP_TYPE_INVALID
;
299 o1
= json_object_object_get(o
, PA_JSON_MAX_KEY
);
301 type
= PA_PROP_TYPE_INVALID
;
306 type
= PA_PROP_TYPE_INT_RANGE
;
310 type
= PA_PROP_TYPE_INVALID
;
318 int pa_format_info_get_prop_int(pa_format_info
*f
, const char *key
, int *v
) {
326 str
= pa_proplist_gets(f
->plist
, key
);
328 return -PA_ERR_NOENTITY
;
330 o
= json_tokener_parse(str
);
332 return -PA_ERR_INVALID
;
334 if (json_object_get_type(o
) != json_type_int
) {
336 return -PA_ERR_INVALID
;
339 *v
= json_object_get_int(o
);
345 int pa_format_info_get_prop_int_range(pa_format_info
*f
, const char *key
, int *min
, int *max
) {
348 int ret
= -PA_ERR_INVALID
;
355 str
= pa_proplist_gets(f
->plist
, key
);
357 return -PA_ERR_NOENTITY
;
359 o
= json_tokener_parse(str
);
361 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
);
385 int pa_format_info_get_prop_int_array(pa_format_info
*f
, const char *key
, int **values
, int *n_values
) {
388 int i
, ret
= -PA_ERR_INVALID
;
395 str
= pa_proplist_gets(f
->plist
, key
);
397 return -PA_ERR_NOENTITY
;
399 o
= json_tokener_parse(str
);
401 return -PA_ERR_INVALID
;
403 if (json_object_get_type(o
) != json_type_array
)
406 *n_values
= json_object_array_length(o
);
407 *values
= pa_xnew(int, *n_values
);
409 for (i
= 0; i
< *n_values
; i
++) {
410 o1
= json_object_array_get_idx(o
, i
);
412 if (json_object_get_type(o1
) != json_type_int
) {
417 (*values
)[i
] = json_object_get_int(o1
);
428 int pa_format_info_get_prop_string(pa_format_info
*f
, const char *key
, char **v
) {
429 const char *str
= NULL
;
436 str
= pa_proplist_gets(f
->plist
, key
);
438 return -PA_ERR_NOENTITY
;
440 o
= json_tokener_parse(str
);
442 return -PA_ERR_INVALID
;
444 if (json_object_get_type(o
) != json_type_string
) {
446 return -PA_ERR_INVALID
;
449 *v
= pa_xstrdup(json_object_get_string(o
));
455 int pa_format_info_get_prop_string_array(pa_format_info
*f
, const char *key
, char ***values
, int *n_values
) {
458 int i
, ret
= -PA_ERR_INVALID
;
465 str
= pa_proplist_gets(f
->plist
, key
);
467 return -PA_ERR_NOENTITY
;
469 o
= json_tokener_parse(str
);
471 return -PA_ERR_INVALID
;
473 if (json_object_get_type(o
) != json_type_array
)
476 *n_values
= json_object_array_length(o
);
477 *values
= pa_xnew(char *, *n_values
);
479 for (i
= 0; i
< *n_values
; i
++) {
480 o1
= json_object_array_get_idx(o
, i
);
482 if (json_object_get_type(o1
) != json_type_string
) {
487 (*values
)[i
] = pa_xstrdup(json_object_get_string(o1
));
498 void pa_format_info_free_string_array(char **values
, int n_values
) {
501 for (i
= 0; i
< n_values
; i
++)
507 void pa_format_info_set_sample_format(pa_format_info
*f
, pa_sample_format_t sf
) {
508 pa_format_info_set_prop_string(f
, PA_PROP_FORMAT_SAMPLE_FORMAT
, pa_sample_format_to_string(sf
));
511 void pa_format_info_set_rate(pa_format_info
*f
, int rate
) {
512 pa_format_info_set_prop_int(f
, PA_PROP_FORMAT_RATE
, rate
);
515 void pa_format_info_set_channels(pa_format_info
*f
, int channels
) {
516 pa_format_info_set_prop_int(f
, PA_PROP_FORMAT_CHANNELS
, channels
);
519 void pa_format_info_set_channel_map(pa_format_info
*f
, const pa_channel_map
*map
) {
520 char map_str
[PA_CHANNEL_MAP_SNPRINT_MAX
];
522 pa_channel_map_snprint(map_str
, sizeof(map_str
), map
);
524 pa_format_info_set_prop_string(f
, PA_PROP_FORMAT_CHANNEL_MAP
, map_str
);
527 void pa_format_info_set_prop_int(pa_format_info
*f
, const char *key
, int value
) {
533 o
= json_object_new_int(value
);
535 pa_proplist_sets(f
->plist
, key
, json_object_to_json_string(o
));
540 void pa_format_info_set_prop_int_array(pa_format_info
*f
, const char *key
, const int *values
, int n_values
) {
547 o
= json_object_new_array();
549 for (i
= 0; i
< n_values
; i
++)
550 json_object_array_add(o
, json_object_new_int(values
[i
]));
552 pa_proplist_sets(f
->plist
, key
, json_object_to_json_string(o
));
557 void pa_format_info_set_prop_int_range(pa_format_info
*f
, const char *key
, int min
, int max
) {
563 o
= json_object_new_object();
565 json_object_object_add(o
, PA_JSON_MIN_KEY
, json_object_new_int(min
));
566 json_object_object_add(o
, PA_JSON_MAX_KEY
, json_object_new_int(max
));
568 pa_proplist_sets(f
->plist
, key
, json_object_to_json_string(o
));
573 void pa_format_info_set_prop_string(pa_format_info
*f
, const char *key
, const char *value
) {
579 o
= json_object_new_string(value
);
581 pa_proplist_sets(f
->plist
, key
, json_object_to_json_string(o
));
586 void pa_format_info_set_prop_string_array(pa_format_info
*f
, const char *key
, const char **values
, int n_values
) {
593 o
= json_object_new_array();
595 for (i
= 0; i
< n_values
; i
++)
596 json_object_array_add(o
, json_object_new_string(values
[i
]));
598 pa_proplist_sets(f
->plist
, key
, json_object_to_json_string(o
));
603 static bool pa_json_is_fixed_type(json_object
*o
) {
604 switch(json_object_get_type(o
)) {
605 case json_type_object
:
606 case json_type_array
:
614 static int pa_json_value_equal(json_object
*o1
, json_object
*o2
) {
615 return (json_object_get_type(o1
) == json_object_get_type(o2
)) &&
616 pa_streq(json_object_to_json_string(o1
), json_object_to_json_string(o2
));
619 static int pa_format_info_prop_compatible(const char *one
, const char *two
) {
620 json_object
*o1
= NULL
, *o2
= NULL
;
623 o1
= json_tokener_parse(one
);
627 o2
= json_tokener_parse(two
);
631 /* We don't deal with both values being non-fixed - just because there is no immediate need (FIXME) */
632 pa_return_val_if_fail(pa_json_is_fixed_type(o1
) || pa_json_is_fixed_type(o2
), false);
634 if (pa_json_is_fixed_type(o1
) && pa_json_is_fixed_type(o2
)) {
635 ret
= pa_json_value_equal(o1
, o2
);
639 if (pa_json_is_fixed_type(o1
)) {
640 json_object
*tmp
= o2
;
645 /* o2 is now a fixed type, and o1 is not */
647 if (json_object_get_type(o1
) == json_type_array
) {
648 for (i
= 0; i
< json_object_array_length(o1
); i
++) {
649 if (pa_json_value_equal(json_object_array_get_idx(o1
, i
), o2
)) {
654 } else if (json_object_get_type(o1
) == json_type_object
) {
655 /* o1 should be a range type */
657 json_object
*o_min
= NULL
, *o_max
= NULL
;
659 if (json_object_get_type(o2
) != json_type_int
) {
660 /* We don't support non-integer ranges */
664 o_min
= json_object_object_get(o1
, PA_JSON_MIN_KEY
);
665 if (!o_min
|| json_object_get_type(o_min
) != json_type_int
)
668 o_max
= json_object_object_get(o1
, PA_JSON_MAX_KEY
);
669 if (!o_max
|| json_object_get_type(o_max
) != json_type_int
)
672 v
= json_object_get_int(o2
);
673 min
= json_object_get_int(o_min
);
674 max
= json_object_get_int(o_max
);
676 ret
= v
>= min
&& v
<= max
;
678 pa_log_warn("Got a format type that we don't support");