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
This commit is contained in:
Wim Taymans 2021-08-18 16:58:22 +02:00
parent f8aa4dcfcc
commit f96fa1bf36
3 changed files with 74 additions and 50 deletions

View file

@ -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, 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; 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); return spa_format_audio_raw_build(b, id, &info);
} }
int format_info_from_spec(struct format_info *info, struct sample_spec *ss, int format_info_from_spec(struct format_info *info, const struct sample_spec *ss,
struct channel_map *map) const struct channel_map *map)
{ {
spa_zero(*info); spa_zero(*info);
info->encoding = ENCODING_PCM; info->encoding = ENCODING_PCM;
@ -473,84 +473,97 @@ int format_info_from_spec(struct format_info *info, struct sample_spec *ss,
return 0; return 0;
} }
const struct spa_pod *format_info_build_param(struct spa_pod_builder *b, uint32_t id, int format_info_to_spec(const struct format_info *info, struct sample_spec *ss,
struct format_info *info) struct channel_map *map)
{ {
const char *str, *val; const char *str, *val;
struct sample_spec ss;
struct channel_map map, *pmap = NULL;
struct spa_json it[2]; struct spa_json it[2];
float f; float f;
int len; int len;
spa_zero(ss); spa_zero(*ss);
spa_zero(map); spa_zero(*map);
if (info->encoding != ENCODING_PCM) 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) if ((str = pw_properties_get(info->props, "format.sample_format")) == NULL)
return NULL; return -ENOENT;
spa_json_init(&it[0], str, strlen(str)); spa_json_init(&it[0], str, strlen(str));
if ((len = spa_json_next(&it[0], &val)) <= 0) if ((len = spa_json_next(&it[0], &val)) <= 0)
return NULL; return -EINVAL;
if (spa_json_is_string(val, len)) { if (spa_json_is_string(val, len)) {
ss.format = format_paname2id(val+1, len-2); ss->format = format_paname2id(val+1, len-2);
if (ss.format == SPA_AUDIO_FORMAT_UNKNOWN) if (ss->format == SPA_AUDIO_FORMAT_UNKNOWN)
return NULL; return -ENOTSUP;
} else if (spa_json_is_array(val, len)) { } else if (spa_json_is_array(val, len)) {
return NULL; return -ENOTSUP;
} else } else
return NULL; return -ENOTSUP;
if ((str = pw_properties_get(info->props, "format.rate")) == NULL) if ((str = pw_properties_get(info->props, "format.rate")) == NULL)
return NULL; return -ENOENT;
spa_json_init(&it[0], str, strlen(str)); spa_json_init(&it[0], str, strlen(str));
if ((len = spa_json_next(&it[0], &val)) <= 0) if ((len = spa_json_next(&it[0], &val)) <= 0)
return NULL; return -EINVAL;
if (spa_json_is_float(val, len)) { if (spa_json_is_float(val, len)) {
if (spa_json_parse_float(val, len, &f) <= 0) if (spa_json_parse_float(val, len, &f) <= 0)
return NULL; return -EINVAL;
ss.rate = f; ss->rate = f;
} else if (spa_json_is_array(val, len)) { } else if (spa_json_is_array(val, len)) {
return NULL; return -ENOTSUP;
} else if (spa_json_is_object(val, len)) { } else if (spa_json_is_object(val, len)) {
return NULL; return -ENOTSUP;
} else } else
return NULL; return -ENOTSUP;
if ((str = pw_properties_get(info->props, "format.channels")) == NULL) if ((str = pw_properties_get(info->props, "format.channels")) == NULL)
return NULL; return -ENOENT;
spa_json_init(&it[0], str, strlen(str)); spa_json_init(&it[0], str, strlen(str));
if ((len = spa_json_next(&it[0], &val)) <= 0) if ((len = spa_json_next(&it[0], &val)) <= 0)
return NULL; return -EINVAL;
if (spa_json_is_float(val, len)) { if (spa_json_is_float(val, len)) {
if (spa_json_parse_float(val, len, &f) <= 0) if (spa_json_parse_float(val, len, &f) <= 0)
return NULL; return -EINVAL;
ss.channels = f; ss->channels = f;
} else if (spa_json_is_array(val, len)) { } else if (spa_json_is_array(val, len)) {
return NULL; return -ENOTSUP;
} else if (spa_json_is_object(val, len)) { } else if (spa_json_is_object(val, len)) {
return NULL; return -ENOTSUP;
} else } else
return NULL; return -ENOTSUP;
if ((str = pw_properties_get(info->props, "format.channel_map")) != NULL) { if ((str = pw_properties_get(info->props, "format.channel_map")) != NULL) {
spa_json_init(&it[0], str, strlen(str)); spa_json_init(&it[0], str, strlen(str));
if ((len = spa_json_next(&it[0], &val)) <= 0) if ((len = spa_json_next(&it[0], &val)) <= 0)
return NULL; return -EINVAL;
if (!spa_json_is_string(val, len)) if (!spa_json_is_string(val, len))
return NULL; return -EINVAL;
while ((*str == '\"' || *str == ',') && while ((*str == '\"' || *str == ',') &&
(len = strcspn(++str, "\",")) > 0) { (len = strcspn(++str, "\",")) > 0) {
map.map[map.channels++] = channel_paname2id(str, len); map->map[map->channels++] = channel_paname2id(str, len);
str += len; str += len;
} }
if (map.channels == ss.channels)
pmap = &map;
} }
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);
} }

View file

@ -205,16 +205,17 @@ void channel_map_parse(const char *str, struct channel_map *map);
bool channel_map_valid(const 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, 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, 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);
int format_info_from_spec(struct format_info *info, struct sample_spec *ss,
struct channel_map *map);
const struct spa_pod *format_info_build_param(struct spa_pod_builder *b, uint32_t id, 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) static inline void format_info_clear(struct format_info *info)
{ {

View file

@ -1291,7 +1291,7 @@ static int do_create_playback_stream(struct client *client, uint32_t command, ui
int res; int res;
struct sample_spec ss; struct sample_spec ss;
struct channel_map map; struct channel_map map;
uint32_t sink_index, syncid; uint32_t sink_index, syncid, rate = 0;
const char *sink_name; const char *sink_name;
struct buffer_attr attr = { 0 }; struct buffer_attr attr = { 0 };
bool corked = false, bool corked = false,
@ -1411,6 +1411,7 @@ static int do_create_playback_stream(struct client *client, uint32_t command, ui
uint8_t i; uint8_t i;
for (i = 0; i < n_formats; i++) { for (i = 0; i < n_formats; i++) {
struct format_info format; struct format_info format;
uint32_t r;
if (message_get(m, if (message_get(m,
TAG_FORMAT_INFO, &format, 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 && if (n_params < MAX_FORMATS &&
(params[n_params] = format_info_build_param(&b, (params[n_params] = format_info_build_param(&b,
SPA_PARAM_EnumFormat, &format)) != NULL) { SPA_PARAM_EnumFormat, &format, &r)) != NULL) {
n_params++; n_params++;
n_valid_formats++; n_valid_formats++;
if (r > rate)
rate = r;
} else { } else {
log_format_info(impl, SPA_LOG_LEVEL_WARN, &format); 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, impl, format_id2name(ss.format), ss.rate,
ss.channels); ss.channels);
} }
pw_properties_setf(props, PW_KEY_NODE_RATE, "1/%u", ss.rate); rate = ss.rate;
} }
if (m->offset != m->length) 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->is_underrun = true;
stream->underrun_for = -1; stream->underrun_for = -1;
if (rate != 0)
pw_properties_setf(props, PW_KEY_NODE_RATE, "1/%u", rate);
if (no_remix) if (no_remix)
pw_properties_set(props, PW_KEY_STREAM_DONT_REMIX, "true"); pw_properties_set(props, PW_KEY_STREAM_DONT_REMIX, "true");
flags = 0; flags = 0;
@ -1562,7 +1567,7 @@ static int do_create_record_stream(struct client *client, uint32_t command, uint
struct pw_properties *props = NULL; struct pw_properties *props = NULL;
uint8_t n_formats = 0; uint8_t n_formats = 0;
struct stream *stream = NULL; 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]; const struct spa_pod *params[MAX_FORMATS];
uint8_t buffer[4096]; uint8_t buffer[4096];
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); 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; uint8_t i;
for (i = 0; i < n_formats; i++) { for (i = 0; i < n_formats; i++) {
struct format_info format; struct format_info format;
uint32_t r;
if (message_get(m, if (message_get(m,
TAG_FORMAT_INFO, &format, 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 && if (n_params < MAX_FORMATS &&
(params[n_params] = format_info_build_param(&b, (params[n_params] = format_info_build_param(&b,
SPA_PARAM_EnumFormat, &format)) != NULL) { SPA_PARAM_EnumFormat, &format, &r)) != NULL) {
n_params++; n_params++;
n_valid_formats++; n_valid_formats++;
if (r > rate)
rate = r;
} else { } else {
log_format_info(impl, SPA_LOG_LEVEL_WARN, &format); 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, impl, format_id2name(ss.format), ss.rate,
ss.channels); ss.channels);
} }
pw_properties_setf(props, PW_KEY_NODE_RATE, "1/%u", ss.rate); rate = ss.rate;
} }
if (m->offset != m->length) if (m->offset != m->length)
goto error_protocol; 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) if (client->quirks & QUIRK_REMOVE_CAPTURE_DONT_MOVE)
no_move = false; no_move = false;
if (rate != 0)
pw_properties_setf(props, PW_KEY_NODE_RATE, "1/%u", rate);
if (peak_detect) if (peak_detect)
pw_properties_set(props, PW_KEY_STREAM_MONITOR, "true"); pw_properties_set(props, PW_KEY_STREAM_MONITOR, "true");
if (no_remix) if (no_remix)