pulse-server: improve maxlength calculations

When no maxlength is given, we use the MAXLENGTH value but we need to
round it DOWN (instead of up) because our buffer is only MAXLENGTH big.
Use CLAMP where we can.
When in capture mode, the maxlength exceeds MAXLENGTH, scale down the
fragsize instead.

Fixes noise in audacious when playing 6 channels sounds. float32 * 6
channels with the maximum buffer size would result in the ringbuffer
being overwritten.
This commit is contained in:
Wim Taymans 2022-09-26 17:17:05 +02:00
parent 1a44689d3f
commit 323ec0b51b

View file

@ -455,7 +455,7 @@ static void clamp_latency(struct stream *s, struct spa_fraction *lat)
static uint64_t fix_playback_buffer_attr(struct stream *s, struct buffer_attr *attr, static uint64_t fix_playback_buffer_attr(struct stream *s, struct buffer_attr *attr,
uint32_t rate, struct spa_fraction *lat) uint32_t rate, struct spa_fraction *lat)
{ {
uint32_t frame_size, max_prebuf, minreq, latency, max_latency; uint32_t frame_size, max_prebuf, minreq, latency, max_latency, maxlength;
struct defs *defs = &s->impl->defs; struct defs *defs = &s->impl->defs;
if ((frame_size = s->frame_size) == 0) if ((frame_size = s->frame_size) == 0)
@ -463,24 +463,26 @@ static uint64_t fix_playback_buffer_attr(struct stream *s, struct buffer_attr *a
if (frame_size == 0) if (frame_size == 0)
frame_size = 4; frame_size = 4;
pw_log_info("[%s] maxlength:%u tlength:%u minreq:%u prebuf:%u", maxlength = SPA_ROUND_DOWN(MAXLENGTH, frame_size);
pw_log_info("[%s] maxlength:%u tlength:%u minreq:%u prebuf:%u max:%u",
s->client->name, attr->maxlength, attr->tlength, s->client->name, attr->maxlength, attr->tlength,
attr->minreq, attr->prebuf); attr->minreq, attr->prebuf, maxlength);
minreq = frac_to_bytes_round_up(s->min_req, &s->ss); minreq = frac_to_bytes_round_up(s->min_req, &s->ss);
max_latency = defs->quantum_limit * frame_size; max_latency = defs->quantum_limit * frame_size;
if (attr->maxlength == (uint32_t) -1 || attr->maxlength > MAXLENGTH) if (attr->maxlength == (uint32_t) -1 || attr->maxlength > maxlength)
attr->maxlength = MAXLENGTH; attr->maxlength = maxlength;
attr->maxlength = SPA_ROUND_UP(attr->maxlength, frame_size); else
attr->maxlength = SPA_ROUND_DOWN(attr->maxlength, frame_size);
minreq = SPA_MIN(minreq, attr->maxlength); minreq = SPA_MIN(minreq, attr->maxlength);
if (attr->tlength == (uint32_t) -1) if (attr->tlength == (uint32_t) -1)
attr->tlength = frac_to_bytes_round_up(s->default_tlength, &s->ss); attr->tlength = frac_to_bytes_round_up(s->default_tlength, &s->ss);
attr->tlength = SPA_MIN(attr->tlength, attr->maxlength); attr->tlength = SPA_CLAMP(attr->tlength, minreq, attr->maxlength);
attr->tlength = SPA_ROUND_UP(attr->tlength, frame_size); attr->tlength = SPA_ROUND_UP(attr->tlength, frame_size);
attr->tlength = SPA_MAX(attr->tlength, minreq);
if (attr->minreq == (uint32_t) -1) { if (attr->minreq == (uint32_t) -1) {
uint32_t process = frac_to_bytes_round_up(s->default_req, &s->ss); uint32_t process = frac_to_bytes_round_up(s->default_req, &s->ss);
@ -655,35 +657,42 @@ static int reply_create_playback_stream(struct stream *stream, struct pw_manager
static uint64_t fix_record_buffer_attr(struct stream *s, struct buffer_attr *attr, static uint64_t fix_record_buffer_attr(struct stream *s, struct buffer_attr *attr,
uint32_t rate, struct spa_fraction *lat) uint32_t rate, struct spa_fraction *lat)
{ {
uint32_t frame_size, minfrag, latency; uint32_t frame_size, minfrag, latency, maxlength;
if ((frame_size = s->frame_size) == 0) if ((frame_size = s->frame_size) == 0)
frame_size = sample_spec_frame_size(&s->ss); frame_size = sample_spec_frame_size(&s->ss);
if (frame_size == 0) if (frame_size == 0)
frame_size = 4; frame_size = 4;
maxlength = SPA_ROUND_DOWN(MAXLENGTH, frame_size);
pw_log_info("[%s] maxlength:%u fragsize:%u framesize:%u", pw_log_info("[%s] maxlength:%u fragsize:%u framesize:%u",
s->client->name, attr->maxlength, attr->fragsize, s->client->name, attr->maxlength, attr->fragsize,
frame_size); frame_size);
if (attr->maxlength == (uint32_t) -1 || attr->maxlength > MAXLENGTH) if (attr->maxlength == (uint32_t) -1 || attr->maxlength > maxlength)
attr->maxlength = MAXLENGTH; attr->maxlength = maxlength;
attr->maxlength -= attr->maxlength % frame_size; else
attr->maxlength = SPA_ROUND_DOWN(attr->maxlength, frame_size);
attr->maxlength = SPA_MAX(attr->maxlength, frame_size); attr->maxlength = SPA_MAX(attr->maxlength, frame_size);
minfrag = frac_to_bytes_round_up(s->min_frag, &s->ss); minfrag = frac_to_bytes_round_up(s->min_frag, &s->ss);
if (attr->fragsize == (uint32_t) -1 || attr->fragsize == 0) if (attr->fragsize == (uint32_t) -1 || attr->fragsize == 0)
attr->fragsize = frac_to_bytes_round_up(s->default_frag, &s->ss); attr->fragsize = frac_to_bytes_round_up(s->default_frag, &s->ss);
attr->fragsize = SPA_MIN(attr->fragsize, attr->maxlength); attr->fragsize = SPA_CLAMP(attr->fragsize, minfrag, attr->maxlength);
attr->fragsize = SPA_ROUND_UP(attr->fragsize, frame_size); attr->fragsize = SPA_ROUND_UP(attr->fragsize, frame_size);
attr->fragsize = SPA_MAX(attr->fragsize, minfrag);
attr->tlength = attr->minreq = attr->prebuf = 0; attr->tlength = attr->minreq = attr->prebuf = 0;
/* make sure we can queue at least to fragsize without overruns */ /* make sure we can queue at least to fragsize without overruns */
if (attr->maxlength < attr->fragsize * 4) if (attr->maxlength < attr->fragsize * 4) {
attr->maxlength = attr->fragsize * 4; attr->maxlength = attr->fragsize * 4;
if (attr->maxlength > maxlength) {
attr->maxlength = maxlength;
attr->fragsize = SPA_ROUND_DOWN(maxlength / 4, frame_size);
}
}
latency = attr->fragsize; latency = attr->fragsize;