From 7910820018fd598e31b969510be407b6dc4fb127 Mon Sep 17 00:00:00 2001
From: Hans de Goede <j.w.r.degoede@hhs.nl>
Date: Mon, 11 May 2009 16:28:27 +0200
Subject: [PATCH 7/9] Fix alsa plugin locking
audacious sometimes hung after playing the first 3 secs of a song,
this patch fixes this.
---
src/alsa/audio.c | 113 ++++++++++++++++++++++++++++++++++++------------------
1 files changed, 75 insertions(+), 38 deletions(-)
diff --git a/src/alsa/audio.c b/src/alsa/audio.c
index 80b92a5..c50548b 100644
--- a/src/alsa/audio.c
+++ b/src/alsa/audio.c
@@ -131,11 +131,19 @@ static void debug(char *str, ...)
int alsa_playing(void)
{
+ int ret;
+
+ g_static_mutex_lock(&alsa_mutex);
+
if (!going || paused || prebuffer || alsa_pcm == NULL)
- return FALSE;
+ ret = FALSE;
+ else
+ ret = snd_pcm_state(alsa_pcm) == SND_PCM_STATE_RUNNING ||
+ get_thread_buffer_filled();
- return snd_pcm_state(alsa_pcm) == SND_PCM_STATE_RUNNING ||
- get_thread_buffer_filled();
+ g_static_mutex_unlock(&alsa_mutex);
+
+ return ret;
}
static int
@@ -215,6 +223,10 @@ static snd_pcm_sframes_t alsa_get_avail(void)
/* get the free space on buffer */
int alsa_free(void)
{
+ int ret;
+
+ g_static_mutex_lock(&alsa_mutex);
+
if (remove_prebuffer && prebuffer)
{
prebuffer = FALSE;
@@ -223,7 +235,11 @@ int alsa_free(void)
if (prebuffer)
remove_prebuffer = TRUE;
- return thread_buffer_size - get_thread_buffer_filled() - 1;
+ ret = thread_buffer_size - get_thread_buffer_filled() - 1;
+
+ g_static_mutex_unlock(&alsa_mutex);
+
+ return ret;
}
/* do pause operation */
@@ -276,8 +292,6 @@ void alsa_close(void)
g_thread_join(audio_thread);
- g_static_mutex_lock(&alsa_mutex); /* alsa_loop locks alsa_mutex! */
-
alsa_cleanup_mixer();
g_free(inputf);
@@ -290,8 +304,6 @@ void alsa_close(void)
if (alsa_cfg.debug)
snd_output_close(logs);
debug("Device closed");
-
- g_static_mutex_unlock(&alsa_mutex);
}
/* reopen ALSA PCM */
@@ -541,28 +553,46 @@ static int get_thread_buffer_filled(void)
int alsa_get_output_time(void)
{
+ int ret;
snd_pcm_sframes_t delay;
guint64 bytes = alsa_hw_written;
- if (!going || alsa_pcm == NULL)
- return 0;
+ g_static_mutex_lock(&alsa_mutex);
- if (!snd_pcm_delay(alsa_pcm, &delay))
+ if (going && alsa_pcm)
{
- unsigned int d = snd_pcm_frames_to_bytes(alsa_pcm, delay);
- if (bytes < d)
- bytes = 0;
- else
- bytes -= d;
+ if (!snd_pcm_delay(alsa_pcm, &delay))
+ {
+ unsigned int d = snd_pcm_frames_to_bytes(alsa_pcm, delay);
+ if (bytes < d)
+ bytes = 0;
+ else
+ bytes -= d;
+ }
+ ret = output_time_offset + (bytes * 1000) / outputf->bps;
}
- return output_time_offset + (bytes * 1000) / outputf->bps;
+ else
+ ret = 0;
+
+ g_static_mutex_unlock(&alsa_mutex);
+
+ return ret;
}
int alsa_get_written_time(void)
{
- if (!going)
- return 0;
- return (alsa_total_written * 1000) / inputf->bps;
+ int ret;
+
+ g_static_mutex_lock(&alsa_mutex);
+
+ if (going)
+ ret = (alsa_total_written * 1000) / inputf->bps;
+ else
+ ret = 0;
+
+ g_static_mutex_unlock(&alsa_mutex);
+
+ return ret;
}
/* transfer data to audio h/w; length is given in bytes
@@ -583,7 +613,9 @@ void alsa_write(gpointer data, int length)
{
int cnt;
char *src = (char *)data;
-
+
+ g_static_mutex_lock(&alsa_mutex);
+
remove_prebuffer = FALSE;
alsa_total_written += length;
@@ -597,6 +629,7 @@ void alsa_write(gpointer data, int length)
length -= cnt;
src += cnt;
}
+ g_static_mutex_unlock(&alsa_mutex);
}
/* transfer data to audio h/w via normal write */
@@ -653,12 +686,17 @@ static void alsa_write_out_thread_data(void)
/* FIXME: proper lock? */
static void *alsa_loop(void *arg)
{
- int npfds = snd_pcm_poll_descriptors_count(alsa_pcm);
- int wr = 0;
+ struct pollfd pfd[16];
+ int npfds, err;
g_static_mutex_lock(&alsa_mutex);
- if (npfds <= 0)
+ npfds = snd_pcm_poll_descriptors_count(alsa_pcm);
+ if (npfds <= 0 || npfds > 16)
+ goto _error;
+
+ err = snd_pcm_poll_descriptors(alsa_pcm, pfd, npfds);
+ if (err != npfds)
goto _error;
while (going && alsa_pcm)
@@ -667,18 +705,21 @@ static void *alsa_loop(void *arg)
prebuffer = FALSE;
if (!paused && !prebuffer && get_thread_buffer_filled())
{
- wr = snd_pcm_wait(alsa_pcm, 10);
- if (wr > 0)
- {
- alsa_write_out_thread_data();
- }
- else if (wr < 0)
- {
- alsa_recovery(wr);
- }
+ g_static_mutex_unlock(&alsa_mutex);
+ err = poll(pfd, npfds, 10);
+ g_static_mutex_lock(&alsa_mutex);
+
+ if (err < 0 && errno != EINTR)
+ goto _error;
+
+ alsa_write_out_thread_data();
}
- else /* XXX: why is this here? --nenolod */
+ else
+ {
+ g_static_mutex_unlock(&alsa_mutex);
g_usleep(10000);
+ g_static_mutex_lock(&alsa_mutex);
+ }
if (pause_request != paused)
alsa_do_pause(pause_request);
@@ -715,8 +756,6 @@ int alsa_open(AFormat fmt, int rate, int nch)
return 0;
}
- g_static_mutex_lock(&alsa_mutex);
-
if (!mixer)
alsa_setup_mixer();
@@ -742,8 +781,6 @@ int alsa_open(AFormat fmt, int rate, int nch)
pause_request = FALSE;
flush_request = -1;
- g_static_mutex_unlock(&alsa_mutex);
-
audio_thread = g_thread_create((GThreadFunc)alsa_loop, NULL, TRUE, NULL);
return 1;
}
--
1.6.2.2