From 5c8799a480382bff87401c3c9e9899ce3326ba55 Mon Sep 17 00:00:00 2001 From: Martin Geier Date: Tue, 2 Apr 2024 14:57:07 +0200 Subject: [PATCH] alsa-pcm: set threshold to final value before set_swparams is called This patch fixes use case, when disable_tsched is set and api.alsa.period-size is set to value different from default quantum size. In a such configuration, threshold needs to be set to a final value before snd_pcm_sw_params_set_avail_min is called to get IRQs with right timing. Avail minimum is calculated from a threshold set in the check_position_config. The method returned different value for threshold right before playback started and after the playback started. Therefore threshold used in the snd_pcm_sw_params_set_avail_min was incorrect. Force the check_position_config to use configured values when called from spa_alsa_prepare as this method is called when starting new playback and the state->period_frames and the state->rate are already known. Signed-off-by: Martin Geier --- spa/plugins/alsa/alsa-pcm.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/spa/plugins/alsa/alsa-pcm.c b/spa/plugins/alsa/alsa-pcm.c index 74e433cbe..45502cad7 100644 --- a/spa/plugins/alsa/alsa-pcm.c +++ b/spa/plugins/alsa/alsa-pcm.c @@ -2497,7 +2497,7 @@ static inline int do_start(struct state *state) return 0; } -static inline int check_position_config(struct state *state); +static inline int check_position_config(struct state *state, bool starting); static int alsa_recover(struct state *state) { @@ -2564,7 +2564,7 @@ recover: spa_list_for_each(follower, &driver->rt.followers, rt.driver_link) { if (follower != driver && follower->linked) { do_drop(follower); - check_position_config(follower); + check_position_config(follower, false); } } do_prepare(driver); @@ -2809,7 +2809,7 @@ static void update_sources(struct state *state, bool active) } } -static inline int check_position_config(struct state *state) +static inline int check_position_config(struct state *state, bool starting) { uint64_t target_duration; struct spa_fraction target_rate; @@ -2819,7 +2819,7 @@ static inline int check_position_config(struct state *state) return 0; if (state->force_position || - (state->disable_tsched && state->started && !state->following)) { + (state->disable_tsched && (starting || state->started) && !state->following)) { target_duration = state->period_frames; target_rate = SPA_FRACTION(1, state->rate); pos->clock.target_duration = target_duration; @@ -2855,7 +2855,7 @@ static int alsa_write_sync(struct state *state, uint64_t current_time) snd_pcm_uframes_t avail, delay, target; bool following = state->following; - if (SPA_UNLIKELY((res = check_position_config(state)) < 0)) + if (SPA_UNLIKELY((res = check_position_config(state, false)) < 0)) return res; if (SPA_UNLIKELY((res = get_status(state, current_time, &avail, &delay, &target)) < 0)) { @@ -3116,7 +3116,7 @@ static int alsa_read_sync(struct state *state, uint64_t current_time) if (SPA_UNLIKELY(!state->alsa_started)) return 0; - if (SPA_UNLIKELY((res = check_position_config(state)) < 0)) + if (SPA_UNLIKELY((res = check_position_config(state, false)) < 0)) return res; if (SPA_UNLIKELY((res = get_status(state, current_time, &avail, &delay, &target)) < 0)) { @@ -3520,7 +3520,7 @@ int spa_alsa_prepare(struct state *state) if (state->prepared) return 0; - if (check_position_config(state) < 0) { + if (check_position_config(state, true) < 0) { spa_log_error(state->log, "%s: invalid position config", state->name); return -EIO; }