mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
alsa: Use the minimum period size as headroom for SOF cards
Configure the headroom to be equal of the minimum allowed period size for the configuration. This is desirable when the ALSA driver's hw_ptr is 'jumpy' due to underplaying hardware architecture, like SOF. In case of SOF the DSP firmware will burst read at stream start to fill it's host facing buffer and later settles to a constant pace. The minimal period size is constrained by the driver to cover the initial burst and settling time of the hw_ptr. Guard this mode of working with a new boolean flag, which is only enabled for SOF cards, kept it disabled for other cards to avoid any unforeseen side effects. Even if the use-period-size-min-as-headroom is set to true, the manual headroom configuration will take precedence to allow experimentation. Link: https://github.com/thesofproject/linux/issues/5284 Link: https://github.com/thesofproject/sof/issues/9695#issuecomment-2569033847 Link: https://github.com/thesofproject/sof/issues/10172 Link: https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/4489 Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
This commit is contained in:
parent
19198d2982
commit
9c42c06af0
2 changed files with 24 additions and 4 deletions
|
|
@ -975,6 +975,13 @@ int spa_alsa_init(struct state *state, const struct spa_dict *info)
|
|||
if (info && (str = spa_dict_lookup(info, "device.profile.pro")) != NULL)
|
||||
state->is_pro = spa_atob(str);
|
||||
|
||||
if (info && spa_strstartswith(spa_dict_lookup(info, SPA_KEY_API_ALSA_CARD_NAME), "sof-") &&
|
||||
state->stream == SND_PCM_STREAM_PLAYBACK) {
|
||||
state->use_period_size_min_as_headroom = true;
|
||||
spa_log_info(state->log,
|
||||
"ALSA SOF driver detected: default api.alsa.use-period-size-min-as-headroom=true");
|
||||
}
|
||||
|
||||
state->multi_rate = true;
|
||||
state->htimestamp = false;
|
||||
state->htimestamp_max_errors = MAX_HTIMESTAMP_ERROR;
|
||||
|
|
@ -2034,7 +2041,12 @@ static void recalc_headroom(struct state *state)
|
|||
if (state->position != NULL)
|
||||
rate = state->position->clock.target_rate.denom;
|
||||
|
||||
state->headroom = state->default_headroom;
|
||||
if (state->use_period_size_min_as_headroom)
|
||||
state->headroom = state->default_headroom ?
|
||||
state->default_headroom : state->period_size_min;
|
||||
else
|
||||
state->headroom = state->default_headroom;
|
||||
|
||||
if (!state->disable_tsched || state->resample) {
|
||||
/* When using timers, we might miss the pointer update for batch
|
||||
* devices so add some extra headroom. With IRQ, we know the pointers
|
||||
|
|
@ -2356,6 +2368,12 @@ int spa_alsa_set_format(struct state *state, struct spa_audio_info *fmt, uint32_
|
|||
periods = UINT_MAX;
|
||||
}
|
||||
|
||||
/* Query the minimum period size for this configuration
|
||||
* This information is used as headroom if use_period_size_min_as_headroom is
|
||||
* set and default_headroom is 0 (not forced by user)
|
||||
*/
|
||||
CHECK(snd_pcm_hw_params_get_period_size_min(params, &state->period_size_min, &dir), "snd_pcm_hw_params_get_period_size_min");
|
||||
|
||||
if (state->default_period_size == 0) {
|
||||
/* Some devices (FireWire) don't produce audio if period number is too
|
||||
* small, so force a minimum. This will restrict possible period sizes if
|
||||
|
|
@ -2417,14 +2435,14 @@ int spa_alsa_set_format(struct state *state, struct spa_audio_info *fmt, uint32_
|
|||
recalc_headroom(state);
|
||||
|
||||
spa_log_info(state->log, "%s: format:%s access:%s-%s rate:%d channels:%d "
|
||||
"buffer frames %lu, period frames %lu, periods %u, frame_size %zd "
|
||||
"buffer frames %lu, period frames %lu (min:%lu), periods %u, frame_size %zd "
|
||||
"headroom %u start-delay:%u batch:%u tsched:%u resample:%u",
|
||||
state->name, snd_pcm_format_name(state->format),
|
||||
state->use_mmap ? "mmap" : "rw",
|
||||
planar ? "planar" : "interleaved",
|
||||
state->rate, state->channels, state->buffer_frames, state->period_frames,
|
||||
periods, state->frame_size, state->headroom, state->start_delay,
|
||||
state->is_batch, !state->disable_tsched, state->resample);
|
||||
state->period_size_min, periods, state->frame_size, state->headroom,
|
||||
state->start_delay, state->is_batch, !state->disable_tsched, state->resample);
|
||||
|
||||
/* write the parameters to device */
|
||||
CHECK(snd_pcm_hw_params(hndl, params), "set_hw_params");
|
||||
|
|
|
|||
|
|
@ -203,6 +203,7 @@ struct state {
|
|||
int n_fds;
|
||||
uint32_t threshold;
|
||||
uint32_t last_threshold;
|
||||
snd_pcm_uframes_t period_size_min;
|
||||
uint32_t headroom;
|
||||
uint32_t start_delay;
|
||||
uint32_t min_delay;
|
||||
|
|
@ -234,6 +235,7 @@ struct state {
|
|||
unsigned int linked:1;
|
||||
unsigned int is_batch:1;
|
||||
unsigned int force_quantum:1;
|
||||
unsigned int use_period_size_min_as_headroom:1;
|
||||
|
||||
uint64_t iec958_codecs;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue