153a5a1b3Sopenharmony_ci/***
253a5a1b3Sopenharmony_ci  This file is part of PulseAudio.
353a5a1b3Sopenharmony_ci
453a5a1b3Sopenharmony_ci  Copyright 2011 Intel Corporation
553a5a1b3Sopenharmony_ci  Copyright 2011 Collabora Multimedia
653a5a1b3Sopenharmony_ci  Copyright 2011 Arun Raghavan <arun.raghavan@collabora.co.uk>
753a5a1b3Sopenharmony_ci
853a5a1b3Sopenharmony_ci  PulseAudio is free software; you can redistribute it and/or modify
953a5a1b3Sopenharmony_ci  it under the terms of the GNU Lesser General Public License as published
1053a5a1b3Sopenharmony_ci  by the Free Software Foundation; either version 2.1 of the License,
1153a5a1b3Sopenharmony_ci  or (at your option) any later version.
1253a5a1b3Sopenharmony_ci
1353a5a1b3Sopenharmony_ci  PulseAudio is distributed in the hope that it will be useful, but
1453a5a1b3Sopenharmony_ci  WITHOUT ANY WARRANTY; without even the implied warranty of
1553a5a1b3Sopenharmony_ci  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1653a5a1b3Sopenharmony_ci  General Public License for more details.
1753a5a1b3Sopenharmony_ci
1853a5a1b3Sopenharmony_ci  You should have received a copy of the GNU Lesser General Public License
1953a5a1b3Sopenharmony_ci  along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
2053a5a1b3Sopenharmony_ci***/
2153a5a1b3Sopenharmony_ci
2253a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H
2353a5a1b3Sopenharmony_ci#include <config.h>
2453a5a1b3Sopenharmony_ci#endif
2553a5a1b3Sopenharmony_ci
2653a5a1b3Sopenharmony_ci#include <pulse/internal.h>
2753a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h>
2853a5a1b3Sopenharmony_ci
2953a5a1b3Sopenharmony_ci#include <pulsecore/core-format.h>
3053a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h>
3153a5a1b3Sopenharmony_ci#include <pulsecore/i18n.h>
3253a5a1b3Sopenharmony_ci#include <pulsecore/json.h>
3353a5a1b3Sopenharmony_ci#include <pulsecore/macro.h>
3453a5a1b3Sopenharmony_ci#include <pulsecore/strbuf.h>
3553a5a1b3Sopenharmony_ci
3653a5a1b3Sopenharmony_ci#include "format.h"
3753a5a1b3Sopenharmony_ci
3853a5a1b3Sopenharmony_ci#define PA_JSON_MIN_KEY "min"
3953a5a1b3Sopenharmony_ci#define PA_JSON_MAX_KEY "max"
4053a5a1b3Sopenharmony_ci
4153a5a1b3Sopenharmony_cistatic int pa_format_info_prop_compatible(const char *one, const char *two);
4253a5a1b3Sopenharmony_ci
4353a5a1b3Sopenharmony_cistatic const char* const _encoding_str_table[]= {
4453a5a1b3Sopenharmony_ci    [PA_ENCODING_PCM] = "pcm",
4553a5a1b3Sopenharmony_ci    [PA_ENCODING_AC3_IEC61937] = "ac3-iec61937",
4653a5a1b3Sopenharmony_ci    [PA_ENCODING_EAC3_IEC61937] = "eac3-iec61937",
4753a5a1b3Sopenharmony_ci    [PA_ENCODING_MPEG_IEC61937] = "mpeg-iec61937",
4853a5a1b3Sopenharmony_ci    [PA_ENCODING_DTS_IEC61937] = "dts-iec61937",
4953a5a1b3Sopenharmony_ci    [PA_ENCODING_MPEG2_AAC_IEC61937] = "mpeg2-aac-iec61937",
5053a5a1b3Sopenharmony_ci    [PA_ENCODING_TRUEHD_IEC61937] = "truehd-iec61937",
5153a5a1b3Sopenharmony_ci    [PA_ENCODING_DTSHD_IEC61937] = "dtshd-iec61937",
5253a5a1b3Sopenharmony_ci    [PA_ENCODING_ANY] = "any",
5353a5a1b3Sopenharmony_ci};
5453a5a1b3Sopenharmony_ci
5553a5a1b3Sopenharmony_ciconst char *pa_encoding_to_string(pa_encoding_t e) {
5653a5a1b3Sopenharmony_ci    if (e < 0 || e >= PA_ENCODING_MAX)
5753a5a1b3Sopenharmony_ci        return NULL;
5853a5a1b3Sopenharmony_ci
5953a5a1b3Sopenharmony_ci    return _encoding_str_table[e];
6053a5a1b3Sopenharmony_ci}
6153a5a1b3Sopenharmony_ci
6253a5a1b3Sopenharmony_cipa_encoding_t pa_encoding_from_string(const char *encoding) {
6353a5a1b3Sopenharmony_ci    pa_encoding_t e;
6453a5a1b3Sopenharmony_ci
6553a5a1b3Sopenharmony_ci    for (e = PA_ENCODING_ANY; e < PA_ENCODING_MAX; e++)
6653a5a1b3Sopenharmony_ci        if (pa_streq(_encoding_str_table[e], encoding))
6753a5a1b3Sopenharmony_ci            return e;
6853a5a1b3Sopenharmony_ci
6953a5a1b3Sopenharmony_ci    return PA_ENCODING_INVALID;
7053a5a1b3Sopenharmony_ci}
7153a5a1b3Sopenharmony_ci
7253a5a1b3Sopenharmony_cipa_format_info* pa_format_info_new(void) {
7353a5a1b3Sopenharmony_ci    pa_format_info *f = pa_xnew(pa_format_info, 1);
7453a5a1b3Sopenharmony_ci
7553a5a1b3Sopenharmony_ci    f->encoding = PA_ENCODING_INVALID;
7653a5a1b3Sopenharmony_ci    f->plist = pa_proplist_new();
7753a5a1b3Sopenharmony_ci
7853a5a1b3Sopenharmony_ci    return f;
7953a5a1b3Sopenharmony_ci}
8053a5a1b3Sopenharmony_ci
8153a5a1b3Sopenharmony_cipa_format_info* pa_format_info_copy(const pa_format_info *src) {
8253a5a1b3Sopenharmony_ci    pa_format_info *dest;
8353a5a1b3Sopenharmony_ci
8453a5a1b3Sopenharmony_ci    pa_assert(src);
8553a5a1b3Sopenharmony_ci
8653a5a1b3Sopenharmony_ci    dest = pa_xnew(pa_format_info, 1);
8753a5a1b3Sopenharmony_ci
8853a5a1b3Sopenharmony_ci    dest->encoding = src->encoding;
8953a5a1b3Sopenharmony_ci
9053a5a1b3Sopenharmony_ci    if (src->plist)
9153a5a1b3Sopenharmony_ci        dest->plist = pa_proplist_copy(src->plist);
9253a5a1b3Sopenharmony_ci    else
9353a5a1b3Sopenharmony_ci        dest->plist = NULL;
9453a5a1b3Sopenharmony_ci
9553a5a1b3Sopenharmony_ci    return dest;
9653a5a1b3Sopenharmony_ci}
9753a5a1b3Sopenharmony_ci
9853a5a1b3Sopenharmony_civoid pa_format_info_free(pa_format_info *f) {
9953a5a1b3Sopenharmony_ci    pa_assert(f);
10053a5a1b3Sopenharmony_ci
10153a5a1b3Sopenharmony_ci    pa_proplist_free(f->plist);
10253a5a1b3Sopenharmony_ci    pa_xfree(f);
10353a5a1b3Sopenharmony_ci}
10453a5a1b3Sopenharmony_ci
10553a5a1b3Sopenharmony_ciint pa_format_info_valid(const pa_format_info *f) {
10653a5a1b3Sopenharmony_ci    return (f->encoding >= 0 && f->encoding < PA_ENCODING_MAX && f->plist != NULL);
10753a5a1b3Sopenharmony_ci}
10853a5a1b3Sopenharmony_ci
10953a5a1b3Sopenharmony_ciint pa_format_info_is_pcm(const pa_format_info *f) {
11053a5a1b3Sopenharmony_ci    return f->encoding == PA_ENCODING_PCM;
11153a5a1b3Sopenharmony_ci}
11253a5a1b3Sopenharmony_ci
11353a5a1b3Sopenharmony_cichar *pa_format_info_snprint(char *s, size_t l, const pa_format_info *f) {
11453a5a1b3Sopenharmony_ci    char *tmp;
11553a5a1b3Sopenharmony_ci
11653a5a1b3Sopenharmony_ci    pa_assert(s);
11753a5a1b3Sopenharmony_ci    pa_assert(l > 0);
11853a5a1b3Sopenharmony_ci    pa_assert(f);
11953a5a1b3Sopenharmony_ci
12053a5a1b3Sopenharmony_ci    pa_init_i18n();
12153a5a1b3Sopenharmony_ci
12253a5a1b3Sopenharmony_ci    if (!pa_format_info_valid(f))
12353a5a1b3Sopenharmony_ci        pa_snprintf(s, l, _("(invalid)"));
12453a5a1b3Sopenharmony_ci    else {
12553a5a1b3Sopenharmony_ci        tmp = pa_proplist_to_string_sep(f->plist, "  ");
12653a5a1b3Sopenharmony_ci        if (tmp[0])
12753a5a1b3Sopenharmony_ci            pa_snprintf(s, l, "%s, %s", pa_encoding_to_string(f->encoding), tmp);
12853a5a1b3Sopenharmony_ci        else
12953a5a1b3Sopenharmony_ci            pa_snprintf(s, l, "%s", pa_encoding_to_string(f->encoding));
13053a5a1b3Sopenharmony_ci        pa_xfree(tmp);
13153a5a1b3Sopenharmony_ci    }
13253a5a1b3Sopenharmony_ci
13353a5a1b3Sopenharmony_ci    return s;
13453a5a1b3Sopenharmony_ci}
13553a5a1b3Sopenharmony_ci
13653a5a1b3Sopenharmony_cipa_format_info* pa_format_info_from_string(const char *str) {
13753a5a1b3Sopenharmony_ci    pa_format_info *f = pa_format_info_new();
13853a5a1b3Sopenharmony_ci    char *encoding = NULL, *properties = NULL;
13953a5a1b3Sopenharmony_ci    size_t pos;
14053a5a1b3Sopenharmony_ci
14153a5a1b3Sopenharmony_ci    pos = strcspn(str, ",");
14253a5a1b3Sopenharmony_ci
14353a5a1b3Sopenharmony_ci    encoding = pa_xstrndup(str, pos);
14453a5a1b3Sopenharmony_ci    f->encoding = pa_encoding_from_string(pa_strip(encoding));
14553a5a1b3Sopenharmony_ci    if (f->encoding == PA_ENCODING_INVALID)
14653a5a1b3Sopenharmony_ci        goto error;
14753a5a1b3Sopenharmony_ci
14853a5a1b3Sopenharmony_ci    if (pos != strlen(str)) {
14953a5a1b3Sopenharmony_ci        pa_proplist *plist;
15053a5a1b3Sopenharmony_ci
15153a5a1b3Sopenharmony_ci        properties = pa_xstrdup(&str[pos+1]);
15253a5a1b3Sopenharmony_ci        plist = pa_proplist_from_string(properties);
15353a5a1b3Sopenharmony_ci
15453a5a1b3Sopenharmony_ci        if (!plist)
15553a5a1b3Sopenharmony_ci            goto error;
15653a5a1b3Sopenharmony_ci
15753a5a1b3Sopenharmony_ci        pa_proplist_free(f->plist);
15853a5a1b3Sopenharmony_ci        f->plist = plist;
15953a5a1b3Sopenharmony_ci    }
16053a5a1b3Sopenharmony_ci
16153a5a1b3Sopenharmony_ciout:
16253a5a1b3Sopenharmony_ci    if (encoding)
16353a5a1b3Sopenharmony_ci        pa_xfree(encoding);
16453a5a1b3Sopenharmony_ci    if (properties)
16553a5a1b3Sopenharmony_ci        pa_xfree(properties);
16653a5a1b3Sopenharmony_ci    return f;
16753a5a1b3Sopenharmony_ci
16853a5a1b3Sopenharmony_cierror:
16953a5a1b3Sopenharmony_ci    pa_format_info_free(f);
17053a5a1b3Sopenharmony_ci    f = NULL;
17153a5a1b3Sopenharmony_ci    goto out;
17253a5a1b3Sopenharmony_ci}
17353a5a1b3Sopenharmony_ci
17453a5a1b3Sopenharmony_ciint pa_format_info_is_compatible(const pa_format_info *first, const pa_format_info *second) {
17553a5a1b3Sopenharmony_ci    const char *key;
17653a5a1b3Sopenharmony_ci    void *state = NULL;
17753a5a1b3Sopenharmony_ci
17853a5a1b3Sopenharmony_ci    pa_assert(first);
17953a5a1b3Sopenharmony_ci    pa_assert(second);
18053a5a1b3Sopenharmony_ci
18153a5a1b3Sopenharmony_ci    if (first->encoding != second->encoding)
18253a5a1b3Sopenharmony_ci        return false;
18353a5a1b3Sopenharmony_ci
18453a5a1b3Sopenharmony_ci    while ((key = pa_proplist_iterate(first->plist, &state))) {
18553a5a1b3Sopenharmony_ci        const char *value_one, *value_two;
18653a5a1b3Sopenharmony_ci
18753a5a1b3Sopenharmony_ci        value_one = pa_proplist_gets(first->plist, key);
18853a5a1b3Sopenharmony_ci        value_two = pa_proplist_gets(second->plist, key);
18953a5a1b3Sopenharmony_ci
19053a5a1b3Sopenharmony_ci        if (!value_two || !pa_format_info_prop_compatible(value_one, value_two))
19153a5a1b3Sopenharmony_ci            return false;
19253a5a1b3Sopenharmony_ci    }
19353a5a1b3Sopenharmony_ci
19453a5a1b3Sopenharmony_ci    return true;
19553a5a1b3Sopenharmony_ci}
19653a5a1b3Sopenharmony_ci
19753a5a1b3Sopenharmony_cipa_format_info* pa_format_info_from_sample_spec(const pa_sample_spec *ss, const pa_channel_map *map) {
19853a5a1b3Sopenharmony_ci    char cm[PA_CHANNEL_MAP_SNPRINT_MAX];
19953a5a1b3Sopenharmony_ci    pa_format_info *f;
20053a5a1b3Sopenharmony_ci
20153a5a1b3Sopenharmony_ci    pa_assert(ss && pa_sample_spec_valid(ss));
20253a5a1b3Sopenharmony_ci    pa_assert(!map || pa_channel_map_valid(map));
20353a5a1b3Sopenharmony_ci
20453a5a1b3Sopenharmony_ci    f = pa_format_info_new();
20553a5a1b3Sopenharmony_ci    f->encoding = PA_ENCODING_PCM;
20653a5a1b3Sopenharmony_ci
20753a5a1b3Sopenharmony_ci    pa_format_info_set_sample_format(f, ss->format);
20853a5a1b3Sopenharmony_ci    pa_format_info_set_rate(f, ss->rate);
20953a5a1b3Sopenharmony_ci    pa_format_info_set_channels(f, ss->channels);
21053a5a1b3Sopenharmony_ci
21153a5a1b3Sopenharmony_ci    if (map) {
21253a5a1b3Sopenharmony_ci        pa_channel_map_snprint(cm, sizeof(cm), map);
21353a5a1b3Sopenharmony_ci        pa_format_info_set_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, cm);
21453a5a1b3Sopenharmony_ci    }
21553a5a1b3Sopenharmony_ci
21653a5a1b3Sopenharmony_ci    return f;
21753a5a1b3Sopenharmony_ci}
21853a5a1b3Sopenharmony_ci
21953a5a1b3Sopenharmony_ci/* For PCM streams */
22053a5a1b3Sopenharmony_ciint pa_format_info_to_sample_spec(const pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map) {
22153a5a1b3Sopenharmony_ci    pa_assert(f);
22253a5a1b3Sopenharmony_ci    pa_assert(ss);
22353a5a1b3Sopenharmony_ci
22453a5a1b3Sopenharmony_ci    if (!pa_format_info_is_pcm(f))
22553a5a1b3Sopenharmony_ci        return pa_format_info_to_sample_spec_fake(f, ss, map);
22653a5a1b3Sopenharmony_ci
22753a5a1b3Sopenharmony_ci    if (pa_format_info_get_sample_format(f, &ss->format) < 0)
22853a5a1b3Sopenharmony_ci        return -PA_ERR_INVALID;
22953a5a1b3Sopenharmony_ci    if (pa_format_info_get_rate(f, &ss->rate) < 0)
23053a5a1b3Sopenharmony_ci        return -PA_ERR_INVALID;
23153a5a1b3Sopenharmony_ci    if (pa_format_info_get_channels(f, &ss->channels) < 0)
23253a5a1b3Sopenharmony_ci        return -PA_ERR_INVALID;
23353a5a1b3Sopenharmony_ci    if (map && pa_format_info_get_channel_map(f, map) < 0)
23453a5a1b3Sopenharmony_ci        return -PA_ERR_INVALID;
23553a5a1b3Sopenharmony_ci
23653a5a1b3Sopenharmony_ci    return 0;
23753a5a1b3Sopenharmony_ci}
23853a5a1b3Sopenharmony_ci
23953a5a1b3Sopenharmony_cipa_prop_type_t pa_format_info_get_prop_type(const pa_format_info *f, const char *key) {
24053a5a1b3Sopenharmony_ci    const char *str;
24153a5a1b3Sopenharmony_ci    pa_json_object *o;
24253a5a1b3Sopenharmony_ci    const pa_json_object *o1;
24353a5a1b3Sopenharmony_ci    pa_prop_type_t type;
24453a5a1b3Sopenharmony_ci
24553a5a1b3Sopenharmony_ci    pa_assert(f);
24653a5a1b3Sopenharmony_ci    pa_assert(key);
24753a5a1b3Sopenharmony_ci
24853a5a1b3Sopenharmony_ci    str = pa_proplist_gets(f->plist, key);
24953a5a1b3Sopenharmony_ci    if (!str)
25053a5a1b3Sopenharmony_ci        return PA_PROP_TYPE_INVALID;
25153a5a1b3Sopenharmony_ci
25253a5a1b3Sopenharmony_ci    o = pa_json_parse(str);
25353a5a1b3Sopenharmony_ci    if (!o)
25453a5a1b3Sopenharmony_ci        return PA_PROP_TYPE_INVALID;
25553a5a1b3Sopenharmony_ci
25653a5a1b3Sopenharmony_ci    switch (pa_json_object_get_type(o)) {
25753a5a1b3Sopenharmony_ci        case PA_JSON_TYPE_INT:
25853a5a1b3Sopenharmony_ci            type = PA_PROP_TYPE_INT;
25953a5a1b3Sopenharmony_ci            break;
26053a5a1b3Sopenharmony_ci
26153a5a1b3Sopenharmony_ci        case PA_JSON_TYPE_STRING:
26253a5a1b3Sopenharmony_ci            type = PA_PROP_TYPE_STRING;
26353a5a1b3Sopenharmony_ci            break;
26453a5a1b3Sopenharmony_ci
26553a5a1b3Sopenharmony_ci        case PA_JSON_TYPE_ARRAY:
26653a5a1b3Sopenharmony_ci            if (pa_json_object_get_array_length(o) == 0) {
26753a5a1b3Sopenharmony_ci                /* Unlikely, but let's account for this anyway. We need at
26853a5a1b3Sopenharmony_ci                 * least one element to figure out the array type. */
26953a5a1b3Sopenharmony_ci                type = PA_PROP_TYPE_INVALID;
27053a5a1b3Sopenharmony_ci                break;
27153a5a1b3Sopenharmony_ci            }
27253a5a1b3Sopenharmony_ci
27353a5a1b3Sopenharmony_ci            o1 = pa_json_object_get_array_member(o, 0);
27453a5a1b3Sopenharmony_ci
27553a5a1b3Sopenharmony_ci            if (pa_json_object_get_type(o1) == PA_JSON_TYPE_INT)
27653a5a1b3Sopenharmony_ci                type = PA_PROP_TYPE_INT_ARRAY;
27753a5a1b3Sopenharmony_ci            else if (pa_json_object_get_type(o1) == PA_JSON_TYPE_STRING)
27853a5a1b3Sopenharmony_ci                type = PA_PROP_TYPE_STRING_ARRAY;
27953a5a1b3Sopenharmony_ci            else
28053a5a1b3Sopenharmony_ci                type = PA_PROP_TYPE_INVALID;
28153a5a1b3Sopenharmony_ci
28253a5a1b3Sopenharmony_ci            break;
28353a5a1b3Sopenharmony_ci
28453a5a1b3Sopenharmony_ci        case PA_JSON_TYPE_OBJECT:
28553a5a1b3Sopenharmony_ci            /* We actually know at this point that it's a int range, but let's
28653a5a1b3Sopenharmony_ci             * confirm. */
28753a5a1b3Sopenharmony_ci            if (!pa_json_object_get_object_member(o, PA_JSON_MIN_KEY)) {
28853a5a1b3Sopenharmony_ci                type = PA_PROP_TYPE_INVALID;
28953a5a1b3Sopenharmony_ci                break;
29053a5a1b3Sopenharmony_ci            }
29153a5a1b3Sopenharmony_ci
29253a5a1b3Sopenharmony_ci            if (!pa_json_object_get_object_member(o, PA_JSON_MAX_KEY)) {
29353a5a1b3Sopenharmony_ci                type = PA_PROP_TYPE_INVALID;
29453a5a1b3Sopenharmony_ci                break;
29553a5a1b3Sopenharmony_ci            }
29653a5a1b3Sopenharmony_ci
29753a5a1b3Sopenharmony_ci            type = PA_PROP_TYPE_INT_RANGE;
29853a5a1b3Sopenharmony_ci            break;
29953a5a1b3Sopenharmony_ci
30053a5a1b3Sopenharmony_ci        default:
30153a5a1b3Sopenharmony_ci            type = PA_PROP_TYPE_INVALID;
30253a5a1b3Sopenharmony_ci            break;
30353a5a1b3Sopenharmony_ci    }
30453a5a1b3Sopenharmony_ci
30553a5a1b3Sopenharmony_ci    pa_json_object_free(o);
30653a5a1b3Sopenharmony_ci    return type;
30753a5a1b3Sopenharmony_ci}
30853a5a1b3Sopenharmony_ci
30953a5a1b3Sopenharmony_ciint pa_format_info_get_prop_int(const pa_format_info *f, const char *key, int *v) {
31053a5a1b3Sopenharmony_ci    const char *str;
31153a5a1b3Sopenharmony_ci    pa_json_object *o;
31253a5a1b3Sopenharmony_ci
31353a5a1b3Sopenharmony_ci    pa_assert(f);
31453a5a1b3Sopenharmony_ci    pa_assert(key);
31553a5a1b3Sopenharmony_ci    pa_assert(v);
31653a5a1b3Sopenharmony_ci
31753a5a1b3Sopenharmony_ci    str = pa_proplist_gets(f->plist, key);
31853a5a1b3Sopenharmony_ci    if (!str)
31953a5a1b3Sopenharmony_ci        return -PA_ERR_NOENTITY;
32053a5a1b3Sopenharmony_ci
32153a5a1b3Sopenharmony_ci    o = pa_json_parse(str);
32253a5a1b3Sopenharmony_ci    if (!o) {
32353a5a1b3Sopenharmony_ci        pa_log_debug("Failed to parse format info property '%s'.", key);
32453a5a1b3Sopenharmony_ci        return -PA_ERR_INVALID;
32553a5a1b3Sopenharmony_ci    }
32653a5a1b3Sopenharmony_ci
32753a5a1b3Sopenharmony_ci    if (pa_json_object_get_type(o) != PA_JSON_TYPE_INT) {
32853a5a1b3Sopenharmony_ci        pa_log_debug("Format info property '%s' type is not int.", key);
32953a5a1b3Sopenharmony_ci        pa_json_object_free(o);
33053a5a1b3Sopenharmony_ci        return -PA_ERR_INVALID;
33153a5a1b3Sopenharmony_ci    }
33253a5a1b3Sopenharmony_ci
33353a5a1b3Sopenharmony_ci    *v = pa_json_object_get_int(o);
33453a5a1b3Sopenharmony_ci    pa_json_object_free(o);
33553a5a1b3Sopenharmony_ci
33653a5a1b3Sopenharmony_ci    return 0;
33753a5a1b3Sopenharmony_ci}
33853a5a1b3Sopenharmony_ci
33953a5a1b3Sopenharmony_ciint pa_format_info_get_prop_int_range(const pa_format_info *f, const char *key, int *min, int *max) {
34053a5a1b3Sopenharmony_ci    const char *str;
34153a5a1b3Sopenharmony_ci    pa_json_object *o;
34253a5a1b3Sopenharmony_ci    const pa_json_object *o1;
34353a5a1b3Sopenharmony_ci    int ret = -PA_ERR_INVALID;
34453a5a1b3Sopenharmony_ci
34553a5a1b3Sopenharmony_ci    pa_assert(f);
34653a5a1b3Sopenharmony_ci    pa_assert(key);
34753a5a1b3Sopenharmony_ci    pa_assert(min);
34853a5a1b3Sopenharmony_ci    pa_assert(max);
34953a5a1b3Sopenharmony_ci
35053a5a1b3Sopenharmony_ci    str = pa_proplist_gets(f->plist, key);
35153a5a1b3Sopenharmony_ci    if (!str)
35253a5a1b3Sopenharmony_ci        return -PA_ERR_NOENTITY;
35353a5a1b3Sopenharmony_ci
35453a5a1b3Sopenharmony_ci    o = pa_json_parse(str);
35553a5a1b3Sopenharmony_ci    if (!o) {
35653a5a1b3Sopenharmony_ci        pa_log_debug("Failed to parse format info property '%s'.", key);
35753a5a1b3Sopenharmony_ci        return -PA_ERR_INVALID;
35853a5a1b3Sopenharmony_ci    }
35953a5a1b3Sopenharmony_ci
36053a5a1b3Sopenharmony_ci    if (pa_json_object_get_type(o) != PA_JSON_TYPE_OBJECT)
36153a5a1b3Sopenharmony_ci        goto out;
36253a5a1b3Sopenharmony_ci
36353a5a1b3Sopenharmony_ci    if (!(o1 = pa_json_object_get_object_member(o, PA_JSON_MIN_KEY)) ||
36453a5a1b3Sopenharmony_ci            (pa_json_object_get_type(o1) != PA_JSON_TYPE_INT))
36553a5a1b3Sopenharmony_ci        goto out;
36653a5a1b3Sopenharmony_ci
36753a5a1b3Sopenharmony_ci    *min = pa_json_object_get_int(o1);
36853a5a1b3Sopenharmony_ci
36953a5a1b3Sopenharmony_ci    if (!(o1 = pa_json_object_get_object_member(o, PA_JSON_MAX_KEY)) ||
37053a5a1b3Sopenharmony_ci            (pa_json_object_get_type(o1) != PA_JSON_TYPE_INT))
37153a5a1b3Sopenharmony_ci        goto out;
37253a5a1b3Sopenharmony_ci
37353a5a1b3Sopenharmony_ci    *max = pa_json_object_get_int(o1);
37453a5a1b3Sopenharmony_ci
37553a5a1b3Sopenharmony_ci    ret = 0;
37653a5a1b3Sopenharmony_ci
37753a5a1b3Sopenharmony_ciout:
37853a5a1b3Sopenharmony_ci    if (ret < 0)
37953a5a1b3Sopenharmony_ci        pa_log_debug("Format info property '%s' is not a valid int range.", key);
38053a5a1b3Sopenharmony_ci
38153a5a1b3Sopenharmony_ci    pa_json_object_free(o);
38253a5a1b3Sopenharmony_ci    return ret;
38353a5a1b3Sopenharmony_ci}
38453a5a1b3Sopenharmony_ci
38553a5a1b3Sopenharmony_ciint pa_format_info_get_prop_int_array(const pa_format_info *f, const char *key, int **values, int *n_values) {
38653a5a1b3Sopenharmony_ci    const char *str;
38753a5a1b3Sopenharmony_ci    pa_json_object *o;
38853a5a1b3Sopenharmony_ci    const pa_json_object *o1;
38953a5a1b3Sopenharmony_ci    int i, ret = -PA_ERR_INVALID;
39053a5a1b3Sopenharmony_ci
39153a5a1b3Sopenharmony_ci    pa_assert(f);
39253a5a1b3Sopenharmony_ci    pa_assert(key);
39353a5a1b3Sopenharmony_ci    pa_assert(values);
39453a5a1b3Sopenharmony_ci    pa_assert(n_values);
39553a5a1b3Sopenharmony_ci
39653a5a1b3Sopenharmony_ci    str = pa_proplist_gets(f->plist, key);
39753a5a1b3Sopenharmony_ci    if (!str)
39853a5a1b3Sopenharmony_ci        return -PA_ERR_NOENTITY;
39953a5a1b3Sopenharmony_ci
40053a5a1b3Sopenharmony_ci    o = pa_json_parse(str);
40153a5a1b3Sopenharmony_ci    if (!o) {
40253a5a1b3Sopenharmony_ci        pa_log_debug("Failed to parse format info property '%s'.", key);
40353a5a1b3Sopenharmony_ci        return -PA_ERR_INVALID;
40453a5a1b3Sopenharmony_ci    }
40553a5a1b3Sopenharmony_ci
40653a5a1b3Sopenharmony_ci    if (pa_json_object_get_type(o) != PA_JSON_TYPE_ARRAY)
40753a5a1b3Sopenharmony_ci        goto out;
40853a5a1b3Sopenharmony_ci
40953a5a1b3Sopenharmony_ci    *n_values = pa_json_object_get_array_length(o);
41053a5a1b3Sopenharmony_ci    *values = pa_xnew(int, *n_values);
41153a5a1b3Sopenharmony_ci
41253a5a1b3Sopenharmony_ci    for (i = 0; i < *n_values; i++) {
41353a5a1b3Sopenharmony_ci        o1 = pa_json_object_get_array_member(o, i);
41453a5a1b3Sopenharmony_ci
41553a5a1b3Sopenharmony_ci        if (pa_json_object_get_type(o1) != PA_JSON_TYPE_INT) {
41653a5a1b3Sopenharmony_ci            goto out;
41753a5a1b3Sopenharmony_ci        }
41853a5a1b3Sopenharmony_ci
41953a5a1b3Sopenharmony_ci        (*values)[i] = pa_json_object_get_int(o1);
42053a5a1b3Sopenharmony_ci    }
42153a5a1b3Sopenharmony_ci
42253a5a1b3Sopenharmony_ci    ret = 0;
42353a5a1b3Sopenharmony_ci
42453a5a1b3Sopenharmony_ciout:
42553a5a1b3Sopenharmony_ci    if (ret < 0)
42653a5a1b3Sopenharmony_ci        pa_log_debug("Format info property '%s' is not a valid int array.", key);
42753a5a1b3Sopenharmony_ci
42853a5a1b3Sopenharmony_ci    pa_json_object_free(o);
42953a5a1b3Sopenharmony_ci    return ret;
43053a5a1b3Sopenharmony_ci}
43153a5a1b3Sopenharmony_ci
43253a5a1b3Sopenharmony_ciint pa_format_info_get_prop_string(const pa_format_info *f, const char *key, char **v) {
43353a5a1b3Sopenharmony_ci    const char *str = NULL;
43453a5a1b3Sopenharmony_ci    pa_json_object *o;
43553a5a1b3Sopenharmony_ci
43653a5a1b3Sopenharmony_ci    pa_assert(f);
43753a5a1b3Sopenharmony_ci    pa_assert(key);
43853a5a1b3Sopenharmony_ci    pa_assert(v);
43953a5a1b3Sopenharmony_ci
44053a5a1b3Sopenharmony_ci    str = pa_proplist_gets(f->plist, key);
44153a5a1b3Sopenharmony_ci    if (!str)
44253a5a1b3Sopenharmony_ci        return -PA_ERR_NOENTITY;
44353a5a1b3Sopenharmony_ci
44453a5a1b3Sopenharmony_ci    o = pa_json_parse(str);
44553a5a1b3Sopenharmony_ci    if (!o) {
44653a5a1b3Sopenharmony_ci        pa_log_debug("Failed to parse format info property '%s'.", key);
44753a5a1b3Sopenharmony_ci        return -PA_ERR_INVALID;
44853a5a1b3Sopenharmony_ci    }
44953a5a1b3Sopenharmony_ci
45053a5a1b3Sopenharmony_ci    if (pa_json_object_get_type(o) != PA_JSON_TYPE_STRING) {
45153a5a1b3Sopenharmony_ci        pa_log_debug("Format info property '%s' type is not string.", key);
45253a5a1b3Sopenharmony_ci        pa_json_object_free(o);
45353a5a1b3Sopenharmony_ci        return -PA_ERR_INVALID;
45453a5a1b3Sopenharmony_ci    }
45553a5a1b3Sopenharmony_ci
45653a5a1b3Sopenharmony_ci    *v = pa_xstrdup(pa_json_object_get_string(o));
45753a5a1b3Sopenharmony_ci    pa_json_object_free(o);
45853a5a1b3Sopenharmony_ci
45953a5a1b3Sopenharmony_ci    return 0;
46053a5a1b3Sopenharmony_ci}
46153a5a1b3Sopenharmony_ci
46253a5a1b3Sopenharmony_ciint pa_format_info_get_prop_string_array(const pa_format_info *f, const char *key, char ***values, int *n_values) {
46353a5a1b3Sopenharmony_ci    const char *str;
46453a5a1b3Sopenharmony_ci    pa_json_object *o;
46553a5a1b3Sopenharmony_ci    const pa_json_object *o1;
46653a5a1b3Sopenharmony_ci    int i, ret = -PA_ERR_INVALID;
46753a5a1b3Sopenharmony_ci
46853a5a1b3Sopenharmony_ci    pa_assert(f);
46953a5a1b3Sopenharmony_ci    pa_assert(key);
47053a5a1b3Sopenharmony_ci    pa_assert(values);
47153a5a1b3Sopenharmony_ci    pa_assert(n_values);
47253a5a1b3Sopenharmony_ci
47353a5a1b3Sopenharmony_ci    str = pa_proplist_gets(f->plist, key);
47453a5a1b3Sopenharmony_ci    if (!str)
47553a5a1b3Sopenharmony_ci        return -PA_ERR_NOENTITY;
47653a5a1b3Sopenharmony_ci
47753a5a1b3Sopenharmony_ci    o = pa_json_parse(str);
47853a5a1b3Sopenharmony_ci    if (!o) {
47953a5a1b3Sopenharmony_ci        pa_log_debug("Failed to parse format info property '%s'.", key);
48053a5a1b3Sopenharmony_ci        return -PA_ERR_INVALID;
48153a5a1b3Sopenharmony_ci    }
48253a5a1b3Sopenharmony_ci
48353a5a1b3Sopenharmony_ci    if (pa_json_object_get_type(o) != PA_JSON_TYPE_ARRAY)
48453a5a1b3Sopenharmony_ci        goto out;
48553a5a1b3Sopenharmony_ci
48653a5a1b3Sopenharmony_ci    *n_values = pa_json_object_get_array_length(o);
48753a5a1b3Sopenharmony_ci    *values = pa_xnew(char *, *n_values);
48853a5a1b3Sopenharmony_ci
48953a5a1b3Sopenharmony_ci    for (i = 0; i < *n_values; i++) {
49053a5a1b3Sopenharmony_ci        o1 = pa_json_object_get_array_member(o, i);
49153a5a1b3Sopenharmony_ci
49253a5a1b3Sopenharmony_ci        if (pa_json_object_get_type(o1) != PA_JSON_TYPE_STRING) {
49353a5a1b3Sopenharmony_ci            goto out;
49453a5a1b3Sopenharmony_ci        }
49553a5a1b3Sopenharmony_ci
49653a5a1b3Sopenharmony_ci        (*values)[i] = pa_xstrdup(pa_json_object_get_string(o1));
49753a5a1b3Sopenharmony_ci    }
49853a5a1b3Sopenharmony_ci
49953a5a1b3Sopenharmony_ci    ret = 0;
50053a5a1b3Sopenharmony_ci
50153a5a1b3Sopenharmony_ciout:
50253a5a1b3Sopenharmony_ci    if (ret < 0)
50353a5a1b3Sopenharmony_ci        pa_log_debug("Format info property '%s' is not a valid string array.", key);
50453a5a1b3Sopenharmony_ci
50553a5a1b3Sopenharmony_ci    pa_json_object_free(o);
50653a5a1b3Sopenharmony_ci    return ret;
50753a5a1b3Sopenharmony_ci}
50853a5a1b3Sopenharmony_ci
50953a5a1b3Sopenharmony_civoid pa_format_info_free_string_array(char **values, int n_values) {
51053a5a1b3Sopenharmony_ci    int i;
51153a5a1b3Sopenharmony_ci
51253a5a1b3Sopenharmony_ci    for (i = 0; i < n_values; i++)
51353a5a1b3Sopenharmony_ci        pa_xfree(values[i]);
51453a5a1b3Sopenharmony_ci
51553a5a1b3Sopenharmony_ci    pa_xfree(values);
51653a5a1b3Sopenharmony_ci}
51753a5a1b3Sopenharmony_ci
51853a5a1b3Sopenharmony_ciint pa_format_info_get_sample_format(const pa_format_info *f, pa_sample_format_t *sf) {
51953a5a1b3Sopenharmony_ci    int r;
52053a5a1b3Sopenharmony_ci    char *sf_str;
52153a5a1b3Sopenharmony_ci    pa_sample_format_t sf_local;
52253a5a1b3Sopenharmony_ci
52353a5a1b3Sopenharmony_ci    pa_assert(f);
52453a5a1b3Sopenharmony_ci    pa_assert(sf);
52553a5a1b3Sopenharmony_ci
52653a5a1b3Sopenharmony_ci    r = pa_format_info_get_prop_string(f, PA_PROP_FORMAT_SAMPLE_FORMAT, &sf_str);
52753a5a1b3Sopenharmony_ci    if (r < 0)
52853a5a1b3Sopenharmony_ci        return r;
52953a5a1b3Sopenharmony_ci
53053a5a1b3Sopenharmony_ci    sf_local = pa_parse_sample_format(sf_str);
53153a5a1b3Sopenharmony_ci    pa_xfree(sf_str);
53253a5a1b3Sopenharmony_ci
53353a5a1b3Sopenharmony_ci    if (!pa_sample_format_valid(sf_local)) {
53453a5a1b3Sopenharmony_ci        pa_log_debug("Invalid sample format.");
53553a5a1b3Sopenharmony_ci        return -PA_ERR_INVALID;
53653a5a1b3Sopenharmony_ci    }
53753a5a1b3Sopenharmony_ci
53853a5a1b3Sopenharmony_ci    *sf = sf_local;
53953a5a1b3Sopenharmony_ci
54053a5a1b3Sopenharmony_ci    return 0;
54153a5a1b3Sopenharmony_ci}
54253a5a1b3Sopenharmony_ci
54353a5a1b3Sopenharmony_ciint pa_format_info_get_rate(const pa_format_info *f, uint32_t *rate) {
54453a5a1b3Sopenharmony_ci    int r;
54553a5a1b3Sopenharmony_ci    int rate_local;
54653a5a1b3Sopenharmony_ci
54753a5a1b3Sopenharmony_ci    pa_assert(f);
54853a5a1b3Sopenharmony_ci    pa_assert(rate);
54953a5a1b3Sopenharmony_ci
55053a5a1b3Sopenharmony_ci    r = pa_format_info_get_prop_int(f, PA_PROP_FORMAT_RATE, &rate_local);
55153a5a1b3Sopenharmony_ci    if (r < 0)
55253a5a1b3Sopenharmony_ci        return r;
55353a5a1b3Sopenharmony_ci
55453a5a1b3Sopenharmony_ci    if (!pa_sample_rate_valid(rate_local)) {
55553a5a1b3Sopenharmony_ci        pa_log_debug("Invalid sample rate: %i", rate_local);
55653a5a1b3Sopenharmony_ci        return -PA_ERR_INVALID;
55753a5a1b3Sopenharmony_ci    }
55853a5a1b3Sopenharmony_ci
55953a5a1b3Sopenharmony_ci    *rate = rate_local;
56053a5a1b3Sopenharmony_ci
56153a5a1b3Sopenharmony_ci    return 0;
56253a5a1b3Sopenharmony_ci}
56353a5a1b3Sopenharmony_ci
56453a5a1b3Sopenharmony_ciint pa_format_info_get_channels(const pa_format_info *f, uint8_t *channels) {
56553a5a1b3Sopenharmony_ci    int r;
56653a5a1b3Sopenharmony_ci    int channels_local;
56753a5a1b3Sopenharmony_ci
56853a5a1b3Sopenharmony_ci    pa_assert(f);
56953a5a1b3Sopenharmony_ci    pa_assert(channels);
57053a5a1b3Sopenharmony_ci
57153a5a1b3Sopenharmony_ci    r = pa_format_info_get_prop_int(f, PA_PROP_FORMAT_CHANNELS, &channels_local);
57253a5a1b3Sopenharmony_ci    if (r < 0)
57353a5a1b3Sopenharmony_ci        return r;
57453a5a1b3Sopenharmony_ci
57553a5a1b3Sopenharmony_ci    if (!pa_channels_valid(channels_local)) {
57653a5a1b3Sopenharmony_ci        pa_log_debug("Invalid channel count: %i", channels_local);
57753a5a1b3Sopenharmony_ci        return -PA_ERR_INVALID;
57853a5a1b3Sopenharmony_ci    }
57953a5a1b3Sopenharmony_ci
58053a5a1b3Sopenharmony_ci    *channels = channels_local;
58153a5a1b3Sopenharmony_ci
58253a5a1b3Sopenharmony_ci    return 0;
58353a5a1b3Sopenharmony_ci}
58453a5a1b3Sopenharmony_ci
58553a5a1b3Sopenharmony_ciint pa_format_info_get_channel_map(const pa_format_info *f, pa_channel_map *map) {
58653a5a1b3Sopenharmony_ci    int r;
58753a5a1b3Sopenharmony_ci    char *map_str;
58853a5a1b3Sopenharmony_ci
58953a5a1b3Sopenharmony_ci    pa_assert(f);
59053a5a1b3Sopenharmony_ci    pa_assert(map);
59153a5a1b3Sopenharmony_ci
59253a5a1b3Sopenharmony_ci    r = pa_format_info_get_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, &map_str);
59353a5a1b3Sopenharmony_ci    if (r < 0)
59453a5a1b3Sopenharmony_ci        return r;
59553a5a1b3Sopenharmony_ci
59653a5a1b3Sopenharmony_ci    map = pa_channel_map_parse(map, map_str);
59753a5a1b3Sopenharmony_ci    pa_xfree(map_str);
59853a5a1b3Sopenharmony_ci
59953a5a1b3Sopenharmony_ci    if (!map) {
60053a5a1b3Sopenharmony_ci        pa_log_debug("Failed to parse channel map.");
60153a5a1b3Sopenharmony_ci        return -PA_ERR_INVALID;
60253a5a1b3Sopenharmony_ci    }
60353a5a1b3Sopenharmony_ci
60453a5a1b3Sopenharmony_ci    return 0;
60553a5a1b3Sopenharmony_ci}
60653a5a1b3Sopenharmony_ci
60753a5a1b3Sopenharmony_civoid pa_format_info_set_sample_format(pa_format_info *f, pa_sample_format_t sf) {
60853a5a1b3Sopenharmony_ci    pa_format_info_set_prop_string(f, PA_PROP_FORMAT_SAMPLE_FORMAT, pa_sample_format_to_string(sf));
60953a5a1b3Sopenharmony_ci}
61053a5a1b3Sopenharmony_ci
61153a5a1b3Sopenharmony_civoid pa_format_info_set_rate(pa_format_info *f, int rate) {
61253a5a1b3Sopenharmony_ci    pa_format_info_set_prop_int(f, PA_PROP_FORMAT_RATE, rate);
61353a5a1b3Sopenharmony_ci}
61453a5a1b3Sopenharmony_ci
61553a5a1b3Sopenharmony_civoid pa_format_info_set_channels(pa_format_info *f, int channels) {
61653a5a1b3Sopenharmony_ci    pa_format_info_set_prop_int(f, PA_PROP_FORMAT_CHANNELS, channels);
61753a5a1b3Sopenharmony_ci}
61853a5a1b3Sopenharmony_ci
61953a5a1b3Sopenharmony_civoid pa_format_info_set_channel_map(pa_format_info *f, const pa_channel_map *map) {
62053a5a1b3Sopenharmony_ci    char map_str[PA_CHANNEL_MAP_SNPRINT_MAX];
62153a5a1b3Sopenharmony_ci
62253a5a1b3Sopenharmony_ci    pa_channel_map_snprint(map_str, sizeof(map_str), map);
62353a5a1b3Sopenharmony_ci
62453a5a1b3Sopenharmony_ci    pa_format_info_set_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, map_str);
62553a5a1b3Sopenharmony_ci}
62653a5a1b3Sopenharmony_ci
62753a5a1b3Sopenharmony_civoid pa_format_info_set_prop_int(pa_format_info *f, const char *key, int value) {
62853a5a1b3Sopenharmony_ci    pa_assert(f);
62953a5a1b3Sopenharmony_ci    pa_assert(key);
63053a5a1b3Sopenharmony_ci
63153a5a1b3Sopenharmony_ci    pa_proplist_setf(f->plist, key, "%d", value);
63253a5a1b3Sopenharmony_ci}
63353a5a1b3Sopenharmony_ci
63453a5a1b3Sopenharmony_civoid pa_format_info_set_prop_int_array(pa_format_info *f, const char *key, const int *values, int n_values) {
63553a5a1b3Sopenharmony_ci    pa_strbuf *buf;
63653a5a1b3Sopenharmony_ci    char *str;
63753a5a1b3Sopenharmony_ci    int i;
63853a5a1b3Sopenharmony_ci
63953a5a1b3Sopenharmony_ci    pa_assert(f);
64053a5a1b3Sopenharmony_ci    pa_assert(key);
64153a5a1b3Sopenharmony_ci    pa_assert(n_values > 0);
64253a5a1b3Sopenharmony_ci
64353a5a1b3Sopenharmony_ci    buf = pa_strbuf_new();
64453a5a1b3Sopenharmony_ci
64553a5a1b3Sopenharmony_ci    pa_strbuf_printf(buf, "[ %d", values[0]);
64653a5a1b3Sopenharmony_ci
64753a5a1b3Sopenharmony_ci    for (i = 1; i < n_values; i++)
64853a5a1b3Sopenharmony_ci        pa_strbuf_printf(buf, ", %d", values[i]);
64953a5a1b3Sopenharmony_ci
65053a5a1b3Sopenharmony_ci    pa_strbuf_printf(buf, " ]");
65153a5a1b3Sopenharmony_ci    str = pa_strbuf_to_string_free(buf);
65253a5a1b3Sopenharmony_ci
65353a5a1b3Sopenharmony_ci    pa_proplist_sets(f->plist, key, str);
65453a5a1b3Sopenharmony_ci    pa_xfree (str);
65553a5a1b3Sopenharmony_ci}
65653a5a1b3Sopenharmony_ci
65753a5a1b3Sopenharmony_civoid pa_format_info_set_prop_int_range(pa_format_info *f, const char *key, int min, int max) {
65853a5a1b3Sopenharmony_ci    pa_assert(f);
65953a5a1b3Sopenharmony_ci    pa_assert(key);
66053a5a1b3Sopenharmony_ci
66153a5a1b3Sopenharmony_ci    pa_proplist_setf(f->plist, key, "{ \"" PA_JSON_MIN_KEY "\": %d, \"" PA_JSON_MAX_KEY "\": %d }",
66253a5a1b3Sopenharmony_ci            min, max);
66353a5a1b3Sopenharmony_ci}
66453a5a1b3Sopenharmony_ci
66553a5a1b3Sopenharmony_civoid pa_format_info_set_prop_string(pa_format_info *f, const char *key, const char *value) {
66653a5a1b3Sopenharmony_ci    pa_assert(f);
66753a5a1b3Sopenharmony_ci    pa_assert(key);
66853a5a1b3Sopenharmony_ci
66953a5a1b3Sopenharmony_ci    pa_proplist_setf(f->plist, key, "\"%s\"", value);
67053a5a1b3Sopenharmony_ci}
67153a5a1b3Sopenharmony_ci
67253a5a1b3Sopenharmony_civoid pa_format_info_set_prop_string_array(pa_format_info *f, const char *key, const char **values, int n_values) {
67353a5a1b3Sopenharmony_ci    pa_strbuf *buf;
67453a5a1b3Sopenharmony_ci    char *str;
67553a5a1b3Sopenharmony_ci    int i;
67653a5a1b3Sopenharmony_ci
67753a5a1b3Sopenharmony_ci    pa_assert(f);
67853a5a1b3Sopenharmony_ci    pa_assert(key);
67953a5a1b3Sopenharmony_ci
68053a5a1b3Sopenharmony_ci    buf = pa_strbuf_new();
68153a5a1b3Sopenharmony_ci
68253a5a1b3Sopenharmony_ci    pa_strbuf_printf(buf, "[ \"%s\"", values[0]);
68353a5a1b3Sopenharmony_ci
68453a5a1b3Sopenharmony_ci    for (i = 1; i < n_values; i++)
68553a5a1b3Sopenharmony_ci        pa_strbuf_printf(buf, ", \"%s\"", values[i]);
68653a5a1b3Sopenharmony_ci
68753a5a1b3Sopenharmony_ci    pa_strbuf_printf(buf, " ]");
68853a5a1b3Sopenharmony_ci    str = pa_strbuf_to_string_free(buf);
68953a5a1b3Sopenharmony_ci
69053a5a1b3Sopenharmony_ci    pa_proplist_sets(f->plist, key, str);
69153a5a1b3Sopenharmony_ci    pa_xfree (str);
69253a5a1b3Sopenharmony_ci}
69353a5a1b3Sopenharmony_ci
69453a5a1b3Sopenharmony_cistatic bool pa_json_is_fixed_type(pa_json_object *o) {
69553a5a1b3Sopenharmony_ci    switch(pa_json_object_get_type(o)) {
69653a5a1b3Sopenharmony_ci        case PA_JSON_TYPE_OBJECT:
69753a5a1b3Sopenharmony_ci        case PA_JSON_TYPE_ARRAY:
69853a5a1b3Sopenharmony_ci            return false;
69953a5a1b3Sopenharmony_ci
70053a5a1b3Sopenharmony_ci        default:
70153a5a1b3Sopenharmony_ci            return true;
70253a5a1b3Sopenharmony_ci    }
70353a5a1b3Sopenharmony_ci}
70453a5a1b3Sopenharmony_ci
70553a5a1b3Sopenharmony_cistatic int pa_format_info_prop_compatible(const char *one, const char *two) {
70653a5a1b3Sopenharmony_ci    pa_json_object *o1 = NULL, *o2 = NULL;
70753a5a1b3Sopenharmony_ci    int i, ret = 0;
70853a5a1b3Sopenharmony_ci
70953a5a1b3Sopenharmony_ci    o1 = pa_json_parse(one);
71053a5a1b3Sopenharmony_ci    if (!o1)
71153a5a1b3Sopenharmony_ci        goto out;
71253a5a1b3Sopenharmony_ci
71353a5a1b3Sopenharmony_ci    o2 = pa_json_parse(two);
71453a5a1b3Sopenharmony_ci    if (!o2)
71553a5a1b3Sopenharmony_ci        goto out;
71653a5a1b3Sopenharmony_ci
71753a5a1b3Sopenharmony_ci    /* We don't deal with both values being non-fixed - just because there is no immediate need (FIXME) */
71853a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_json_is_fixed_type(o1) || pa_json_is_fixed_type(o2), false);
71953a5a1b3Sopenharmony_ci
72053a5a1b3Sopenharmony_ci    if (pa_json_is_fixed_type(o1) && pa_json_is_fixed_type(o2)) {
72153a5a1b3Sopenharmony_ci        ret = pa_json_object_equal(o1, o2);
72253a5a1b3Sopenharmony_ci        goto out;
72353a5a1b3Sopenharmony_ci    }
72453a5a1b3Sopenharmony_ci
72553a5a1b3Sopenharmony_ci    if (pa_json_is_fixed_type(o1)) {
72653a5a1b3Sopenharmony_ci        pa_json_object *tmp = o2;
72753a5a1b3Sopenharmony_ci        o2 = o1;
72853a5a1b3Sopenharmony_ci        o1 = tmp;
72953a5a1b3Sopenharmony_ci    }
73053a5a1b3Sopenharmony_ci
73153a5a1b3Sopenharmony_ci    /* o2 is now a fixed type, and o1 is not */
73253a5a1b3Sopenharmony_ci
73353a5a1b3Sopenharmony_ci    if (pa_json_object_get_type(o1) == PA_JSON_TYPE_ARRAY) {
73453a5a1b3Sopenharmony_ci        for (i = 0; i < pa_json_object_get_array_length(o1); i++) {
73553a5a1b3Sopenharmony_ci            if (pa_json_object_equal(pa_json_object_get_array_member(o1, i), o2)) {
73653a5a1b3Sopenharmony_ci                ret = 1;
73753a5a1b3Sopenharmony_ci                break;
73853a5a1b3Sopenharmony_ci            }
73953a5a1b3Sopenharmony_ci        }
74053a5a1b3Sopenharmony_ci    } else if (pa_json_object_get_type(o1) == PA_JSON_TYPE_OBJECT) {
74153a5a1b3Sopenharmony_ci        /* o1 should be a range type */
74253a5a1b3Sopenharmony_ci        int min, max, v;
74353a5a1b3Sopenharmony_ci        const pa_json_object *o_min = NULL, *o_max = NULL;
74453a5a1b3Sopenharmony_ci
74553a5a1b3Sopenharmony_ci        if (pa_json_object_get_type(o2) != PA_JSON_TYPE_INT) {
74653a5a1b3Sopenharmony_ci            /* We don't support non-integer ranges */
74753a5a1b3Sopenharmony_ci            goto out;
74853a5a1b3Sopenharmony_ci        }
74953a5a1b3Sopenharmony_ci
75053a5a1b3Sopenharmony_ci        if (!(o_min = pa_json_object_get_object_member(o1, PA_JSON_MIN_KEY)) ||
75153a5a1b3Sopenharmony_ci            pa_json_object_get_type(o_min) != PA_JSON_TYPE_INT)
75253a5a1b3Sopenharmony_ci            goto out;
75353a5a1b3Sopenharmony_ci
75453a5a1b3Sopenharmony_ci        if (!(o_max = pa_json_object_get_object_member(o1, PA_JSON_MAX_KEY)) ||
75553a5a1b3Sopenharmony_ci            pa_json_object_get_type(o_max) != PA_JSON_TYPE_INT)
75653a5a1b3Sopenharmony_ci            goto out;
75753a5a1b3Sopenharmony_ci
75853a5a1b3Sopenharmony_ci        v = pa_json_object_get_int(o2);
75953a5a1b3Sopenharmony_ci        min = pa_json_object_get_int(o_min);
76053a5a1b3Sopenharmony_ci        max = pa_json_object_get_int(o_max);
76153a5a1b3Sopenharmony_ci
76253a5a1b3Sopenharmony_ci        ret = v >= min && v <= max;
76353a5a1b3Sopenharmony_ci    } else {
76453a5a1b3Sopenharmony_ci        pa_log_warn("Got a format type that we don't support");
76553a5a1b3Sopenharmony_ci    }
76653a5a1b3Sopenharmony_ci
76753a5a1b3Sopenharmony_ciout:
76853a5a1b3Sopenharmony_ci    if (o1)
76953a5a1b3Sopenharmony_ci        pa_json_object_free(o1);
77053a5a1b3Sopenharmony_ci    if (o2)
77153a5a1b3Sopenharmony_ci        pa_json_object_free(o2);
77253a5a1b3Sopenharmony_ci
77353a5a1b3Sopenharmony_ci    return ret;
77453a5a1b3Sopenharmony_ci}
775