alsa: improve target delay in ALSA

Don't just limit the max delay of samples we keep in the ALSA ringbuffer
to the buffer_size but to half of it. Make this into a max_delay
variable.

If we have a buffer size of 8192 samples and a headroom of 8192 samples,
when capturing, we would wait for the ringbuffer to contain at least
8192 samples, which would always xrun. When we limit the size to
half, we can still read the data without xruns.

Fixes #2972
This commit is contained in:
Wim Taymans 2023-03-03 14:10:33 +01:00
parent 8030a9f360
commit a7322d5043
2 changed files with 4 additions and 2 deletions

View file

@ -1597,6 +1597,7 @@ int spa_alsa_set_format(struct state *state, struct spa_audio_info *fmt, uint32_
if (is_batch)
state->headroom += period_size;
state->max_delay = state->buffer_frames / 2;
if (spa_strstartswith(state->props.device, "a52") ||
spa_strstartswith(state->props.device, "dca"))
state->min_delay = SPA_MIN(2048u, state->buffer_frames);
@ -1608,7 +1609,7 @@ int spa_alsa_set_format(struct state *state, struct spa_audio_info *fmt, uint32_
state->latency[state->port_direction].min_rate =
state->latency[state->port_direction].max_rate =
SPA_MAX(state->min_delay, state->headroom);
SPA_MAX(state->min_delay, SPA_MIN(state->max_delay, state->headroom));
spa_log_info(state->log, "%s (%s): format:%s access:%s-%s rate:%d channels:%d "
"buffer frames %lu, period frames %lu, periods %u, frame_size %zd "
@ -1882,7 +1883,7 @@ static int get_status(struct state *state, uint64_t current_time,
if (state->matching)
*target += 32;
}
*target = SPA_CLAMP(*target, state->min_delay, state->buffer_frames);
*target = SPA_CLAMP(*target, state->min_delay, state->max_delay);
return 0;
}

View file

@ -178,6 +178,7 @@ struct state {
uint32_t headroom;
uint32_t start_delay;
uint32_t min_delay;
uint32_t max_delay;
uint32_t duration;
unsigned int alsa_started:1;