changeset 3149:4b50e2a0ae1f

Branch merge.
author William Pitcock <nenolod@atheme.org>
date Mon, 11 May 2009 12:25:48 -0500
parents d443c917dab9
children 062f42c3737e
files src/alsa/audio.c
diffstat 1 files changed, 96 insertions(+), 30 deletions(-) [+]
line wrap: on
line diff
--- a/src/alsa/audio.c	Mon May 11 17:32:04 2009 +0100
+++ b/src/alsa/audio.c	Mon May 11 12:25:48 2009 -0500
@@ -141,11 +141,21 @@
 
 int alsa_playing(void)
 {
-	if (!going || paused || prebuffer || alsa_pcm == NULL)
-		return FALSE;
+	gint ret;
+
+	g_static_mutex_lock(&alsa_mutex);
 
-	return snd_pcm_state(alsa_pcm) == SND_PCM_STATE_RUNNING ||
-	       get_thread_buffer_filled();
+	if (!going || paused || prebuffer || alsa_pcm == NULL)
+		ret = FALSE;
+	else 
+		ret = snd_pcm_state(alsa_pcm) == SND_PCM_STATE_RUNNING &&
+	               !paused &&
+        	       !prebuffer &&
+                       get_thread_buffer_filled() > hw_period_size_in;
+
+	g_static_mutex_unlock(&alsa_mutex);
+
+	return ret;
 }
 
 static gint
@@ -225,6 +235,10 @@
 /* get the free space on buffer */
 int alsa_free(void)
 {
+	gint ret;
+
+	g_static_mutex_lock(&alsa_mutex);
+
 	if (remove_prebuffer && prebuffer)
 	{
 		prebuffer = FALSE;
@@ -233,7 +247,11 @@
 	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 */
@@ -286,8 +304,6 @@
 
 	g_thread_join(audio_thread);
 
-	g_static_mutex_lock(&alsa_mutex); /* alsa_loop locks alsa_mutex! */
-
 	alsa_cleanup_mixer();
 
 	g_free(inputf);
@@ -300,8 +316,6 @@
 	if (alsa_cfg.debug)
 		snd_output_close(logs);
 	debug("Device closed");
-
-	g_static_mutex_unlock(&alsa_mutex);
 }
 
 /* reopen ALSA PCM */
@@ -551,28 +565,42 @@
 
 gint alsa_get_output_time(void)
 {
+	gint ret = 0;
 	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 != NULL)
 	{
-		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;
+
+	g_static_mutex_unlock(&alsa_mutex);
+
+	return ret;
 }
 
 gint alsa_get_written_time(void)
 {
-	if (!going)
-		return 0;
-	return (alsa_total_written * 1000) / inputf->bps;
+	gint ret = 0;
+
+	g_static_mutex_lock(&alsa_mutex);
+
+	if (going)
+		ret = (alsa_total_written * 1000) / inputf->bps;
+
+	g_static_mutex_unlock(&alsa_mutex);
+
+	return ret;
 }
 
 /* transfer data to audio h/w; length is given in bytes
@@ -594,6 +622,8 @@
 	gint cnt;
 	gchar *src = (gchar *)data;
 	
+	g_static_mutex_lock(&alsa_mutex);
+
 	remove_prebuffer = FALSE;
 	
 	alsa_total_written += length;
@@ -607,6 +637,7 @@
 		length -= cnt;
 		src += cnt;
 	}
+	g_static_mutex_unlock(&alsa_mutex);
 }
 
 /* transfer data to audio h/w via normal write */
@@ -645,7 +676,7 @@
 {
 	gint length, cnt, avail;
 
-	length = get_thread_buffer_filled();
+	length = MIN(hw_period_size_in, get_thread_buffer_filled());
 	avail = snd_pcm_frames_to_bytes(alsa_pcm, alsa_get_avail());
 	length = MIN(length, avail);
 	while (length > 0)
@@ -663,21 +694,56 @@
 /* FIXME: proper lock? */
 static void *alsa_loop(void *arg)
 {
-	gint npfds = snd_pcm_poll_descriptors_count(alsa_pcm);
-	gint wr = 0;
+	struct pollfd *pfd;
+	unsigned short *revents;
+	gint i, npfds, err, wr;
 
 	g_static_mutex_lock(&alsa_mutex);
 
+	npfds = snd_pcm_poll_descriptors_count(alsa_pcm);
 	if (npfds <= 0)
 		goto _error;
 
+	pfd = alloca(sizeof(*pfd) * npfds);
+	revents = alloca(sizeof(*revents) * npfds);
+	err = snd_pcm_poll_descriptors(alsa_pcm, pfd, npfds);
+	if (err != npfds)
+                goto _error;
+
 	while (going && alsa_pcm)
 	{
 		if (get_thread_buffer_filled() > prebuffer_size)
 			prebuffer = FALSE;
-		if (!paused && !prebuffer && get_thread_buffer_filled())
+		if (!paused && !prebuffer &&
+		    get_thread_buffer_filled() > hw_period_size_in)
 		{
-			wr = snd_pcm_wait(alsa_pcm, 10);
+			g_static_mutex_unlock(&alsa_mutex);
+			err = poll(pfd, npfds, 10);
+			g_static_mutex_lock(&alsa_mutex);
+
+			if (err == 0)
+				continue;
+
+			if (err < 0) {
+				if (errno == EINTR)
+					continue;
+				goto _error;
+			}
+
+			err = snd_pcm_poll_descriptors_revents(alsa_pcm, pfd, npfds, revents);
+			if (err < 0)
+				goto _error;
+
+			wr = 0;
+			for (i = 0; i < npfds; i++) {
+				if (revents[i] & (POLLERR | POLLNVAL)) {
+					wr = -1;
+					break;
+				}
+				if (revents[i] & POLLOUT)
+					wr = 1;
+			}
+
 			if (wr > 0)
 			{
 				alsa_write_out_thread_data();
@@ -688,7 +754,11 @@
 			}
 		}
 		else	/* XXX: why is this here? --nenolod */
+		{
+			g_static_mutex_unlock(&alsa_mutex);
 			g_usleep(10000);
+			g_static_mutex_lock(&alsa_mutex);
+		}
 
 		if (pause_request != paused)
 			alsa_do_pause(pause_request);
@@ -725,8 +795,6 @@
 		return 0;
 	}
 
-	g_static_mutex_lock(&alsa_mutex);
-
 	if (!mixer)
 		alsa_setup_mixer();
 
@@ -752,8 +820,6 @@
 	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;
 }