From f96fa1bf369067b87a51cc44fa310f37290b5433 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 18 Aug 2021 16:58:22 +0200 Subject: [PATCH] pulse-server: find the rate in the format_info Also look for the highest rate in the format_info to suggest as the graph sample rate. See #1523 --- src/modules/module-protocol-pulse/format.c | 87 +++++++++++-------- src/modules/module-protocol-pulse/format.h | 15 ++-- .../module-protocol-pulse/pulse-server.c | 22 +++-- 3 files changed, 74 insertions(+), 50 deletions(-) diff --git a/src/modules/module-protocol-pulse/format.c b/src/modules/module-protocol-pulse/format.c index c56ca7a57..ff64ab09e 100644 --- a/src/modules/module-protocol-pulse/format.c +++ b/src/modules/module-protocol-pulse/format.c @@ -430,7 +430,7 @@ int format_parse_param(const struct spa_pod *param, struct sample_spec *ss, stru } const struct spa_pod *format_build_param(struct spa_pod_builder *b, uint32_t id, - struct sample_spec *spec, struct channel_map *map) + const struct sample_spec *spec, const struct channel_map *map) { struct spa_audio_info_raw info; @@ -444,8 +444,8 @@ const struct spa_pod *format_build_param(struct spa_pod_builder *b, uint32_t id, return spa_format_audio_raw_build(b, id, &info); } -int format_info_from_spec(struct format_info *info, struct sample_spec *ss, - struct channel_map *map) +int format_info_from_spec(struct format_info *info, const struct sample_spec *ss, + const struct channel_map *map) { spa_zero(*info); info->encoding = ENCODING_PCM; @@ -473,84 +473,97 @@ int format_info_from_spec(struct format_info *info, struct sample_spec *ss, return 0; } -const struct spa_pod *format_info_build_param(struct spa_pod_builder *b, uint32_t id, - struct format_info *info) +int format_info_to_spec(const struct format_info *info, struct sample_spec *ss, + struct channel_map *map) { const char *str, *val; - struct sample_spec ss; - struct channel_map map, *pmap = NULL; struct spa_json it[2]; float f; int len; - spa_zero(ss); - spa_zero(map); + spa_zero(*ss); + spa_zero(*map); if (info->encoding != ENCODING_PCM) - return NULL; + return -ENOTSUP; + if (info->props == NULL) + return -ENOENT; if ((str = pw_properties_get(info->props, "format.sample_format")) == NULL) - return NULL; + return -ENOENT; spa_json_init(&it[0], str, strlen(str)); if ((len = spa_json_next(&it[0], &val)) <= 0) - return NULL; + return -EINVAL; if (spa_json_is_string(val, len)) { - ss.format = format_paname2id(val+1, len-2); - if (ss.format == SPA_AUDIO_FORMAT_UNKNOWN) - return NULL; + ss->format = format_paname2id(val+1, len-2); + if (ss->format == SPA_AUDIO_FORMAT_UNKNOWN) + return -ENOTSUP; } else if (spa_json_is_array(val, len)) { - return NULL; + return -ENOTSUP; } else - return NULL; + return -ENOTSUP; if ((str = pw_properties_get(info->props, "format.rate")) == NULL) - return NULL; + return -ENOENT; spa_json_init(&it[0], str, strlen(str)); if ((len = spa_json_next(&it[0], &val)) <= 0) - return NULL; + return -EINVAL; if (spa_json_is_float(val, len)) { if (spa_json_parse_float(val, len, &f) <= 0) - return NULL; - ss.rate = f; + return -EINVAL; + ss->rate = f; } else if (spa_json_is_array(val, len)) { - return NULL; + return -ENOTSUP; } else if (spa_json_is_object(val, len)) { - return NULL; + return -ENOTSUP; } else - return NULL; + return -ENOTSUP; if ((str = pw_properties_get(info->props, "format.channels")) == NULL) - return NULL; + return -ENOENT; spa_json_init(&it[0], str, strlen(str)); if ((len = spa_json_next(&it[0], &val)) <= 0) - return NULL; + return -EINVAL; if (spa_json_is_float(val, len)) { if (spa_json_parse_float(val, len, &f) <= 0) - return NULL; - ss.channels = f; + return -EINVAL; + ss->channels = f; } else if (spa_json_is_array(val, len)) { - return NULL; + return -ENOTSUP; } else if (spa_json_is_object(val, len)) { - return NULL; + return -ENOTSUP; } else - return NULL; + return -ENOTSUP; if ((str = pw_properties_get(info->props, "format.channel_map")) != NULL) { spa_json_init(&it[0], str, strlen(str)); if ((len = spa_json_next(&it[0], &val)) <= 0) - return NULL; + return -EINVAL; if (!spa_json_is_string(val, len)) - return NULL; + return -EINVAL; while ((*str == '\"' || *str == ',') && (len = strcspn(++str, "\",")) > 0) { - map.map[map.channels++] = channel_paname2id(str, len); + map->map[map->channels++] = channel_paname2id(str, len); str += len; } - if (map.channels == ss.channels) - pmap = ↦ } - return format_build_param(b, id, &ss, pmap); + return 0; +} + +const struct spa_pod *format_info_build_param(struct spa_pod_builder *b, uint32_t id, + const struct format_info *info, uint32_t *rate) +{ + struct sample_spec ss; + struct channel_map map; + int res; + + if ((res = format_info_to_spec(info, &ss, &map)) < 0) { + errno = -res; + return NULL; + } + *rate = ss.rate; + return format_build_param(b, id, &ss, &map); } diff --git a/src/modules/module-protocol-pulse/format.h b/src/modules/module-protocol-pulse/format.h index 4df949046..b6a4a6df1 100644 --- a/src/modules/module-protocol-pulse/format.h +++ b/src/modules/module-protocol-pulse/format.h @@ -205,16 +205,17 @@ void channel_map_parse(const char *str, struct channel_map *map); bool channel_map_valid(const struct channel_map *map); int format_parse_param(const struct spa_pod *param, struct sample_spec *ss, - struct channel_map *map); + struct channel_map *map); const struct spa_pod *format_build_param(struct spa_pod_builder *b, uint32_t id, - struct sample_spec *spec, struct channel_map *map); - -int format_info_from_spec(struct format_info *info, struct sample_spec *ss, - struct channel_map *map); - + const struct sample_spec *spec, const struct channel_map *map); const struct spa_pod *format_info_build_param(struct spa_pod_builder *b, uint32_t id, - struct format_info *info); + const struct format_info *info, uint32_t *rate); + +int format_info_from_spec(struct format_info *info, const struct sample_spec *ss, + const struct channel_map *map); +int format_info_to_spec(const struct format_info *info, struct sample_spec *ss, + struct channel_map *map); static inline void format_info_clear(struct format_info *info) { diff --git a/src/modules/module-protocol-pulse/pulse-server.c b/src/modules/module-protocol-pulse/pulse-server.c index 5bdcb8382..91035d9fc 100644 --- a/src/modules/module-protocol-pulse/pulse-server.c +++ b/src/modules/module-protocol-pulse/pulse-server.c @@ -1291,7 +1291,7 @@ static int do_create_playback_stream(struct client *client, uint32_t command, ui int res; struct sample_spec ss; struct channel_map map; - uint32_t sink_index, syncid; + uint32_t sink_index, syncid, rate = 0; const char *sink_name; struct buffer_attr attr = { 0 }; bool corked = false, @@ -1411,6 +1411,7 @@ static int do_create_playback_stream(struct client *client, uint32_t command, ui uint8_t i; for (i = 0; i < n_formats; i++) { struct format_info format; + uint32_t r; if (message_get(m, TAG_FORMAT_INFO, &format, @@ -1419,9 +1420,11 @@ static int do_create_playback_stream(struct client *client, uint32_t command, ui if (n_params < MAX_FORMATS && (params[n_params] = format_info_build_param(&b, - SPA_PARAM_EnumFormat, &format)) != NULL) { + SPA_PARAM_EnumFormat, &format, &r)) != NULL) { n_params++; n_valid_formats++; + if (r > rate) + rate = r; } else { log_format_info(impl, SPA_LOG_LEVEL_WARN, &format); } @@ -1440,7 +1443,7 @@ static int do_create_playback_stream(struct client *client, uint32_t command, ui impl, format_id2name(ss.format), ss.rate, ss.channels); } - pw_properties_setf(props, PW_KEY_NODE_RATE, "1/%u", ss.rate); + rate = ss.rate; } if (m->offset != m->length) @@ -1475,6 +1478,8 @@ static int do_create_playback_stream(struct client *client, uint32_t command, ui stream->is_underrun = true; stream->underrun_for = -1; + if (rate != 0) + pw_properties_setf(props, PW_KEY_NODE_RATE, "1/%u", rate); if (no_remix) pw_properties_set(props, PW_KEY_STREAM_DONT_REMIX, "true"); flags = 0; @@ -1562,7 +1567,7 @@ static int do_create_record_stream(struct client *client, uint32_t command, uint struct pw_properties *props = NULL; uint8_t n_formats = 0; struct stream *stream = NULL; - uint32_t n_params = 0, n_valid_formats = 0, flags, id; + uint32_t n_params = 0, n_valid_formats = 0, flags, id, rate = 0; const struct spa_pod *params[MAX_FORMATS]; uint8_t buffer[4096]; struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); @@ -1640,6 +1645,7 @@ static int do_create_record_stream(struct client *client, uint32_t command, uint uint8_t i; for (i = 0; i < n_formats; i++) { struct format_info format; + uint32_t r; if (message_get(m, TAG_FORMAT_INFO, &format, @@ -1648,9 +1654,11 @@ static int do_create_record_stream(struct client *client, uint32_t command, uint if (n_params < MAX_FORMATS && (params[n_params] = format_info_build_param(&b, - SPA_PARAM_EnumFormat, &format)) != NULL) { + SPA_PARAM_EnumFormat, &format, &r)) != NULL) { n_params++; n_valid_formats++; + if (r > rate) + rate = r; } else { log_format_info(impl, SPA_LOG_LEVEL_WARN, &format); } @@ -1680,7 +1688,7 @@ static int do_create_record_stream(struct client *client, uint32_t command, uint impl, format_id2name(ss.format), ss.rate, ss.channels); } - pw_properties_setf(props, PW_KEY_NODE_RATE, "1/%u", ss.rate); + rate = ss.rate; } if (m->offset != m->length) goto error_protocol; @@ -1715,6 +1723,8 @@ static int do_create_record_stream(struct client *client, uint32_t command, uint if (client->quirks & QUIRK_REMOVE_CAPTURE_DONT_MOVE) no_move = false; + if (rate != 0) + pw_properties_setf(props, PW_KEY_NODE_RATE, "1/%u", rate); if (peak_detect) pw_properties_set(props, PW_KEY_STREAM_MONITOR, "true"); if (no_remix)