From 4f57f3cdaeba4bc91da8072624fbaab10c01c800 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sat, 22 Jan 2022 16:17:09 +0100 Subject: [PATCH] pulse-server: allow per-application latency quirks Make it possible to set latency and buffer parameters in the matching rules. Add a rule for speech-dispatcher and force it to some larger latency. --- src/daemon/pipewire-pulse.conf.in | 20 ++++++++++++--- .../module-protocol-pulse/pulse-server.c | 25 ++++++++----------- src/modules/module-protocol-pulse/stream.c | 21 ++++++++++++++++ src/modules/module-protocol-pulse/stream.h | 7 ++++++ 4 files changed, 55 insertions(+), 18 deletions(-) diff --git a/src/daemon/pipewire-pulse.conf.in b/src/daemon/pipewire-pulse.conf.in index 4b3da7949..eaf08e890 100644 --- a/src/daemon/pipewire-pulse.conf.in +++ b/src/daemon/pipewire-pulse.conf.in @@ -89,7 +89,7 @@ pulse.rules = [ # all keys must match the value. ~ starts regex. #client.name = "Firefox" #application.process.binary = "teams" - #application.name = "~teams.*" + #application.name = "~speech-dispatcher.*" } ] actions = { @@ -103,6 +103,8 @@ pulse.rules = [ } } { + # skype does not want to use devices that don't have an + # S16 sample format. matches = [ { application.process.binary = "teams" } { application.process.binary = "skypeforlinux" } @@ -110,9 +112,19 @@ pulse.rules = [ actions = { quirks = [ force-s16-info ] } } { - matches = [ - { application.process.binary = "firefox" } - ] + # firefox marks the capture streams as don't move and then they + # can't be moved with pavucontrol or other tools. + matches = [ { application.process.binary = "firefox" } ] actions = { quirks = [ remove-capture-dont-move ] } } + { + # speech dispatcher asks for too small latency and then underruns. + matches = [ { application.name = "~speech-dispatcher*" } ] + actions = { + update-props = { + pulse.min.req = 1024/48000 # 21ms + pulse.min.quantum = 1024/48000 # 21ms + } + } + } ] diff --git a/src/modules/module-protocol-pulse/pulse-server.c b/src/modules/module-protocol-pulse/pulse-server.c index a6bbd63b2..3179f7d34 100644 --- a/src/modules/module-protocol-pulse/pulse-server.c +++ b/src/modules/module-protocol-pulse/pulse-server.c @@ -371,7 +371,7 @@ static uint32_t fix_playback_buffer_attr(struct stream *s, struct buffer_attr *a struct defs *defs = &s->impl->defs; frame_size = s->frame_size; - minreq = frac_to_bytes_round_up(defs->min_req, &s->ss); + minreq = frac_to_bytes_round_up(s->min_req, &s->ss); max_latency = defs->quantum_limit * frame_size; if (attr->maxlength == (uint32_t) -1 || attr->maxlength > MAXLENGTH) @@ -380,7 +380,7 @@ static uint32_t fix_playback_buffer_attr(struct stream *s, struct buffer_attr *a attr->maxlength = SPA_MAX(attr->maxlength, frame_size); if (attr->tlength == (uint32_t) -1) - attr->tlength = frac_to_bytes_round_up(defs->default_tlength, &s->ss); + attr->tlength = frac_to_bytes_round_up(s->default_tlength, &s->ss); if (attr->tlength > attr->maxlength) attr->tlength = attr->maxlength; attr->tlength -= attr->tlength % frame_size; @@ -388,7 +388,7 @@ static uint32_t fix_playback_buffer_attr(struct stream *s, struct buffer_attr *a attr->tlength = SPA_MAX(attr->tlength, minreq); if (attr->minreq == (uint32_t) -1) { - uint32_t process = frac_to_bytes_round_up(defs->default_req, &s->ss); + uint32_t process = frac_to_bytes_round_up(s->default_req, &s->ss); /* With low-latency, tlength/4 gives a decent default in all of traditional, * adjust latency and early request modes. */ uint32_t m = attr->tlength / 4; @@ -459,7 +459,6 @@ static int reply_create_playback_stream(struct stream *stream, struct pw_manager const char *peer_name; struct spa_fraction lat; uint64_t lat_usec; - struct defs *defs = &stream->impl->defs; lat.denom = stream->ss.rate; lat.num = fix_playback_buffer_attr(stream, &stream->attr); @@ -468,9 +467,9 @@ static int reply_create_playback_stream(struct stream *stream, struct pw_manager if (stream->buffer == NULL) return -errno; - if (lat.num * defs->min_quantum.denom / lat.denom < defs->min_quantum.num) - lat.num = (defs->min_quantum.num * lat.denom + - (defs->min_quantum.denom -1)) / defs->min_quantum.denom; + if (lat.num * stream->min_quantum.denom / lat.denom < stream->min_quantum.num) + lat.num = (stream->min_quantum.num * lat.denom + + (stream->min_quantum.denom -1)) / stream->min_quantum.denom; lat_usec = lat.num * SPA_USEC_PER_SEC / lat.denom; snprintf(latency, sizeof(latency), "%u/%u", lat.num, lat.denom); @@ -549,7 +548,6 @@ static int reply_create_playback_stream(struct stream *stream, struct pw_manager static uint32_t fix_record_buffer_attr(struct stream *s, struct buffer_attr *attr) { uint32_t frame_size, minfrag, latency; - struct defs *defs = &s->impl->defs; frame_size = s->frame_size; @@ -558,10 +556,10 @@ static uint32_t fix_record_buffer_attr(struct stream *s, struct buffer_attr *att attr->maxlength -= attr->maxlength % frame_size; attr->maxlength = SPA_MAX(attr->maxlength, frame_size); - minfrag = frac_to_bytes_round_up(defs->min_frag, &s->ss); + minfrag = frac_to_bytes_round_up(s->min_frag, &s->ss); if (attr->fragsize == (uint32_t) -1 || attr->fragsize == 0) - attr->fragsize = frac_to_bytes_round_up(defs->default_frag, &s->ss); + attr->fragsize = frac_to_bytes_round_up(s->default_frag, &s->ss); attr->fragsize -= attr->fragsize % frame_size; attr->fragsize = SPA_MAX(attr->fragsize, minfrag); attr->fragsize = SPA_MAX(attr->fragsize, frame_size); @@ -599,7 +597,6 @@ static int reply_create_record_stream(struct stream *stream, struct pw_manager_o uint32_t peer_index; struct spa_fraction lat; uint64_t lat_usec; - struct defs *defs = &stream->impl->defs; lat.denom = stream->ss.rate; lat.num = fix_record_buffer_attr(stream, &stream->attr); @@ -608,9 +605,9 @@ static int reply_create_record_stream(struct stream *stream, struct pw_manager_o if (stream->buffer == NULL) return -errno; - if (lat.num * defs->min_quantum.denom / lat.denom < defs->min_quantum.num) - lat.num = (defs->min_quantum.num * lat.denom + - (defs->min_quantum.denom -1)) / defs->min_quantum.denom; + if (lat.num * stream->min_quantum.denom / lat.denom < stream->min_quantum.num) + lat.num = (stream->min_quantum.num * lat.denom + + (stream->min_quantum.denom -1)) / stream->min_quantum.denom; lat_usec = lat.num * SPA_USEC_PER_SEC / lat.denom; snprintf(latency, sizeof(latency), "%u/%u", lat.num, lat.denom); diff --git a/src/modules/module-protocol-pulse/stream.c b/src/modules/module-protocol-pulse/stream.c index 6044d12c9..4c362f92f 100644 --- a/src/modules/module-protocol-pulse/stream.c +++ b/src/modules/module-protocol-pulse/stream.c @@ -44,11 +44,25 @@ #include "reply.h" #include "stream.h" +static int parse_frac(struct pw_properties *props, const char *key, + const struct spa_fraction *def, struct spa_fraction *res) +{ + const char *str; + if (props == NULL || + (str = pw_properties_get(props, key)) == NULL || + sscanf(str, "%u/%u", &res->num, &res->denom) != 2 || + res->denom == 0) { + *res = *def; + } + return 0; +} + struct stream *stream_new(struct client *client, enum stream_type type, uint32_t create_tag, const struct sample_spec *ss, const struct channel_map *map, const struct buffer_attr *attr) { int res; + struct defs *defs = &client->impl->defs; struct stream *stream = calloc(1, sizeof(*stream)); if (stream == NULL) @@ -67,6 +81,13 @@ struct stream *stream_new(struct client *client, enum stream_type type, uint32_t stream->attr = *attr; spa_ringbuffer_init(&stream->ring); + parse_frac(client->props, "pulse.min.req", &defs->min_req, &stream->min_req); + parse_frac(client->props, "pulse.min.frag", &defs->min_frag, &stream->min_frag); + parse_frac(client->props, "pulse.min.quantum", &defs->min_quantum, &stream->min_quantum); + parse_frac(client->props, "pulse.default.req", &defs->default_req, &stream->default_req); + parse_frac(client->props, "pulse.default.frag", &defs->default_frag, &stream->default_frag); + parse_frac(client->props, "pulse.default.tlength", &defs->default_tlength, &stream->default_tlength); + switch (type) { case STREAM_TYPE_RECORD: stream->direction = PW_DIRECTION_INPUT; diff --git a/src/modules/module-protocol-pulse/stream.h b/src/modules/module-protocol-pulse/stream.h index 3ca50467a..a7c4cc1e4 100644 --- a/src/modules/module-protocol-pulse/stream.h +++ b/src/modules/module-protocol-pulse/stream.h @@ -86,6 +86,13 @@ struct stream { uint32_t last_quantum; int64_t requested; + struct spa_fraction min_req; + struct spa_fraction default_req; + struct spa_fraction min_frag; + struct spa_fraction default_frag; + struct spa_fraction default_tlength; + struct spa_fraction min_quantum; + struct sample_spec ss; struct channel_map map; struct buffer_attr attr;