X-Git-Url: https://code.delx.au/pulseaudio/blobdiff_plain/b4e938e1944ef49de2466aae06f824ce4db1c81e..a36bf31cae89594b3d56f3264b85fded763fd567:/src/pulse/format.c diff --git a/src/pulse/format.c b/src/pulse/format.c index 81c329ff..6c345944 100644 --- a/src/pulse/format.c +++ b/src/pulse/format.c @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -41,20 +42,31 @@ static int pa_format_info_prop_compatible(const char *one, const char *two); -const char *pa_encoding_to_string(pa_encoding_t e) { - static const char* const table[]= { - [PA_ENCODING_PCM] = "pcm", - [PA_ENCODING_AC3_IEC61937] = "ac3-iec61937", - [PA_ENCODING_EAC3_IEC61937] = "eac3-iec61937", - [PA_ENCODING_MPEG_IEC61937] = "mpeg-iec61937", - [PA_ENCODING_DTS_IEC61937] = "dts-iec61937", - [PA_ENCODING_ANY] = "any", - }; +static const char* const _encoding_str_table[]= { + [PA_ENCODING_PCM] = "pcm", + [PA_ENCODING_AC3_IEC61937] = "ac3-iec61937", + [PA_ENCODING_EAC3_IEC61937] = "eac3-iec61937", + [PA_ENCODING_MPEG_IEC61937] = "mpeg-iec61937", + [PA_ENCODING_DTS_IEC61937] = "dts-iec61937", + [PA_ENCODING_MPEG2_AAC_IEC61937] = "mpeg2-aac-iec61937", + [PA_ENCODING_ANY] = "any", +}; +const char *pa_encoding_to_string(pa_encoding_t e) { if (e < 0 || e >= PA_ENCODING_MAX) return NULL; - return table[e]; + return _encoding_str_table[e]; +} + +pa_encoding_t pa_encoding_from_string(const char *encoding) { + pa_encoding_t e; + + for (e = PA_ENCODING_ANY; e < PA_ENCODING_MAX; e++) + if (pa_streq(_encoding_str_table[e], encoding)) + return e; + + return PA_ENCODING_INVALID; } pa_format_info* pa_format_info_new(void) { @@ -90,10 +102,6 @@ void pa_format_info_free(pa_format_info *f) { pa_xfree(f); } -void pa_format_info_free2(pa_format_info *f, void *userdata) { - pa_format_info_free(f); -} - int pa_format_info_valid(const pa_format_info *f) { return (f->encoding >= 0 && f->encoding < PA_ENCODING_MAX && f->plist != NULL); } @@ -114,15 +122,56 @@ char *pa_format_info_snprint(char *s, size_t l, const pa_format_info *f) { if (!pa_format_info_valid(f)) pa_snprintf(s, l, _("(invalid)")); else { - tmp = pa_proplist_to_string_sep(f->plist, ", "); - pa_snprintf(s, l, _("%s, %s"), pa_encoding_to_string(f->encoding), tmp[0] ? tmp : _("(no properties)")); + tmp = pa_proplist_to_string_sep(f->plist, " "); + if (tmp[0]) + pa_snprintf(s, l, "%s, %s", pa_encoding_to_string(f->encoding), tmp); + else + pa_snprintf(s, l, "%s", pa_encoding_to_string(f->encoding)); pa_xfree(tmp); } return s; } -int pa_format_info_is_compatible(pa_format_info *first, pa_format_info *second) { +pa_format_info* pa_format_info_from_string(const char *str) { + pa_format_info *f = pa_format_info_new(); + char *encoding = NULL, *properties = NULL; + size_t pos; + + pos = strcspn(str, ","); + + encoding = pa_xstrndup(str, pos); + f->encoding = pa_encoding_from_string(pa_strip(encoding)); + if (f->encoding == PA_ENCODING_INVALID) + goto error; + + if (pos != strlen(str)) { + pa_proplist *plist; + + properties = pa_xstrdup(&str[pos+1]); + plist = pa_proplist_from_string(properties); + + if (!plist) + goto error; + + pa_proplist_free(f->plist); + f->plist = plist; + } + +out: + if (encoding) + pa_xfree(encoding); + if (properties) + pa_xfree(properties); + return f; + +error: + pa_format_info_free(f); + f = NULL; + goto out; +} + +int pa_format_info_is_compatible(const pa_format_info *first, const pa_format_info *second) { const char *key; void *state = NULL; @@ -130,7 +179,7 @@ int pa_format_info_is_compatible(pa_format_info *first, pa_format_info *second) pa_assert(second); if (first->encoding != second->encoding) - return FALSE; + return false; while ((key = pa_proplist_iterate(first->plist, &state))) { const char *value_one, *value_two; @@ -139,13 +188,13 @@ int pa_format_info_is_compatible(pa_format_info *first, pa_format_info *second) value_two = pa_proplist_gets(second->plist, key); if (!value_two || !pa_format_info_prop_compatible(value_one, value_two)) - return FALSE; + return false; } - return TRUE; + return true; } -pa_format_info* pa_format_info_from_sample_spec(pa_sample_spec *ss, pa_channel_map *map) { +pa_format_info* pa_format_info_from_sample_spec(const pa_sample_spec *ss, const pa_channel_map *map) { char cm[PA_CHANNEL_MAP_SNPRINT_MAX]; pa_format_info *f; @@ -168,88 +217,100 @@ pa_format_info* pa_format_info_from_sample_spec(pa_sample_spec *ss, pa_channel_m } /* For PCM streams */ -pa_bool_t pa_format_info_to_sample_spec(pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map) { - char *sf = NULL, *m = NULL; - int rate, channels; - pa_bool_t ret = FALSE; - +int pa_format_info_to_sample_spec(const pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map) { pa_assert(f); pa_assert(ss); - pa_return_val_if_fail(f->encoding == PA_ENCODING_PCM, FALSE); - if (!pa_format_info_get_prop_string(f, PA_PROP_FORMAT_SAMPLE_FORMAT, &sf)) - goto out; - if (!pa_format_info_get_prop_int(f, PA_PROP_FORMAT_RATE, &rate)) - goto out; - if (!pa_format_info_get_prop_int(f, PA_PROP_FORMAT_CHANNELS, &channels)) - goto out; + if (!pa_format_info_is_pcm(f)) + return pa_format_info_to_sample_spec_fake(f, ss, map); - if ((ss->format = pa_parse_sample_format(sf)) == PA_SAMPLE_INVALID) - goto out; + if (pa_format_info_get_sample_format(f, &ss->format) < 0) + return -PA_ERR_INVALID; + if (pa_format_info_get_rate(f, &ss->rate) < 0) + return -PA_ERR_INVALID; + if (pa_format_info_get_channels(f, &ss->channels) < 0) + return -PA_ERR_INVALID; + if (map && pa_format_info_get_channel_map(f, map) < 0) + return -PA_ERR_INVALID; - ss->rate = (uint32_t) rate; - ss->channels = (uint8_t) channels; - - if (map) { - pa_channel_map_init(map); - - if (pa_format_info_get_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, &m)) - if (pa_channel_map_parse(map, m) == NULL) - goto out; - } + return 0; +} - ret = TRUE; +pa_prop_type_t pa_format_info_get_prop_type(const pa_format_info *f, const char *key) { + const char *str; + json_object *o, *o1; + pa_prop_type_t type; -out: - if (sf) - pa_xfree(sf); - if (m) - pa_xfree(m); + pa_assert(f); + pa_assert(key); - return ret; -} + str = pa_proplist_gets(f->plist, key); + if (!str) + return PA_PROP_TYPE_INVALID; -/* For compressed streams */ -pa_bool_t pa_format_info_to_sample_spec_fake(pa_format_info *f, pa_sample_spec *ss) { - int rate; + o = json_tokener_parse(str); + if (is_error(o)) + return PA_PROP_TYPE_INVALID; - pa_assert(f); - pa_assert(ss); - pa_return_val_if_fail(f->encoding != PA_ENCODING_PCM, FALSE); + switch (json_object_get_type(o)) { + case json_type_int: + type = PA_PROP_TYPE_INT; + break; - ss->format = PA_SAMPLE_S16LE; - ss->channels = 2; + case json_type_string: + type = PA_PROP_TYPE_STRING; + break; - pa_return_val_if_fail(pa_format_info_get_prop_int(f, PA_PROP_FORMAT_RATE, &rate), FALSE); - ss->rate = (uint32_t) rate; + case json_type_array: + if (json_object_array_length(o) == 0) { + /* Unlikely, but let's account for this anyway. We need at + * least one element to figure out the array type. */ + type = PA_PROP_TYPE_INVALID; + break; + } - if (f->encoding == PA_ENCODING_EAC3_IEC61937) - ss->rate *= 4; + o1 = json_object_array_get_idx(o, 1); - return TRUE; -} + if (json_object_get_type(o1) == json_type_int) + type = PA_PROP_TYPE_INT_ARRAY; + else if (json_object_get_type(o1) == json_type_string) + type = PA_PROP_TYPE_STRING_ARRAY; + else + type = PA_PROP_TYPE_INVALID; -void pa_format_info_set_sample_format(pa_format_info *f, pa_sample_format_t sf) { - pa_format_info_set_prop_string(f, PA_PROP_FORMAT_SAMPLE_FORMAT, pa_sample_format_to_string(sf)); -} + json_object_put(o1); + break; -void pa_format_info_set_rate(pa_format_info *f, int rate) { - pa_format_info_set_prop_int(f, PA_PROP_FORMAT_RATE, rate); -} + case json_type_object: + /* We actually know at this point that it's a int range, but let's + * confirm. */ + o1 = json_object_object_get(o, PA_JSON_MIN_KEY); + if (!o1) { + type = PA_PROP_TYPE_INVALID; + break; + } + json_object_put(o1); -void pa_format_info_set_channels(pa_format_info *f, int channels) { - pa_format_info_set_prop_int(f, PA_PROP_FORMAT_CHANNELS, channels); -} + o1 = json_object_object_get(o, PA_JSON_MAX_KEY); + if (!o1) { + type = PA_PROP_TYPE_INVALID; + break; + } + json_object_put(o1); -void pa_format_info_set_channel_map(pa_format_info *f, const pa_channel_map *map) { - char map_str[PA_CHANNEL_MAP_SNPRINT_MAX]; + type = PA_PROP_TYPE_INT_RANGE; + break; - pa_channel_map_snprint(map_str, sizeof(map_str), map); + default: + type = PA_PROP_TYPE_INVALID; + break; + } - pa_format_info_set_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, map_str); + json_object_put(o); + return type; } -pa_bool_t pa_format_info_get_prop_int(pa_format_info *f, const char *key, int *v) { +int pa_format_info_get_prop_int(const pa_format_info *f, const char *key, int *v) { const char *str; json_object *o; @@ -257,21 +318,109 @@ pa_bool_t pa_format_info_get_prop_int(pa_format_info *f, const char *key, int *v pa_assert(key); pa_assert(v); - pa_return_val_if_fail(str = pa_proplist_gets(f->plist, key), FALSE); + str = pa_proplist_gets(f->plist, key); + if (!str) + return -PA_ERR_NOENTITY; + o = json_tokener_parse(str); - pa_return_val_if_fail(!is_error(o), FALSE); + if (is_error(o)) + return -PA_ERR_INVALID; + if (json_object_get_type(o) != json_type_int) { json_object_put(o); - return FALSE; + return -PA_ERR_INVALID; } *v = json_object_get_int(o); json_object_put(o); - return TRUE; + return 0; } -pa_bool_t pa_format_info_get_prop_string(pa_format_info *f, const char *key, char **v) { +int pa_format_info_get_prop_int_range(const pa_format_info *f, const char *key, int *min, int *max) { + const char *str; + json_object *o, *o1; + int ret = -PA_ERR_INVALID; + + pa_assert(f); + pa_assert(key); + pa_assert(min); + pa_assert(max); + + str = pa_proplist_gets(f->plist, key); + if (!str) + return -PA_ERR_NOENTITY; + + o = json_tokener_parse(str); + if (is_error(o)) + return -PA_ERR_INVALID; + + if (json_object_get_type(o) != json_type_object) + goto out; + + if (!(o1 = json_object_object_get(o, PA_JSON_MIN_KEY))) + goto out; + + *min = json_object_get_int(o1); + json_object_put(o1); + + if (!(o1 = json_object_object_get(o, PA_JSON_MAX_KEY))) + goto out; + + *max = json_object_get_int(o1); + json_object_put(o1); + + ret = 0; + +out: + json_object_put(o); + return ret; +} + +int pa_format_info_get_prop_int_array(const pa_format_info *f, const char *key, int **values, int *n_values) { + const char *str; + json_object *o, *o1; + int i, ret = -PA_ERR_INVALID; + + pa_assert(f); + pa_assert(key); + pa_assert(values); + pa_assert(n_values); + + str = pa_proplist_gets(f->plist, key); + if (!str) + return -PA_ERR_NOENTITY; + + o = json_tokener_parse(str); + if (is_error(o)) + return -PA_ERR_INVALID; + + if (json_object_get_type(o) != json_type_array) + goto out; + + *n_values = json_object_array_length(o); + *values = pa_xnew(int, *n_values); + + for (i = 0; i < *n_values; i++) { + o1 = json_object_array_get_idx(o, i); + + if (json_object_get_type(o1) != json_type_int) { + json_object_put(o1); + goto out; + } + + (*values)[i] = json_object_get_int(o1); + json_object_put(o1); + } + + ret = 0; + +out: + json_object_put(o); + return ret; +} + +int pa_format_info_get_prop_string(const pa_format_info *f, const char *key, char **v) { const char *str = NULL; json_object *o; @@ -279,21 +428,95 @@ pa_bool_t pa_format_info_get_prop_string(pa_format_info *f, const char *key, cha pa_assert(key); pa_assert(v); - str = pa_proplist_gets(f->plist, key), FALSE; + str = pa_proplist_gets(f->plist, key); if (!str) - return FALSE; + return -PA_ERR_NOENTITY; o = json_tokener_parse(str); - pa_return_val_if_fail(!is_error(o), FALSE); + if (is_error(o)) + return -PA_ERR_INVALID; + if (json_object_get_type(o) != json_type_string) { json_object_put(o); - return FALSE; + return -PA_ERR_INVALID; } *v = pa_xstrdup(json_object_get_string(o)); json_object_put(o); - return TRUE; + return 0; +} + +int pa_format_info_get_prop_string_array(const pa_format_info *f, const char *key, char ***values, int *n_values) { + const char *str; + json_object *o, *o1; + int i, ret = -PA_ERR_INVALID; + + pa_assert(f); + pa_assert(key); + pa_assert(values); + pa_assert(n_values); + + str = pa_proplist_gets(f->plist, key); + if (!str) + return -PA_ERR_NOENTITY; + + o = json_tokener_parse(str); + if (is_error(o)) + return -PA_ERR_INVALID; + + if (json_object_get_type(o) != json_type_array) + goto out; + + *n_values = json_object_array_length(o); + *values = pa_xnew(char *, *n_values); + + for (i = 0; i < *n_values; i++) { + o1 = json_object_array_get_idx(o, i); + + if (json_object_get_type(o1) != json_type_string) { + json_object_put(o1); + goto out; + } + + (*values)[i] = pa_xstrdup(json_object_get_string(o1)); + json_object_put(o1); + } + + ret = 0; + +out: + json_object_put(o); + return ret; +} + +void pa_format_info_free_string_array(char **values, int n_values) { + int i; + + for (i = 0; i < n_values; i++) + pa_xfree(values[i]); + + pa_xfree(values); +} + +void pa_format_info_set_sample_format(pa_format_info *f, pa_sample_format_t sf) { + pa_format_info_set_prop_string(f, PA_PROP_FORMAT_SAMPLE_FORMAT, pa_sample_format_to_string(sf)); +} + +void pa_format_info_set_rate(pa_format_info *f, int rate) { + pa_format_info_set_prop_int(f, PA_PROP_FORMAT_RATE, rate); +} + +void pa_format_info_set_channels(pa_format_info *f, int channels) { + pa_format_info_set_prop_int(f, PA_PROP_FORMAT_CHANNELS, channels); +} + +void pa_format_info_set_channel_map(pa_format_info *f, const pa_channel_map *map) { + char map_str[PA_CHANNEL_MAP_SNPRINT_MAX]; + + pa_channel_map_snprint(map_str, sizeof(map_str), map); + + pa_format_info_set_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, map_str); } void pa_format_info_set_prop_int(pa_format_info *f, const char *key, int value) { @@ -372,15 +595,14 @@ void pa_format_info_set_prop_string_array(pa_format_info *f, const char *key, co json_object_put(o); } -static pa_bool_t pa_json_is_fixed_type(json_object *o) -{ +static bool pa_json_is_fixed_type(json_object *o) { switch(json_object_get_type(o)) { case json_type_object: case json_type_array: - return FALSE; + return false; default: - return TRUE; + return true; } } @@ -402,7 +624,7 @@ static int pa_format_info_prop_compatible(const char *one, const char *two) { goto out; /* We don't deal with both values being non-fixed - just because there is no immediate need (FIXME) */ - pa_return_val_if_fail(pa_json_is_fixed_type(o1) || pa_json_is_fixed_type(o2), FALSE); + pa_return_val_if_fail(pa_json_is_fixed_type(o1) || pa_json_is_fixed_type(o2), false); if (pa_json_is_fixed_type(o1) && pa_json_is_fixed_type(o2)) { ret = pa_json_value_equal(o1, o2);