xref: /third_party/pulseaudio/src/pulse/format.c (revision 53a5a1b3)
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
41static int pa_format_info_prop_compatible(const char *one, const char *two);
42
43static 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
55const 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
62pa_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
72pa_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
81pa_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
98void 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
105int pa_format_info_valid(const pa_format_info *f) {
106    return (f->encoding >= 0 && f->encoding < PA_ENCODING_MAX && f->plist != NULL);
107}
108
109int pa_format_info_is_pcm(const pa_format_info *f) {
110    return f->encoding == PA_ENCODING_PCM;
111}
112
113char *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
136pa_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
161out:
162    if (encoding)
163        pa_xfree(encoding);
164    if (properties)
165        pa_xfree(properties);
166    return f;
167
168error:
169    pa_format_info_free(f);
170    f = NULL;
171    goto out;
172}
173
174int 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
197pa_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 */
220int 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
239pa_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
309int 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
339int 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
377out:
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
385int 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
424out:
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
432int 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
462int 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
501out:
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
509void 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
518int 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
543int 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
564int 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
585int 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
607void 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
611void 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
615void 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
619void 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
627void 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
634void 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
657void 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
665void 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
672void 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
694static 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
705static 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
767out:
768    if (o1)
769        pa_json_object_free(o1);
770    if (o2)
771        pa_json_object_free(o2);
772
773    return ret;
774}
775