Branch data Line data Source code
1 : : /***
2 : : This file is part of PulseAudio.
3 : :
4 : : Copyright 2011 Intel Corporation
5 : : Copyright 2011 Collabora Multimedia
6 : : Copyright 2011 Arun Raghavan <arun.raghavan@collabora.co.uk>
7 : :
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.
12 : :
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.
17 : :
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
21 : : USA.
22 : : ***/
23 : :
24 : : #ifdef HAVE_CONFIG_H
25 : : #include <config.h>
26 : : #endif
27 : :
28 : : #include <json.h>
29 : :
30 : : #include <pulse/internal.h>
31 : : #include <pulse/xmalloc.h>
32 : :
33 : : #include <pulsecore/core-util.h>
34 : : #include <pulsecore/i18n.h>
35 : : #include <pulsecore/macro.h>
36 : :
37 : : #include "format.h"
38 : :
39 : : #define PA_JSON_MIN_KEY "min"
40 : : #define PA_JSON_MAX_KEY "max"
41 : :
42 : : static int pa_format_info_prop_compatible(const char *one, const char *two);
43 : :
44 : : static const char* const _encoding_str_table[]= {
45 : : [PA_ENCODING_PCM] = "pcm",
46 : : [PA_ENCODING_AC3_IEC61937] = "ac3-iec61937",
47 : : [PA_ENCODING_EAC3_IEC61937] = "eac3-iec61937",
48 : : [PA_ENCODING_MPEG_IEC61937] = "mpeg-iec61937",
49 : : [PA_ENCODING_DTS_IEC61937] = "dts-iec61937",
50 : : [PA_ENCODING_ANY] = "any",
51 : : };
52 : :
53 : 0 : const char *pa_encoding_to_string(pa_encoding_t e) {
54 [ # # ]: 0 : if (e < 0 || e >= PA_ENCODING_MAX)
55 : : return NULL;
56 : :
57 : 0 : return _encoding_str_table[e];
58 : : }
59 : :
60 : 0 : pa_encoding_t pa_encoding_from_string(const char *encoding) {
61 : : pa_encoding_t e;
62 : :
63 [ # # ]: 0 : for (e = PA_ENCODING_ANY; e < PA_ENCODING_MAX; e++)
64 [ # # ]: 0 : if (pa_streq(_encoding_str_table[e], encoding))
65 : : return e;
66 : :
67 : : return PA_ENCODING_INVALID;
68 : : }
69 : :
70 : 18 : pa_format_info* pa_format_info_new(void) {
71 : 18 : pa_format_info *f = pa_xnew(pa_format_info, 1);
72 : :
73 : 18 : f->encoding = PA_ENCODING_INVALID;
74 : 18 : f->plist = pa_proplist_new();
75 : :
76 : 18 : return f;
77 : : }
78 : :
79 : 0 : pa_format_info* pa_format_info_copy(const pa_format_info *src) {
80 : : pa_format_info *dest;
81 : :
82 [ # # ]: 0 : pa_assert(src);
83 : :
84 : 0 : dest = pa_xnew(pa_format_info, 1);
85 : :
86 : 0 : dest->encoding = src->encoding;
87 : :
88 [ # # ]: 0 : if (src->plist)
89 : 0 : dest->plist = pa_proplist_copy(src->plist);
90 : : else
91 : 0 : dest->plist = NULL;
92 : :
93 : 0 : return dest;
94 : : }
95 : :
96 : 18 : void pa_format_info_free(pa_format_info *f) {
97 [ - + ]: 18 : pa_assert(f);
98 : :
99 : 18 : pa_proplist_free(f->plist);
100 : 18 : pa_xfree(f);
101 : 18 : }
102 : :
103 : 0 : void pa_format_info_free2(pa_format_info *f, void *userdata) {
104 : 0 : pa_format_info_free(f);
105 : 0 : }
106 : :
107 : 0 : int pa_format_info_valid(const pa_format_info *f) {
108 [ # # ][ # # ]: 0 : return (f->encoding >= 0 && f->encoding < PA_ENCODING_MAX && f->plist != NULL);
109 : : }
110 : :
111 : 0 : int pa_format_info_is_pcm(const pa_format_info *f) {
112 : 0 : return f->encoding == PA_ENCODING_PCM;
113 : : }
114 : :
115 : 0 : char *pa_format_info_snprint(char *s, size_t l, const pa_format_info *f) {
116 : : char *tmp;
117 : :
118 [ # # ]: 0 : pa_assert(s);
119 [ # # ]: 0 : pa_assert(l > 0);
120 [ # # ]: 0 : pa_assert(f);
121 : :
122 : 0 : pa_init_i18n();
123 : :
124 [ # # ]: 0 : if (!pa_format_info_valid(f))
125 : 0 : pa_snprintf(s, l, _("(invalid)"));
126 : : else {
127 : 0 : tmp = pa_proplist_to_string_sep(f->plist, " ");
128 [ # # ]: 0 : if (tmp[0])
129 : 0 : pa_snprintf(s, l, "%s, %s", pa_encoding_to_string(f->encoding), tmp);
130 : : else
131 : 0 : pa_snprintf(s, l, "%s", pa_encoding_to_string(f->encoding));
132 : 0 : pa_xfree(tmp);
133 : : }
134 : :
135 : 0 : return s;
136 : : }
137 : :
138 : 0 : pa_format_info* pa_format_info_from_string(const char *str) {
139 : 0 : pa_format_info *f = pa_format_info_new();
140 : 0 : char *encoding = NULL, *properties = NULL;
141 : : size_t pos;
142 : :
143 [ # # ][ # # ]: 0 : pos = strcspn(str, ",");
[ # # ][ # # ]
144 : :
145 : 0 : encoding = pa_xstrndup(str, pos);
146 : 0 : f->encoding = pa_encoding_from_string(pa_strip(encoding));
147 [ # # ]: 0 : if (f->encoding == PA_ENCODING_INVALID)
148 : : goto error;
149 : :
150 [ # # ]: 0 : if (pos != strlen(str)) {
151 : : pa_proplist *plist;
152 : :
153 : 0 : properties = pa_xstrdup(&str[pos+1]);
154 : 0 : plist = pa_proplist_from_string(properties);
155 : :
156 [ # # ]: 0 : if (!plist)
157 : : goto error;
158 : :
159 : 0 : pa_proplist_free(f->plist);
160 : 0 : f->plist = plist;
161 : : }
162 : :
163 : : out:
164 [ # # ]: 0 : if (encoding)
165 : 0 : pa_xfree(encoding);
166 [ # # ]: 0 : if (properties)
167 : 0 : pa_xfree(properties);
168 : 0 : return f;
169 : :
170 : : error:
171 : 0 : pa_format_info_free(f);
172 : 0 : f = NULL;
173 : 0 : goto out;
174 : : }
175 : :
176 : 14 : int pa_format_info_is_compatible(pa_format_info *first, pa_format_info *second) {
177 : : const char *key;
178 : 14 : void *state = NULL;
179 : :
180 [ - + ]: 14 : pa_assert(first);
181 [ - + ]: 14 : pa_assert(second);
182 : :
183 [ + - ]: 14 : if (first->encoding != second->encoding)
184 : : return FALSE;
185 : :
186 [ + + ]: 28 : while ((key = pa_proplist_iterate(first->plist, &state))) {
187 : : const char *value_one, *value_two;
188 : :
189 : 14 : value_one = pa_proplist_gets(first->plist, key);
190 : 14 : value_two = pa_proplist_gets(second->plist, key);
191 : :
192 [ + - ][ + + ]: 28 : if (!value_two || !pa_format_info_prop_compatible(value_one, value_two))
193 : : return FALSE;
194 : : }
195 : :
196 : : return TRUE;
197 : : }
198 : :
199 : 0 : pa_format_info* pa_format_info_from_sample_spec(pa_sample_spec *ss, pa_channel_map *map) {
200 : : char cm[PA_CHANNEL_MAP_SNPRINT_MAX];
201 : : pa_format_info *f;
202 : :
203 [ # # ][ # # ]: 0 : pa_assert(ss && pa_sample_spec_valid(ss));
204 [ # # ][ # # ]: 0 : pa_assert(!map || pa_channel_map_valid(map));
205 : :
206 : 0 : f = pa_format_info_new();
207 : 0 : f->encoding = PA_ENCODING_PCM;
208 : :
209 : 0 : pa_format_info_set_sample_format(f, ss->format);
210 : 0 : pa_format_info_set_rate(f, ss->rate);
211 : 0 : pa_format_info_set_channels(f, ss->channels);
212 : :
213 [ # # ]: 0 : if (map) {
214 : 0 : pa_channel_map_snprint(cm, sizeof(cm), map);
215 : 0 : pa_format_info_set_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, cm);
216 : : }
217 : :
218 : 0 : return f;
219 : : }
220 : :
221 : : /* For compressed streams */
222 : 0 : static int pa_format_info_to_sample_spec_fake(pa_format_info *f, pa_sample_spec *ss) {
223 : : int rate;
224 : :
225 [ # # ]: 0 : pa_assert(f);
226 [ # # ]: 0 : pa_assert(ss);
227 : :
228 : : /* Note: When we add support for non-IEC61937 encapsulated compressed
229 : : * formats, this function should return a non-zero values for these. */
230 : :
231 : 0 : ss->format = PA_SAMPLE_S16LE;
232 : 0 : ss->channels = 2;
233 : :
234 [ # # ]: 0 : pa_return_val_if_fail(pa_format_info_get_prop_int(f, PA_PROP_FORMAT_RATE, &rate) == 0, -PA_ERR_INVALID);
235 : 0 : ss->rate = (uint32_t) rate;
236 : :
237 [ # # ]: 0 : if (f->encoding == PA_ENCODING_EAC3_IEC61937)
238 : 0 : ss->rate *= 4;
239 : :
240 : : return 0;
241 : : }
242 : :
243 : : /* For PCM streams */
244 : 0 : int pa_format_info_to_sample_spec(pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map) {
245 : 0 : char *sf = NULL, *m = NULL;
246 : : int rate, channels;
247 : 0 : int ret = -PA_ERR_INVALID;
248 : :
249 [ # # ]: 0 : pa_assert(f);
250 [ # # ]: 0 : pa_assert(ss);
251 : :
252 [ # # ]: 0 : if (!pa_format_info_is_pcm(f))
253 : 0 : return pa_format_info_to_sample_spec_fake(f, ss);
254 : :
255 [ # # ]: 0 : if (pa_format_info_get_prop_string(f, PA_PROP_FORMAT_SAMPLE_FORMAT, &sf))
256 : : goto out;
257 [ # # ]: 0 : if (pa_format_info_get_prop_int(f, PA_PROP_FORMAT_RATE, &rate))
258 : : goto out;
259 [ # # ]: 0 : if (pa_format_info_get_prop_int(f, PA_PROP_FORMAT_CHANNELS, &channels))
260 : : goto out;
261 : :
262 [ # # ]: 0 : if ((ss->format = pa_parse_sample_format(sf)) == PA_SAMPLE_INVALID)
263 : : goto out;
264 : :
265 : 0 : ss->rate = (uint32_t) rate;
266 : 0 : ss->channels = (uint8_t) channels;
267 : :
268 [ # # ]: 0 : if (map) {
269 : 0 : pa_channel_map_init(map);
270 : :
271 [ # # ]: 0 : if (pa_format_info_get_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, &m) == 0)
272 [ # # ]: 0 : if (pa_channel_map_parse(map, m) == NULL)
273 : : goto out;
274 : : }
275 : :
276 : : ret = 0;
277 : :
278 : : out:
279 [ # # ]: 0 : if (sf)
280 : 0 : pa_xfree(sf);
281 [ # # ]: 0 : if (m)
282 : 0 : pa_xfree(m);
283 : :
284 : : return ret;
285 : : }
286 : :
287 : 5 : pa_prop_type_t pa_format_info_get_prop_type(pa_format_info *f, const char *key) {
288 : : const char *str;
289 : : json_object *o, *o1;
290 : : pa_prop_type_t type;
291 : :
292 [ - + ]: 5 : pa_assert(f);
293 [ - + ]: 5 : pa_assert(key);
294 : :
295 : 5 : str = pa_proplist_gets(f->plist, key);
296 [ + - ]: 5 : if (!str)
297 : : return PA_PROP_TYPE_INVALID;
298 : :
299 : 5 : o = json_tokener_parse(str);
300 [ + - ]: 5 : if (is_error(o))
301 : : return PA_PROP_TYPE_INVALID;
302 : :
303 [ + + + - : 5 : switch (json_object_get_type(o)) {
+ ]
304 : : case json_type_int:
305 : : type = PA_PROP_TYPE_INT;
306 : : break;
307 : :
308 : : case json_type_string:
309 : 1 : type = PA_PROP_TYPE_STRING;
310 : 1 : break;
311 : :
312 : : case json_type_array:
313 [ + - ]: 2 : if (json_object_array_length(o) == 0) {
314 : : /* Unlikely, but let's account for this anyway. We need at
315 : : * least one element to figure out the array type. */
316 : : type = PA_PROP_TYPE_INVALID;
317 : : break;
318 : : }
319 : :
320 : 2 : o1 = json_object_array_get_idx(o, 1);
321 : :
322 [ + + ]: 2 : if (json_object_get_type(o1) == json_type_int)
323 : : type = PA_PROP_TYPE_INT_ARRAY;
324 [ - + ]: 1 : else if (json_object_get_type(o1) == json_type_string)
325 : : type = PA_PROP_TYPE_STRING_ARRAY;
326 : : else
327 : 0 : type = PA_PROP_TYPE_INVALID;
328 : :
329 : 2 : json_object_put(o1);
330 : 2 : break;
331 : :
332 : : case json_type_object:
333 : : /* We actually know at this point that it's a int range, but let's
334 : : * confirm. */
335 : 1 : o1 = json_object_object_get(o, PA_JSON_MIN_KEY);
336 [ + - ]: 1 : if (!o1) {
337 : : type = PA_PROP_TYPE_INVALID;
338 : : break;
339 : : }
340 : 1 : json_object_put(o1);
341 : :
342 : 1 : o1 = json_object_object_get(o, PA_JSON_MAX_KEY);
343 [ + - ]: 1 : if (!o1) {
344 : : type = PA_PROP_TYPE_INVALID;
345 : : break;
346 : : }
347 : 1 : json_object_put(o1);
348 : :
349 : 1 : type = PA_PROP_TYPE_INT_RANGE;
350 : 1 : break;
351 : :
352 : : default:
353 : 0 : type = PA_PROP_TYPE_INVALID;
354 : 0 : break;
355 : : }
356 : :
357 : 5 : json_object_put(o);
358 : 5 : return type;
359 : : }
360 : :
361 : 1 : int pa_format_info_get_prop_int(pa_format_info *f, const char *key, int *v) {
362 : : const char *str;
363 : : json_object *o;
364 : :
365 [ - + ]: 1 : pa_assert(f);
366 [ - + ]: 1 : pa_assert(key);
367 [ - + ]: 1 : pa_assert(v);
368 : :
369 : 1 : str = pa_proplist_gets(f->plist, key);
370 [ + - ]: 1 : if (!str)
371 : : return -PA_ERR_NOENTITY;
372 : :
373 : 1 : o = json_tokener_parse(str);
374 [ + - ]: 1 : if (is_error(o))
375 : : return -PA_ERR_INVALID;
376 : :
377 [ - + ]: 1 : if (json_object_get_type(o) != json_type_int) {
378 : 0 : json_object_put(o);
379 : 0 : return -PA_ERR_INVALID;
380 : : }
381 : :
382 : 1 : *v = json_object_get_int(o);
383 : 1 : json_object_put(o);
384 : :
385 : 1 : return 0;
386 : : }
387 : :
388 : 1 : int pa_format_info_get_prop_int_range(pa_format_info *f, const char *key, int *min, int *max) {
389 : : const char *str;
390 : : json_object *o, *o1;
391 : 1 : int ret = -PA_ERR_INVALID;
392 : :
393 [ - + ]: 1 : pa_assert(f);
394 [ - + ]: 1 : pa_assert(key);
395 [ - + ]: 1 : pa_assert(min);
396 [ - + ]: 1 : pa_assert(max);
397 : :
398 : 1 : str = pa_proplist_gets(f->plist, key);
399 [ + - ]: 1 : if (!str)
400 : : return -PA_ERR_NOENTITY;
401 : :
402 : 1 : o = json_tokener_parse(str);
403 [ + - ]: 1 : if (is_error(o))
404 : : return -PA_ERR_INVALID;
405 : :
406 [ + - ]: 1 : if (json_object_get_type(o) != json_type_object)
407 : : goto out;
408 : :
409 [ + - ]: 1 : if (!(o1 = json_object_object_get(o, PA_JSON_MIN_KEY)))
410 : : goto out;
411 : :
412 : 1 : *min = json_object_get_int(o1);
413 : 1 : json_object_put(o1);
414 : :
415 [ + - ]: 1 : if (!(o1 = json_object_object_get(o, PA_JSON_MAX_KEY)))
416 : : goto out;
417 : :
418 : 1 : *max = json_object_get_int(o1);
419 : 1 : json_object_put(o1);
420 : :
421 : 1 : ret = 0;
422 : :
423 : : out:
424 : 1 : json_object_put(o);
425 : 1 : return ret;
426 : : }
427 : :
428 : 1 : int pa_format_info_get_prop_int_array(pa_format_info *f, const char *key, int **values, int *n_values)
429 : : {
430 : : const char *str;
431 : : json_object *o, *o1;
432 : 1 : int i, ret = -PA_ERR_INVALID;
433 : :
434 [ - + ]: 1 : pa_assert(f);
435 [ - + ]: 1 : pa_assert(key);
436 [ - + ]: 1 : pa_assert(values);
437 [ - + ]: 1 : pa_assert(n_values);
438 : :
439 : 1 : str = pa_proplist_gets(f->plist, key);
440 [ + - ]: 1 : if (!str)
441 : : return -PA_ERR_NOENTITY;
442 : :
443 : 1 : o = json_tokener_parse(str);
444 [ + - ]: 1 : if (is_error(o))
445 : : return -PA_ERR_INVALID;
446 : :
447 [ + - ]: 1 : if (json_object_get_type(o) != json_type_array)
448 : : goto out;
449 : :
450 : 1 : *n_values = json_object_array_length(o);
451 : 1 : *values = pa_xnew(int, *n_values);
452 : :
453 [ + + ]: 4 : for (i = 0; i < *n_values; i++) {
454 : 3 : o1 = json_object_array_get_idx(o, i);
455 : :
456 [ - + ]: 3 : if (json_object_get_type(o1) != json_type_int) {
457 : 0 : json_object_put(o1);
458 : 0 : goto out;
459 : : }
460 : :
461 : 3 : (*values)[i] = json_object_get_int(o1);
462 : 3 : json_object_put(o1);
463 : : }
464 : :
465 : : ret = 0;
466 : :
467 : : out:
468 : 1 : json_object_put(o);
469 : 1 : return ret;
470 : : }
471 : :
472 : 1 : int pa_format_info_get_prop_string(pa_format_info *f, const char *key, char **v) {
473 : 1 : const char *str = NULL;
474 : : json_object *o;
475 : :
476 [ - + ]: 1 : pa_assert(f);
477 [ - + ]: 1 : pa_assert(key);
478 [ - + ]: 1 : pa_assert(v);
479 : :
480 : 1 : str = pa_proplist_gets(f->plist, key);
481 [ + - ]: 1 : if (!str)
482 : : return -PA_ERR_NOENTITY;
483 : :
484 : 1 : o = json_tokener_parse(str);
485 [ + - ]: 1 : if (is_error(o))
486 : : return -PA_ERR_INVALID;
487 : :
488 [ - + ]: 1 : if (json_object_get_type(o) != json_type_string) {
489 : 0 : json_object_put(o);
490 : 0 : return -PA_ERR_INVALID;
491 : : }
492 : :
493 : 1 : *v = pa_xstrdup(json_object_get_string(o));
494 : 1 : json_object_put(o);
495 : :
496 : 1 : return 0;
497 : : }
498 : :
499 : 1 : int pa_format_info_get_prop_string_array(pa_format_info *f, const char *key, char ***values, int *n_values)
500 : : {
501 : : const char *str;
502 : : json_object *o, *o1;
503 : 1 : int i, ret = -PA_ERR_INVALID;
504 : :
505 [ - + ]: 1 : pa_assert(f);
506 [ - + ]: 1 : pa_assert(key);
507 [ - + ]: 1 : pa_assert(values);
508 [ - + ]: 1 : pa_assert(n_values);
509 : :
510 : 1 : str = pa_proplist_gets(f->plist, key);
511 [ + - ]: 1 : if (!str)
512 : : return -PA_ERR_NOENTITY;
513 : :
514 : 1 : o = json_tokener_parse(str);
515 [ + - ]: 1 : if (is_error(o))
516 : : return -PA_ERR_INVALID;
517 : :
518 [ + - ]: 1 : if (json_object_get_type(o) != json_type_array)
519 : : goto out;
520 : :
521 : 1 : *n_values = json_object_array_length(o);
522 : 1 : *values = pa_xnew(char *, *n_values);
523 : :
524 [ + + ]: 4 : for (i = 0; i < *n_values; i++) {
525 : 3 : o1 = json_object_array_get_idx(o, i);
526 : :
527 [ - + ]: 3 : if (json_object_get_type(o1) != json_type_string) {
528 : 0 : json_object_put(o1);
529 : 0 : goto out;
530 : : }
531 : :
532 : 3 : (*values)[i] = pa_xstrdup(json_object_get_string(o1));
533 : 3 : json_object_put(o1);
534 : : }
535 : :
536 : : ret = 0;
537 : :
538 : : out:
539 : 1 : json_object_put(o);
540 : 1 : return ret;
541 : : }
542 : :
543 : 1 : void pa_format_info_free_string_array(char **values, int n_values) {
544 : : int i;
545 : :
546 [ + + ]: 4 : for (i = 0; i < n_values; i++)
547 : 3 : pa_xfree(values[i]);
548 : :
549 : 1 : pa_xfree(values);
550 : 1 : }
551 : :
552 : 0 : void pa_format_info_set_sample_format(pa_format_info *f, pa_sample_format_t sf) {
553 : 0 : pa_format_info_set_prop_string(f, PA_PROP_FORMAT_SAMPLE_FORMAT, pa_sample_format_to_string(sf));
554 : 0 : }
555 : :
556 : 0 : void pa_format_info_set_rate(pa_format_info *f, int rate) {
557 : 0 : pa_format_info_set_prop_int(f, PA_PROP_FORMAT_RATE, rate);
558 : 0 : }
559 : :
560 : 0 : void pa_format_info_set_channels(pa_format_info *f, int channels) {
561 : 0 : pa_format_info_set_prop_int(f, PA_PROP_FORMAT_CHANNELS, channels);
562 : 0 : }
563 : :
564 : 0 : void pa_format_info_set_channel_map(pa_format_info *f, const pa_channel_map *map) {
565 : : char map_str[PA_CHANNEL_MAP_SNPRINT_MAX];
566 : :
567 : 0 : pa_channel_map_snprint(map_str, sizeof(map_str), map);
568 : :
569 : 0 : pa_format_info_set_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, map_str);
570 : 0 : }
571 : :
572 : 7 : void pa_format_info_set_prop_int(pa_format_info *f, const char *key, int value) {
573 : : json_object *o;
574 : :
575 [ - + ]: 7 : pa_assert(f);
576 [ - + ]: 7 : pa_assert(key);
577 : :
578 : 7 : o = json_object_new_int(value);
579 : :
580 : 7 : pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
581 : :
582 : 7 : json_object_put(o);
583 : 7 : }
584 : :
585 : 2 : void pa_format_info_set_prop_int_array(pa_format_info *f, const char *key, const int *values, int n_values) {
586 : : json_object *o;
587 : : int i;
588 : :
589 [ - + ]: 2 : pa_assert(f);
590 [ - + ]: 2 : pa_assert(key);
591 : :
592 : 2 : o = json_object_new_array();
593 : :
594 [ + + ]: 8 : for (i = 0; i < n_values; i++)
595 : 6 : json_object_array_add(o, json_object_new_int(values[i]));
596 : :
597 : 2 : pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
598 : :
599 : 2 : json_object_put(o);
600 : 2 : }
601 : :
602 : 2 : void pa_format_info_set_prop_int_range(pa_format_info *f, const char *key, int min, int max) {
603 : : json_object *o;
604 : :
605 [ - + ]: 2 : pa_assert(f);
606 [ - + ]: 2 : pa_assert(key);
607 : :
608 : 2 : o = json_object_new_object();
609 : :
610 : 2 : json_object_object_add(o, PA_JSON_MIN_KEY, json_object_new_int(min));
611 : 2 : json_object_object_add(o, PA_JSON_MAX_KEY, json_object_new_int(max));
612 : :
613 : 2 : pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
614 : :
615 : 2 : json_object_put(o);
616 : 2 : }
617 : :
618 : 5 : void pa_format_info_set_prop_string(pa_format_info *f, const char *key, const char *value) {
619 : : json_object *o;
620 : :
621 [ - + ]: 5 : pa_assert(f);
622 [ - + ]: 5 : pa_assert(key);
623 : :
624 : 5 : o = json_object_new_string(value);
625 : :
626 : 5 : pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
627 : :
628 : 5 : json_object_put(o);
629 : 5 : }
630 : :
631 : 2 : void pa_format_info_set_prop_string_array(pa_format_info *f, const char *key, const char **values, int n_values) {
632 : : json_object *o;
633 : : int i;
634 : :
635 [ - + ]: 2 : pa_assert(f);
636 [ - + ]: 2 : pa_assert(key);
637 : :
638 : 2 : o = json_object_new_array();
639 : :
640 [ + + ]: 8 : for (i = 0; i < n_values; i++)
641 : 6 : json_object_array_add(o, json_object_new_string(values[i]));
642 : :
643 : 2 : pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
644 : :
645 : 2 : json_object_put(o);
646 : 2 : }
647 : :
648 : 54 : static pa_bool_t pa_json_is_fixed_type(json_object *o)
649 : : {
650 [ + + ]: 54 : switch(json_object_get_type(o)) {
651 : : case json_type_object:
652 : : case json_type_array:
653 : : return FALSE;
654 : :
655 : : default:
656 : : return TRUE;
657 : : }
658 : : }
659 : :
660 : 24 : static int pa_json_value_equal(json_object *o1, json_object *o2) {
661 [ + - + + ]: 48 : return (json_object_get_type(o1) == json_object_get_type(o2)) &&
662 : 24 : pa_streq(json_object_to_json_string(o1), json_object_to_json_string(o2));
663 : : }
664 : :
665 : 14 : static int pa_format_info_prop_compatible(const char *one, const char *two) {
666 : 14 : json_object *o1 = NULL, *o2 = NULL;
667 : 14 : int i, ret = 0;
668 : :
669 : 14 : o1 = json_tokener_parse(one);
670 [ + - ]: 14 : if (is_error(o1))
671 : : goto out;
672 : :
673 : 14 : o2 = json_tokener_parse(two);
674 [ + - ]: 14 : if (is_error(o2))
675 : : goto out;
676 : :
677 : : /* We don't deal with both values being non-fixed - just because there is no immediate need (FIXME) */
678 [ + + ][ - + ]: 14 : pa_return_val_if_fail(pa_json_is_fixed_type(o1) || pa_json_is_fixed_type(o2), FALSE);
679 : :
680 [ + + ][ + + ]: 14 : if (pa_json_is_fixed_type(o1) && pa_json_is_fixed_type(o2)) {
681 : 2 : ret = pa_json_value_equal(o1, o2);
682 : 2 : goto out;
683 : : }
684 : :
685 [ + + ]: 12 : if (pa_json_is_fixed_type(o1)) {
686 : 6 : json_object *tmp = o2;
687 : 6 : o2 = o1;
688 : 6 : o1 = tmp;
689 : : }
690 : :
691 : : /* o2 is now a fixed type, and o1 is not */
692 : :
693 [ + + ]: 12 : if (json_object_get_type(o1) == json_type_array) {
694 [ + + ]: 26 : for (i = 0; i < json_object_array_length(o1); i++) {
695 [ + + ]: 22 : if (pa_json_value_equal(json_object_array_get_idx(o1, i), o2)) {
696 : : ret = 1;
697 : : break;
698 : : }
699 : : }
700 [ + - ]: 4 : } else if (json_object_get_type(o1) == json_type_object) {
701 : : /* o1 should be a range type */
702 : : int min, max, v;
703 : 4 : json_object *o_min = NULL, *o_max = NULL;
704 : :
705 [ + - ]: 4 : if (json_object_get_type(o2) != json_type_int) {
706 : : /* We don't support non-integer ranges */
707 : : goto out;
708 : : }
709 : :
710 : 4 : o_min = json_object_object_get(o1, PA_JSON_MIN_KEY);
711 [ + - ][ + - ]: 4 : if (!o_min || json_object_get_type(o_min) != json_type_int)
712 : : goto out;
713 : :
714 : 4 : o_max = json_object_object_get(o1, PA_JSON_MAX_KEY);
715 [ + - ][ + - ]: 4 : if (!o_max || json_object_get_type(o_max) != json_type_int)
716 : : goto out;
717 : :
718 : 4 : v = json_object_get_int(o2);
719 : 4 : min = json_object_get_int(o_min);
720 : 4 : max = json_object_get_int(o_max);
721 : :
722 : 4 : ret = v >= min && v <= max;
723 : : } else {
724 : 0 : pa_log_warn("Got a format type that we don't support");
725 : : }
726 : :
727 : : out:
728 [ + - ]: 14 : if (o1)
729 : 14 : json_object_put(o1);
730 [ + - ]: 14 : if (o2)
731 : 14 : json_object_put(o2);
732 : :
733 : : return ret;
734 : : }
|