From e975cb16d34fd595bc8387fb48dacb6ff8a0f49c Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 15 Sep 2023 11:15:26 +0200 Subject: [PATCH] alsa: add spa_alsa_prepare() Split the spa_alsa_start() in a prepare and start function. Prepare will then also reset state and prefill the playback buffer with silence. This makes it possible to reuse the prepare function in recover(). --- spa/plugins/alsa/alsa-pcm.c | 58 ++++++++++++++++++++++--------------- spa/plugins/alsa/alsa-pcm.h | 6 ++-- 2 files changed, 39 insertions(+), 25 deletions(-) diff --git a/spa/plugins/alsa/alsa-pcm.c b/spa/plugins/alsa/alsa-pcm.c index 4cf4d9ad9..38d72715f 100644 --- a/spa/plugins/alsa/alsa-pcm.c +++ b/spa/plugins/alsa/alsa-pcm.c @@ -1979,14 +1979,10 @@ recover: state->name, snd_strerror(res)); return res; } - spa_dll_init(&state->dll); - state->alsa_recovering = true; - state->alsa_started = false; - if (state->stream == SND_PCM_STREAM_PLAYBACK) - spa_alsa_silence(state, state->start_delay + state->threshold + state->headroom); + spa_alsa_prepare(state); - return do_start(state); + return spa_alsa_start(state); } static inline snd_pcm_sframes_t alsa_avail(struct state *state) @@ -2236,13 +2232,16 @@ static inline int check_position_config(struct state *state) target_duration = state->position->clock.target_duration; target_rate = state->position->clock.target_rate; } + if (target_duration == 0 || target_rate.denom == 0) + return -EIO; if (SPA_UNLIKELY((state->duration != target_duration) || (state->rate_denom != target_rate.denom))) { + spa_log_debug(state->log, "%p: follower:%d duration:%u->%"PRIu64" rate;%d->%d", + state, state->following, state->duration, target_duration, + state->rate_denom, target_rate.denom); state->duration = target_duration; state->rate_denom = target_rate.denom; - if (state->rate_denom == 0 || state->duration == 0) - return -EIO; state->threshold = SPA_SCALE32_UP(state->duration, state->rate, state->rate_denom); state->max_error = SPA_MAX(256.0f, state->threshold / 2.0f); state->max_resync = SPA_MIN(state->threshold, state->max_error); @@ -2866,26 +2865,23 @@ static int do_setup_sources(struct spa_loop *loop, return 0; } -int spa_alsa_start(struct state *state) +int spa_alsa_prepare(struct state *state) { int err; - if (state->started) - return 0; + spa_alsa_pause(state); - state->following = is_following(state); + if (state->prepared) + return 0; if (check_position_config(state) < 0) { spa_log_error(state->log, "%s: invalid position config", state->name); return -EIO; } - setup_matching(state); - - spa_dll_init(&state->dll); state->last_threshold = state->threshold; - spa_log_debug(state->log, "%p: start %d duration:%d rate:%d follower:%d match:%d resample:%d", + spa_log_debug(state->log, "%p: start threshold:%d duration:%d rate:%d follower:%d match:%d resample:%d", state, state->threshold, state->duration, state->rate_denom, state->following, state->matching, state->resample); @@ -2896,6 +2892,28 @@ int spa_alsa_start(struct state *state) state->name, snd_strerror(err)); return err; } + if (state->stream == SND_PCM_STREAM_PLAYBACK) + spa_alsa_silence(state, state->start_delay + state->threshold + state->headroom); + + reset_buffers(state); + state->alsa_sync = true; + state->alsa_sync_warning = false; + state->alsa_recovering = false; + state->alsa_started = false; + + state->prepared = true; + + return 0; +} + +int spa_alsa_start(struct state *state) +{ + int err; + + if (state->started) + return 0; + + spa_alsa_prepare(state); if (!state->disable_tsched) { /* Timer-based scheduling */ @@ -2936,16 +2954,9 @@ int spa_alsa_start(struct state *state) } } - reset_buffers(state); - state->alsa_sync = true; - state->alsa_sync_warning = false; - state->alsa_recovering = false; - state->alsa_started = false; - /* start capture now, playback will start after first write. Without tsched, we start * right away so that the fds become active in poll right away. */ if (state->stream == SND_PCM_STREAM_PLAYBACK) { - spa_alsa_silence(state, state->start_delay + state->threshold + state->headroom); if (state->disable_tsched) do_start(state); } @@ -3026,6 +3037,7 @@ int spa_alsa_pause(struct state *state) snd_strerror(err)); state->started = false; + state->prepared = false; return 0; } diff --git a/spa/plugins/alsa/alsa-pcm.h b/spa/plugins/alsa/alsa-pcm.h index d0b3311d7..27f225daa 100644 --- a/spa/plugins/alsa/alsa-pcm.h +++ b/spa/plugins/alsa/alsa-pcm.h @@ -112,7 +112,9 @@ struct state { struct spa_param_info params[N_NODE_PARAMS]; struct props props; - bool opened; + unsigned int opened:1; + unsigned int prepared:1; + unsigned int started:1; snd_pcm_t *hndl; bool have_format; @@ -170,7 +172,6 @@ struct state { size_t ready_offset; - bool started; /* Either a single source for tsched, or a set of pollfds from ALSA */ struct spa_source source[MAX_POLL]; int timerfd; @@ -241,6 +242,7 @@ int spa_alsa_init(struct state *state, const struct spa_dict *info); int spa_alsa_clear(struct state *state); int spa_alsa_open(struct state *state, const char *params); +int spa_alsa_prepare(struct state *state); int spa_alsa_start(struct state *state); int spa_alsa_reassign_follower(struct state *state); int spa_alsa_pause(struct state *state);