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 char *sf
= NULL
, *m
= NULL
;
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_prop_string(f
, PA_PROP_FORMAT_SAMPLE_FORMAT
, &sf
))
233 if (pa_format_info_get_prop_int(f
, PA_PROP_FORMAT_RATE
, &rate
))
235 if (pa_format_info_get_prop_int(f
, PA_PROP_FORMAT_CHANNELS
, &channels
))
238 if ((ss
->format
= pa_parse_sample_format(sf
)) == PA_SAMPLE_INVALID
)
241 ss
->rate
= (uint32_t) rate
;
242 ss
->channels
= (uint8_t) channels
;
245 pa_channel_map_init(map
);
247 if (pa_format_info_get_prop_string(f
, PA_PROP_FORMAT_CHANNEL_MAP
, &m
) == 0)
248 if (pa_channel_map_parse(map
, m
) == NULL
)
263 pa_prop_type_t
pa_format_info_get_prop_type(pa_format_info
*f
, const char *key
) {
271 str
= pa_proplist_gets(f
->plist
, key
);
273 return PA_PROP_TYPE_INVALID
;
275 o
= json_tokener_parse(str
);
277 return PA_PROP_TYPE_INVALID
;
279 switch (json_object_get_type(o
)) {
281 type
= PA_PROP_TYPE_INT
;
284 case json_type_string
:
285 type
= PA_PROP_TYPE_STRING
;
288 case json_type_array
:
289 if (json_object_array_length(o
) == 0) {
290 /* Unlikely, but let's account for this anyway. We need at
291 * least one element to figure out the array type. */
292 type
= PA_PROP_TYPE_INVALID
;
296 o1
= json_object_array_get_idx(o
, 1);
298 if (json_object_get_type(o1
) == json_type_int
)
299 type
= PA_PROP_TYPE_INT_ARRAY
;
300 else if (json_object_get_type(o1
) == json_type_string
)
301 type
= PA_PROP_TYPE_STRING_ARRAY
;
303 type
= PA_PROP_TYPE_INVALID
;
308 case json_type_object
:
309 /* We actually know at this point that it's a int range, but let's
311 o1
= json_object_object_get(o
, PA_JSON_MIN_KEY
);
313 type
= PA_PROP_TYPE_INVALID
;
318 o1
= json_object_object_get(o
, PA_JSON_MAX_KEY
);
320 type
= PA_PROP_TYPE_INVALID
;
325 type
= PA_PROP_TYPE_INT_RANGE
;
329 type
= PA_PROP_TYPE_INVALID
;
337 int pa_format_info_get_prop_int(pa_format_info
*f
, const char *key
, int *v
) {
345 str
= pa_proplist_gets(f
->plist
, key
);
347 return -PA_ERR_NOENTITY
;
349 o
= json_tokener_parse(str
);
351 return -PA_ERR_INVALID
;
353 if (json_object_get_type(o
) != json_type_int
) {
355 return -PA_ERR_INVALID
;
358 *v
= json_object_get_int(o
);
364 int pa_format_info_get_prop_int_range(pa_format_info
*f
, const char *key
, int *min
, int *max
) {
367 int ret
= -PA_ERR_INVALID
;
374 str
= pa_proplist_gets(f
->plist
, key
);
376 return -PA_ERR_NOENTITY
;
378 o
= json_tokener_parse(str
);
380 return -PA_ERR_INVALID
;
382 if (json_object_get_type(o
) != json_type_object
)
385 if (!(o1
= json_object_object_get(o
, PA_JSON_MIN_KEY
)))
388 *min
= json_object_get_int(o1
);
391 if (!(o1
= json_object_object_get(o
, PA_JSON_MAX_KEY
)))
394 *max
= json_object_get_int(o1
);
404 int pa_format_info_get_prop_int_array(pa_format_info
*f
, const char *key
, int **values
, int *n_values
) {
407 int i
, ret
= -PA_ERR_INVALID
;
414 str
= pa_proplist_gets(f
->plist
, key
);
416 return -PA_ERR_NOENTITY
;
418 o
= json_tokener_parse(str
);
420 return -PA_ERR_INVALID
;
422 if (json_object_get_type(o
) != json_type_array
)
425 *n_values
= json_object_array_length(o
);
426 *values
= pa_xnew(int, *n_values
);
428 for (i
= 0; i
< *n_values
; i
++) {
429 o1
= json_object_array_get_idx(o
, i
);
431 if (json_object_get_type(o1
) != json_type_int
) {
436 (*values
)[i
] = json_object_get_int(o1
);
447 int pa_format_info_get_prop_string(pa_format_info
*f
, const char *key
, char **v
) {
448 const char *str
= NULL
;
455 str
= pa_proplist_gets(f
->plist
, key
);
457 return -PA_ERR_NOENTITY
;
459 o
= json_tokener_parse(str
);
461 return -PA_ERR_INVALID
;
463 if (json_object_get_type(o
) != json_type_string
) {
465 return -PA_ERR_INVALID
;
468 *v
= pa_xstrdup(json_object_get_string(o
));
474 int pa_format_info_get_prop_string_array(pa_format_info
*f
, const char *key
, char ***values
, int *n_values
) {
477 int i
, ret
= -PA_ERR_INVALID
;
484 str
= pa_proplist_gets(f
->plist
, key
);
486 return -PA_ERR_NOENTITY
;
488 o
= json_tokener_parse(str
);
490 return -PA_ERR_INVALID
;
492 if (json_object_get_type(o
) != json_type_array
)
495 *n_values
= json_object_array_length(o
);
496 *values
= pa_xnew(char *, *n_values
);
498 for (i
= 0; i
< *n_values
; i
++) {
499 o1
= json_object_array_get_idx(o
, i
);
501 if (json_object_get_type(o1
) != json_type_string
) {
506 (*values
)[i
] = pa_xstrdup(json_object_get_string(o1
));
517 void pa_format_info_free_string_array(char **values
, int n_values
) {
520 for (i
= 0; i
< n_values
; i
++)
526 void pa_format_info_set_sample_format(pa_format_info
*f
, pa_sample_format_t sf
) {
527 pa_format_info_set_prop_string(f
, PA_PROP_FORMAT_SAMPLE_FORMAT
, pa_sample_format_to_string(sf
));
530 void pa_format_info_set_rate(pa_format_info
*f
, int rate
) {
531 pa_format_info_set_prop_int(f
, PA_PROP_FORMAT_RATE
, rate
);
534 void pa_format_info_set_channels(pa_format_info
*f
, int channels
) {
535 pa_format_info_set_prop_int(f
, PA_PROP_FORMAT_CHANNELS
, channels
);
538 void pa_format_info_set_channel_map(pa_format_info
*f
, const pa_channel_map
*map
) {
539 char map_str
[PA_CHANNEL_MAP_SNPRINT_MAX
];
541 pa_channel_map_snprint(map_str
, sizeof(map_str
), map
);
543 pa_format_info_set_prop_string(f
, PA_PROP_FORMAT_CHANNEL_MAP
, map_str
);
546 void pa_format_info_set_prop_int(pa_format_info
*f
, const char *key
, int value
) {
552 o
= json_object_new_int(value
);
554 pa_proplist_sets(f
->plist
, key
, json_object_to_json_string(o
));
559 void pa_format_info_set_prop_int_array(pa_format_info
*f
, const char *key
, const int *values
, int n_values
) {
566 o
= json_object_new_array();
568 for (i
= 0; i
< n_values
; i
++)
569 json_object_array_add(o
, json_object_new_int(values
[i
]));
571 pa_proplist_sets(f
->plist
, key
, json_object_to_json_string(o
));
576 void pa_format_info_set_prop_int_range(pa_format_info
*f
, const char *key
, int min
, int max
) {
582 o
= json_object_new_object();
584 json_object_object_add(o
, PA_JSON_MIN_KEY
, json_object_new_int(min
));
585 json_object_object_add(o
, PA_JSON_MAX_KEY
, json_object_new_int(max
));
587 pa_proplist_sets(f
->plist
, key
, json_object_to_json_string(o
));
592 void pa_format_info_set_prop_string(pa_format_info
*f
, const char *key
, const char *value
) {
598 o
= json_object_new_string(value
);
600 pa_proplist_sets(f
->plist
, key
, json_object_to_json_string(o
));
605 void pa_format_info_set_prop_string_array(pa_format_info
*f
, const char *key
, const char **values
, int n_values
) {
612 o
= json_object_new_array();
614 for (i
= 0; i
< n_values
; i
++)
615 json_object_array_add(o
, json_object_new_string(values
[i
]));
617 pa_proplist_sets(f
->plist
, key
, json_object_to_json_string(o
));
622 static bool pa_json_is_fixed_type(json_object
*o
) {
623 switch(json_object_get_type(o
)) {
624 case json_type_object
:
625 case json_type_array
:
633 static int pa_json_value_equal(json_object
*o1
, json_object
*o2
) {
634 return (json_object_get_type(o1
) == json_object_get_type(o2
)) &&
635 pa_streq(json_object_to_json_string(o1
), json_object_to_json_string(o2
));
638 static int pa_format_info_prop_compatible(const char *one
, const char *two
) {
639 json_object
*o1
= NULL
, *o2
= NULL
;
642 o1
= json_tokener_parse(one
);
646 o2
= json_tokener_parse(two
);
650 /* We don't deal with both values being non-fixed - just because there is no immediate need (FIXME) */
651 pa_return_val_if_fail(pa_json_is_fixed_type(o1
) || pa_json_is_fixed_type(o2
), false);
653 if (pa_json_is_fixed_type(o1
) && pa_json_is_fixed_type(o2
)) {
654 ret
= pa_json_value_equal(o1
, o2
);
658 if (pa_json_is_fixed_type(o1
)) {
659 json_object
*tmp
= o2
;
664 /* o2 is now a fixed type, and o1 is not */
666 if (json_object_get_type(o1
) == json_type_array
) {
667 for (i
= 0; i
< json_object_array_length(o1
); i
++) {
668 if (pa_json_value_equal(json_object_array_get_idx(o1
, i
), o2
)) {
673 } else if (json_object_get_type(o1
) == json_type_object
) {
674 /* o1 should be a range type */
676 json_object
*o_min
= NULL
, *o_max
= NULL
;
678 if (json_object_get_type(o2
) != json_type_int
) {
679 /* We don't support non-integer ranges */
683 o_min
= json_object_object_get(o1
, PA_JSON_MIN_KEY
);
684 if (!o_min
|| json_object_get_type(o_min
) != json_type_int
)
687 o_max
= json_object_object_get(o1
, PA_JSON_MAX_KEY
);
688 if (!o_max
|| json_object_get_type(o_max
) != json_type_int
)
691 v
= json_object_get_int(o2
);
692 min
= json_object_get_int(o_min
);
693 max
= json_object_get_int(o_max
);
695 ret
= v
>= min
&& v
<= max
;
697 pa_log_warn("Got a format type that we don't support");