Blob Blame History Raw
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