• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/json.h>
27 #include <pulse/internal.h>
28 #include <pulse/xmalloc.h>
29 
30 #include <pulsecore/core-format.h>
31 #include <pulsecore/core-util.h>
32 #include <pulsecore/i18n.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