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().
This commit is contained in:
Wim Taymans 2023-09-15 11:15:26 +02:00
parent a5d684af8a
commit e975cb16d3
2 changed files with 39 additions and 25 deletions

View file

@ -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;
}

View file

@ -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);