Index: AUTHORS
===================================================================
--- AUTHORS	(revision 1072)
+++ AUTHORS	(working copy)
@@ -9,3 +9,4 @@
 CONTRIBUTORS
 
 Maarten Maathuis <madman2003@gmail.com>: Transition to FLAC API 8.
+Hong Jen Yee (PCMan) <pcman.tw@gmail.com>: PulseAudio support
Index: src/core.c
===================================================================
--- src/core.c	(revision 1072)
+++ src/core.c	(working copy)
@@ -73,6 +73,11 @@
 #include <mmsystem.h>
 #endif /* _WIN32 */
 
+#ifdef HAVE_PULSE
+#include <pulse/simple.h>
+#include <pulse/error.h>
+#endif /* HAVE_PULSE */
+
 #include "common.h"
 #include "utils.h"
 #include "version.h"
@@ -792,7 +797,155 @@
 #endif /* HAVE_SNDIO */
 
 
+/* PulseAudio output thread */
+/* 2009-08-20 added by Hong Jen Yee (PCMan) <pcman.tw@gmail.com> */
+#ifdef HAVE_PULSE
+void *
+pulse_thread(void * arg) {
 
+    u_int32_t i;
+    thread_info_t * info = (thread_info_t *)arg;
+	u_int32_t driver_offset = 0;
+	int bufsize = 1024;
+        int n_avail;
+	int ret, err;
+	char recv_cmd;
+
+    pa_simple* pa = info->pa;
+	short * pa_short_buf = NULL;
+
+	struct timespec req_time;
+	struct timespec rem_time;
+	req_time.tv_sec = 0;
+    req_time.tv_nsec = 100000000;
+
+	if ((info->pa_short_buf = malloc(2*bufsize * sizeof(short))) == NULL) {
+		fprintf(stderr, "pulse_thread: malloc error\n");
+		exit(1);
+	}
+	pa_short_buf = info->pa_short_buf;
+
+	if ((l_buf = malloc(bufsize * sizeof(float))) == NULL) {
+		fprintf(stderr, "pulse_thread: malloc error\n");
+		exit(1);
+	}
+	if ((r_buf = malloc(bufsize * sizeof(float))) == NULL) {
+		fprintf(stderr, "pulse_thread: malloc error\n");
+		exit(1);
+	}
+#ifdef HAVE_LADSPA
+	ladspa_buflen = bufsize;
+#endif /* HAVE_LADSPA */
+
+	while (1) {
+	pulse_wake:
+		while (rb_read_space(rb_disk2out)) {
+			rb_read(rb_disk2out, &recv_cmd, 1);
+			switch (recv_cmd) {
+			case CMD_FLUSH:
+				while ((n_avail = rb_read_space(rb)) > 0) {
+					if (n_avail > 2*bufsize * sizeof(short))
+						n_avail = 2*bufsize * sizeof(short);
+					rb_read(rb, (char *)pa_short_buf,
+							     2*bufsize * sizeof(short));
+				}
+				rb_write(rb_out2disk, (char *)&driver_offset, sizeof(u_int32_t));
+				goto pulse_wake;
+				break;
+			case CMD_FINISH:
+				goto pulse_finish;
+				break;
+			default:
+				fprintf(stderr, "pulse_thread: recv'd unknown command %d\n", recv_cmd);
+				break;
+			}
+		}
+
+		if ((n_avail = rb_read_space(rb) / (2*sample_size)) == 0) {
+			nanosleep(&req_time, &rem_time);
+			goto pulse_wake;
+		}
+
+		if (n_avail > bufsize)
+			n_avail = bufsize;
+		
+		for (i = 0; i < n_avail; i++) {
+			rb_read(rb, (char *)&(l_buf[i]), sample_size);
+			rb_read(rb, (char *)&(r_buf[i]), sample_size);
+		}
+
+#ifdef HAVE_LADSPA
+		if (options.ladspa_is_postfader) {
+			for (i = 0; i < n_avail; i++) {
+				l_buf[i] *= left_gain;
+				r_buf[i] *= right_gain;
+			}
+		}
+#else
+		for (i = 0; i < n_avail; i++) {
+			l_buf[i] *= left_gain;
+			r_buf[i] *= right_gain;
+		}
+#endif /* HAVE_LADSPA */
+
+		if (n_avail < bufsize) {
+			for (i = n_avail; i < bufsize; i++) {
+				l_buf[i] = 0.0f;
+				r_buf[i] = 0.0f;
+			}
+		}
+
+		/* plugin processing */
+#ifdef HAVE_LADSPA
+		plugin_lock = 1;
+		for (i = 0; i < n_plugins; i++) {
+			if (plugin_vect[i]->is_bypassed)
+				continue;
+
+			if (plugin_vect[i]->handle) {
+				plugin_vect[i]->descriptor->run(plugin_vect[i]->handle, ladspa_buflen);
+			}
+			if (plugin_vect[i]->handle2) {
+				plugin_vect[i]->descriptor->run(plugin_vect[i]->handle2, ladspa_buflen);
+			}
+		}
+		plugin_lock = 0;
+
+		if (!options.ladspa_is_postfader) {
+			for (i = 0; i < bufsize; i++) {
+				l_buf[i] *= left_gain;
+				r_buf[i] *= right_gain;
+			}
+		}
+#endif /* HAVE_LADSPA */
+
+		for (i = 0; i < bufsize; i++) {
+			if (l_buf[i] > 1.0)
+				l_buf[i] = 1.0;
+			else if (l_buf[i] < -1.0)
+				l_buf[i] = -1.0;
+
+			if (r_buf[i] > 1.0)
+				r_buf[i] = 1.0;
+			else if (r_buf[i] < -1.0)
+				r_buf[i] = -1.0;
+
+			pa_short_buf[2*i] = floorf(32767.0 * l_buf[i]);
+			pa_short_buf[2*i+1] = floorf(32767.0 * r_buf[i]);
+		}
+
+		/* write data to audio device */
+        ret = pa_simple_write(pa, pa_short_buf, 2*n_avail * sizeof(short), &err);
+		if (ret != 0)
+			fprintf(stderr, "pulse_thread: Error writing to audio device\n%s", pa_strerror(err));
+
+	}
+ pulse_finish:
+	return 0;
+}
+#endif /* HAVE_PULSE */
+
+
 /* OSS output thread */
 #ifdef HAVE_OSS
 void *
@@ -1678,7 +1831,51 @@
 #endif /* HAVE_JACK */
 
 
+#ifdef HAVE_PULSE
+/* return values:
+ *  0 : success
+ *  -1: sample rate out of range
+ *  +N : unable to initilize PulseAudio
+ *       N = error code returned by PulseAudio.
+ */
+/* 2009-08-20 added by Hong Jen Yee (PCMan) <pcman.tw@gmail.com> */
+int
+pulse_init(thread_info_t * info, int verbose, int realtime, int priority) {
 
+    int err = 0;
+    if (info->out_SR > MAX_SAMPLERATE) {
+		if (verbose) {
+			fprintf(stderr, "\nThe sample rate you set (%ld Hz) is higher than MAX_SAMPLERATE.\n",
+				info->out_SR);
+			fprintf(stderr, "This is an arbitrary limit, which you may safely enlarge "
+				"if you really need to.\n");
+			fprintf(stderr, "Currently MAX_SAMPLERATE = %d Hz.\n", MAX_SAMPLERATE);
+		}
+        return -1;
+    }
+
+    info->pa_spec.format = PA_SAMPLE_S16NE;
+    info->pa_spec.channels = 2;
+    info->pa_spec.rate = info->out_SR;
+
+    info->pa = pa_simple_new(NULL, "Aqualung", PA_STREAM_PLAYBACK, NULL,
+                             "Music", &info->pa_spec, NULL, NULL, &err);
+    if(!info->pa)
+    {
+        if(verbose)
+            fprintf(stderr, "Unable to initilize PulseAudio: %s\n", pa_strerror(err));
+        return err;
+    }
+
+	/* start PulseAudio output thread */
+	AQUALUNG_THREAD_CREATE(info->pulse_thread_id, NULL, pulse_thread, info)
+	set_thread_priority(info->pulse_thread_id, "PulseAudio output", realtime, priority);
+
+	return 0;
+}
+#endif /* HAVE_PULSE */
+
+
 #ifdef _WIN32
 
 #define WIN32_BUFFER_LEN (1<<16)
@@ -2471,9 +2668,9 @@
 		{ 0, 0, 0, 0 }
 	};
 
-#if defined(HAVE_JACK) || defined(HAVE_ALSA) || defined(HAVE_OSS) || defined(HAVE_SNDIO)
+#if defined(HAVE_JACK) || defined(HAVE_ALSA) || defined(HAVE_OSS) || defined(HAVE_SNDIO) || defined(HAVE_PULSE)
 	int auto_driver_found = 0;
-#endif /* jack || alsa || oss || sndio */
+#endif /* jack || alsa || oss || sndio || pulseaudio */
 
 	if (setenv("LC_NUMERIC", "POSIX", 1) != 0) {
 		fprintf(stderr, "aqualung main(): setenv(\"LC_NUMERIC\", \"POSIX\") failed\n");
@@ -2570,6 +2767,22 @@
 					free(output_str);
 					break;
 				}
+                /* 2009-08-20 added by Hong Jen Yee (PCMan) <pcman.tw@gmail.com> */
+				if (strcmp(output_str, "pulse") == 0) {
+#ifdef HAVE_PULSE
+					output = PULSE_DRIVER;
+#else
+					fprintf(stderr,
+						"You selected PulseAudio output, but this instance of Aqualung "
+						"is compiled\n"
+						"without PulseAudio output support. Type aqualung -v to get a "
+						"list of\n"
+						"compiled-in features.\n");
+					exit(1);
+#endif /* HAVE_PULSE*/
+					free(output_str);
+					break;
+				}
 				if (strcmp(output_str, "alsa") == 0) {
 #ifdef HAVE_ALSA
 					output = ALSA_DRIVER;
@@ -2935,6 +3148,26 @@
 	if (output == 0) {
 		printf("No output driver specified, probing for a usable driver.\n");
 	}
+#ifdef HAVE_PULSE
+	if (output == 0) {
+		int ret;
+
+		/* probe PulseAudio */
+		printf("Probing PulseAudio driver... ");
+        thread_info.out_SR = rate;
+
+		ret = pulse_init(&thread_info, 0, try_realtime, priority);
+		if (ret == -1) {
+			printf("sample rate out of range\n");
+		} else if (ret > 0) {
+			printf("unable to initialize PulseAudio: %s\n", pa_strerror(ret));
+		} else {
+			output = PULSE_DRIVER;
+			auto_driver_found = 1;
+			printf("OK\n");
+		}
+	}
+#endif /* HAVE_PULSE */
 #ifdef HAVE_JACK
 	if (output == 0) {
 		int ret;
@@ -3100,6 +3333,13 @@
 	}
 #endif /* HAVE_OSS */
 
+/* 2009-08-20 added by Hong Jen Yee (PCMan) <pcman.tw@gmail.com> */
+#ifdef HAVE_PULSE
+	if (output == PULSE_DRIVER) {
+		thread_info.out_SR = rate;
+	}
+#endif /* HAVE_PULSE */
+
 #ifdef _WIN32
 	if (output == WIN32_DRIVER) {
 		thread_info.out_SR = rate;
@@ -3137,6 +3377,18 @@
 	}
 #endif /* HAVE_OSS */
 
+/* 2009-08-20 added by Hong Jen Yee (PCMan) <pcman.tw@gmail.com> */
+#ifdef HAVE_PULSE
+	if (output == PULSE_DRIVER) {
+		if (!auto_driver_found) {
+			int ret = pulse_init(&thread_info, 1, try_realtime, priority);
+			if (ret != 0) {
+				exit(1);
+			}
+		}
+	}
+#endif /* HAVE_PULSE */
+
 #ifdef HAVE_ALSA
 	if (output == ALSA_DRIVER) {
 		AQUALUNG_THREAD_CREATE(thread_info.alsa_thread_id, NULL, alsa_thread, &thread_info)
@@ -3175,6 +3427,15 @@
 	}
 #endif /* HAVE_OSS */
 
+/* 2009-08-20 added by Hong Jen Yee (PCMan) <pcman.tw@gmail.com> */
+#ifdef HAVE_PULSE
+	if (output == PULSE_DRIVER) {
+		AQUALUNG_THREAD_JOIN(thread_info.pulse_thread_id)
+		free(thread_info.pa_short_buf);
+        pa_simple_free(thread_info.pa);
+	}
+#endif /* HAVE_PULSE */
+
 #ifdef HAVE_ALSA
 	if (output == ALSA_DRIVER) {
 		AQUALUNG_THREAD_JOIN(thread_info.alsa_thread_id)
Index: src/core.h
===================================================================
--- src/core.h	(revision 1072)
+++ src/core.h	(working copy)
@@ -64,6 +64,10 @@
 #include <sndio.h>
 #endif /* HAVE_SNDIO */
 
+#ifdef HAVE_PULSE
+#define PULSE_DRIVER 6
+#include <pulse/simple.h>
+#endif /* HAVE_PULSE */
 
 #define MAX_SAMPLERATE 96000
 
@@ -113,6 +117,13 @@
 	AQUALUNG_THREAD_DECLARE(win32_thread_id)
 #endif /* _WIN32 */
 
+#ifdef HAVE_PULSE
+	AQUALUNG_THREAD_DECLARE(pulse_thread_id)
+    pa_simple *pa;
+    pa_sample_spec pa_spec;
+	short * pa_short_buf;
+#endif /* HAVE_PULSE */
+
 	u_int32_t rb_size;
 	unsigned long in_SR;
 	unsigned long in_SR_prev;
Index: configure.ac
===================================================================
--- configure.ac	(revision 1072)
+++ configure.ac	(working copy)
@@ -287,7 +287,30 @@
 	fi
 fi
 
+AC_MSG_CHECKING(for PulseAudio support)
+AC_ARG_WITH(
+	pulse,
+	[  --with-pulse=yes,no     compile with PulseAudio support (default: yes)],
+	pulse="$withval",
+	pulse="detect")
 
+if test "$pulse" = "no"; then
+	AC_MSG_RESULT(no)
+else
+	AC_CHECK_LIB(pulse-simple, pa_simple_new, [lib=yes], [lib=no])
+	if test "$lib" = "yes"; then
+	        pulse_CFLAGS=`pkg-config --cflags libpulse-simple`
+		pulse_LIBS=`pkg-config --libs libpulse-simple`
+		AC_DEFINE([HAVE_PULSE], [1], [Defined if compile with PulseAudio support])
+	fi
+	if test "$lib" = "no" -a "$pulse" = "yes"; then
+		AC_MSG_ERROR(You do not appear to have the PulseAudio installed. Grab it from http://pulseaudio.org/)
+	fi
+	if test "$pulse" = "detect"; then
+	        pulse=$lib
+	fi
+fi
+
 AC_MSG_CHECKING(for Sample Rate Converter support)
 AC_ARG_WITH(
 	src,
@@ -911,7 +934,6 @@
 	fi
 fi
 
-
 # Compiler and linker variables
 AQUALUNG_SKINDIR="-DAQUALUNG_SKINDIR=\\\"$datadir/aqualung/skin\\\""
 AQUALUNG_LOCALEDIR="-DAQUALUNG_LOCALEDIR=\\\"$datadir/locale\\\""
@@ -919,8 +941,8 @@
 
 CFLAGS="$CFLAGS $BUILD_CFLAGS -Wall $PLATFORM_CFLAGS $AQUALUNG_SKINDIR $AQUALUNG_LOCALEDIR $AQUALUNG_DATADIR -D_GNU_SOURCE"
 CXXFLAGS="$CFLAGS"
-CPPFLAGS="$gtk_CFLAGS $glib_CFLAGS $xml_CFLAGS $alsa_CFLAGS $jack_CFLAGS $cdda_CFLAGS"
-LIBS="decoder/libdecoder.a encoder/libencoder.a $gtk_LIBS $glib_LIBS $xml_LIBS $jack_LIBS $lrdf_LIBS $src_LIBS $alsa_LIBS $sndio_LIBS $oss_LIBS $sndfile_LIBS $flac_LIBS $ogg_LIBS $wavpack_LIBS $speex_LIBS $mad_LIBS $mod_LIBS $mpc_LIBS $mac_LIBS $lavc_LIBS $vorbisenc_LIBS $lame_LIBS $cdda_LIBS $cddb_LIBS $ifp_LIBS $PLATFORM_LIBS $z_LIBS $bz2_LIBS $lua_LIBS"
+CPPFLAGS="$gtk_CFLAGS $glib_CFLAGS $xml_CFLAGS $alsa_CFLAGS $jack_CFLAGS $cdda_CFLAGS $pulse_CFLAGS"
+LIBS="decoder/libdecoder.a encoder/libencoder.a $gtk_LIBS $glib_LIBS $xml_LIBS $jack_LIBS $lrdf_LIBS $src_LIBS $alsa_LIBS $sndio_LIBS $oss_LIBS $sndfile_LIBS $flac_LIBS $ogg_LIBS $wavpack_LIBS $speex_LIBS $mad_LIBS $mod_LIBS $mpc_LIBS $mac_LIBS $lavc_LIBS $vorbisenc_LIBS $lame_LIBS $cdda_LIBS $cddb_LIBS $ifp_LIBS $PLATFORM_LIBS $z_LIBS $bz2_LIBS $lua_LIBS $pulse_LIBS"
 
 
 AC_OUTPUT([Makefile \
@@ -976,6 +998,7 @@
 echo "      LAME (MP3)                          :  $lame"
 echo
 echo "  Output driver support:"
+echo "      PulseAudio                          :  $pulse"
 echo "      sndio Audio                         :  $sndio"
 echo "      OSS Audio                           :  $oss"
 echo "      ALSA Audio                          :  $alsa"
