From d53eb0309df34f058b33c18210c8949c8a2d8b8e Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 20 Oct 2010 09:26:24 +0200 Subject: [PATCH] alsaloop: Delay the restart a bit (to handle snd-aloop playback xruns better) Signed-off-by: Jaroslav Kysela --- alsaloop/alsaloop.h | 2 ++ alsaloop/pcmjob.c | 33 ++++++++++++++++++++++++++------- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/alsaloop/alsaloop.h b/alsaloop/alsaloop.h index e506427..8dc445a 100644 --- a/alsaloop/alsaloop.h +++ b/alsaloop/alsaloop.h @@ -143,6 +143,8 @@ struct loopback { unsigned int linked:1; /* linked streams */ unsigned int reinit:1; unsigned int running:1; + unsigned int stop_pending:1; + snd_pcm_uframes_t stop_count; sync_type_t sync; /* type of sync */ slave_type_t slave; int thread; /* thread number */ diff --git a/alsaloop/pcmjob.c b/alsaloop/pcmjob.c index 925380c..23270a0 100644 --- a/alsaloop/pcmjob.c +++ b/alsaloop/pcmjob.c @@ -738,6 +738,15 @@ static int writeit(struct loopback_handle *lhandle) lhandle->buf_pos += r; lhandle->buf_pos %= lhandle->buf_size; xrun_profile(lhandle->loopback); + if (lhandle->loopback->stop_pending) { + lhandle->loopback->stop_count += r; + if (lhandle->loopback->stop_count * lhandle->pitch > + lhandle->loopback->latency * 3) { + lhandle->loopback->stop_pending = 0; + lhandle->loopback->reinit = 1; + break; + } + } } return res; } @@ -1521,6 +1530,7 @@ int pcmjob_start(struct loopback *loop) goto __error; } loop->running = 1; + loop->stop_pending = 0; if (loop->xrun) { getcurtimestamp(&loop->xrun_last_update); loop->xrun_last_pdelay = XRUN_PROFILE_UNKNOWN; @@ -1638,6 +1648,7 @@ static int ctl_event_check(snd_ctl_elem_value_t *val, snd_ctl_event_t *ev) static int handle_ctl_events(struct loopback_handle *lhandle, unsigned short events) { + struct loopback *loop = lhandle->loopback; snd_ctl_event_t *ev; int err; @@ -1647,16 +1658,24 @@ static int handle_ctl_events(struct loopback_handle *lhandle, break; if (snd_ctl_event_get_type(ev) != SND_CTL_EVENT_ELEM) continue; - if (lhandle == lhandle->loopback->play) + if (lhandle == loop->play) goto __ctl_check; if (verbose > 6) - snd_output_printf(lhandle->loopback->output, "%s: ctl event!!!! %s\n", lhandle->id, snd_ctl_event_elem_get_name(ev)); + snd_output_printf(loop->output, "%s: ctl event!!!! %s\n", lhandle->id, snd_ctl_event_elem_get_name(ev)); if (ctl_event_check(lhandle->ctl_active, ev)) { err = get_active(lhandle); if (verbose > 7) - snd_output_printf(lhandle->loopback->output, "%s: ctl event active %i\n", lhandle->id, err); - if (err != lhandle->loopback->running) - goto __restart; + snd_output_printf(loop->output, "%s: ctl event active %i\n", lhandle->id, err); + if (!err) { + if (lhandle->loopback->running) { + loop->stop_pending = 1; + loop->stop_count = 0; + } + } else { + loop->stop_pending = 0; + if (loop->running == 0) + goto __restart; + } } else if (ctl_event_check(lhandle->ctl_format, ev)) { err = get_format(lhandle); if (lhandle->format != err) @@ -1676,8 +1695,8 @@ static int handle_ctl_events(struct loopback_handle *lhandle, return 0; __restart: - pcmjob_stop(lhandle->loopback); - err = pcmjob_start(lhandle->loopback); + pcmjob_stop(loop); + err = pcmjob_start(loop); if (err < 0) return err; return 1;