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