diff --git a/configure.in b/configure.in
index b5a6d3f9384649e730cdc3b891db0ada6ac9fede..beaca639f106d514c0155f128689167198ddb315 100644
--- a/configure.in
+++ b/configure.in
@@ -149,7 +149,7 @@ AC_CHECK_HEADERS(sys/soundcard.h)
 AC_CHECK_HEADERS(machine/soundcard.h)
 AM_CONDITIONAL(HAVE_OSS,test "${ac_cv_header_sys_soundcard_h}" = "yes" || test "${ac_cv_header_machine_soundcard_h}" = "yes")
 
-dnl Check for ALSA
+dnl Check for ALSA 0.5.x
 
 AC_ARG_ENABLE(alsa, [  --enable-alsa           include alsa 0.5 output plugin ],
 [ BUILD_ALSA="$enableval" ],[ BUILD_ALSA="yes" ])
@@ -167,6 +167,24 @@ else
 fi
 AC_SUBST(ALSA_LIBS)
 
+dnl Check for ALSA 0.9.x
+
+AC_ARG_ENABLE(alsa09, [  --enable-alsa09           include alsa 0.9 output plugin ],
+[ BUILD_ALSA09="$enableval" ],[ BUILD_ALSA09="yes" ])
+
+if test "$BUILD_ALSA" = "yes"; then
+   AC_CHECK_LIB(asound, snd_pcm_open, have_alsa09=yes, have_alsa09=no)
+   AC_CHECK_HEADER(sys/asoundlib.h, , have_alsa09=no)
+   AM_CONDITIONAL(HAVE_ALSA09,test "x$have_alsa09" = xyes)
+fi
+
+if test "x$have_alsa09" = xyes; then
+	ALSA09_LIBS="-lasound"
+else
+	ALSA09_LIBS=""
+fi
+AC_SUBST(ALSA09_LIBS)
+
 dnl Check for Sun audio
 
 AC_CHECK_HEADERS(sys/audioio.h)
@@ -202,4 +220,5 @@ AM_CONDITIONAL(HAVE_IRIX,test "x$have_irix" = xyes)
 
 AM_CONDITIONAL(HAVE_SOLARIS,test "x$have_solaris" = xyes)
 
-AC_OUTPUT(Makefile src/Makefile doc/Makefile include/Makefile include/ao/Makefile include/ao/os_types.h src/plugins/Makefile src/plugins/esd/Makefile src/plugins/oss/Makefile src/plugins/alsa/Makefile src/plugins/sun/Makefile src/plugins/irix/Makefile src/plugins/arts/Makefile debian/Makefile)
+AC_OUTPUT(Makefile src/Makefile doc/Makefile include/Makefile include/ao/Makefile include/ao/os_types.h src/plugins/Makefile src/plugins/esd/Makefile src/plugins/oss/Makefile src/plugins/alsa/Makefile src/plugins/alsa09/Makefile src/plugins/sun/Makefile src/plugins/irix/Makefile src/plugins/arts/Makefile debian/Makefile)
+
diff --git a/src/ao_private.h b/src/ao_private.h
index b26e72dcce09e1610849148163b3ab895bfbc6d2..591f81557c31f3737121a1bfd5cc1d8a034d5b31 100644
--- a/src/ao_private.h
+++ b/src/ao_private.h
@@ -42,7 +42,7 @@
 #if defined(__OpenBSD__)	
 #define DLOPEN_FLAG RTLD_LAZY
 #else
-#define DLOPEN_FLAG RTLD_NOW
+#define DLOPEN_FLAG (RTLD_NOW | RTLD_GLOBAL)
 #endif
 
 /* --- Constants --- */
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index 3b9cd9e1a1ae118098fe46bf1ab284a06152982b..a38c85ee16694af083e99f83e3d2f6738700ac39 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -1,4 +1,4 @@
 ## Process this file with automake to produce Makefile.in
 
 AUTOMAKE_OPTIONS = foreign
-SUBDIRS = oss esd arts alsa sun irix # macosx
+SUBDIRS = oss esd arts alsa alsa09 sun irix # macosx
diff --git a/src/plugins/alsa09/Makefile.am b/src/plugins/alsa09/Makefile.am
new file mode 100644
index 0000000000000000000000000000000000000000..c1e19f003884406b152e3e4513e294d8bac2b79d
--- /dev/null
+++ b/src/plugins/alsa09/Makefile.am
@@ -0,0 +1,28 @@
+## Process this file with automake to produce Makefile.in
+
+AUTOMAKE_OPTIONS = foreign
+
+if HAVE_ALSA09
+
+alsa09ltlibs = libalsa09.la
+alsa09ldflags = -export-dynamic -avoid-version
+alsa09sources = ao_alsa09.c
+
+else
+
+alsa09ltlibs =
+alsa09ldflags =
+alsa09sources =
+
+endif
+
+INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/include
+
+libdir = $(plugindir)
+lib_LTLIBRARIES = $(alsa09ltlibs)
+
+libalsa09_la_LDFLAGS = $(alsa09ldflags)
+libalsa09_la_LIBADD = @ALSA09_LIBS@
+libalsa09_la_SOURCES = $(alsa09sources)
+
+EXTRA_DIST = ao_alsa09.c
diff --git a/src/plugins/alsa09/ao_alsa09.c b/src/plugins/alsa09/ao_alsa09.c
new file mode 100644
index 0000000000000000000000000000000000000000..cc454cbe42d74a10eb2b323395d29403d3a4a2b5
--- /dev/null
+++ b/src/plugins/alsa09/ao_alsa09.c
@@ -0,0 +1,309 @@
+/*
+ *
+ *  ao_alsa09.c
+ *
+ *      Copyright (C) Stan Seibert - July 2000, July 2001
+ *
+ *  This file is part of libao, a cross-platform library.  See
+ *  README for a history of this source code.
+ *
+ *  libao is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  libao is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GNU Make; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <string.h>
+
+#include <sys/asoundlib.h>
+#include <ao/ao.h>
+#include <ao/plugin.h>
+
+#define AO_ALSA_BUF_SIZE 32768
+
+static char *ao_alsa_options[] = {
+	"dev",
+	"buf_size"
+};
+static ao_info ao_alsa_info =
+{
+	AO_TYPE_LIVE,
+	"Advanced Linux Sound Architecture (ALSA) output",
+	"alsa09",
+	"Bill Currie <bill@taniwha.org>",
+	"Outputs to the Advanced Linux Sound Architecture version 0.9.x.",
+	AO_FMT_NATIVE,
+	30,
+	ao_alsa_options,
+	2
+};
+
+
+typedef struct ao_alsa_internal
+{
+	snd_pcm_t *pcm_handle;
+	char *buf;
+	int buf_size;
+	int buf_end;
+	int sample_size;
+	char *dev;
+} ao_alsa_internal;
+
+
+int ao_plugin_test()
+{
+	snd_pcm_t *handle;
+	int err;
+
+	err = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK,
+			   SND_PCM_NONBLOCK);
+
+	if (err != 0)
+		return 0; /* Cannot use this plugin with default parameters */
+	else {
+		snd_pcm_close(handle);
+		return 1; /* This plugin works in default mode */
+	}
+}
+
+
+ao_info *ao_plugin_driver_info(void)
+{
+	return &ao_alsa_info;
+}
+
+
+int ao_plugin_device_init(ao_device *device)
+{
+	ao_alsa_internal *internal;
+
+	internal = (ao_alsa_internal *) malloc(sizeof(ao_alsa_internal));
+
+	if (internal == NULL)	
+		return 0; /* Could not initialize device memory */
+	
+	internal->buf_size = AO_ALSA_BUF_SIZE;
+	internal->dev = strdup ("default");
+	if (!internal->dev) {
+		free (internal);
+		return 0;
+	}
+	
+	device->internal = internal;
+
+	return 1; /* Memory alloc successful */
+}
+
+
+int ao_plugin_set_option(ao_device *device, const char *key, const char *value)
+{
+	ao_alsa_internal *internal = (ao_alsa_internal *) device->internal;
+
+	if (!strcmp(key, "dev")) {
+		if (internal->dev)
+			free (internal->dev);
+		internal->dev = strdup (value);
+		if (!internal->dev)
+			return 0;
+	}
+	else if (!strcmp(key, "buf_size"))
+		internal->buf_size = atoi(value);
+
+	return 1;
+}
+
+int ao_plugin_open(ao_device *device, ao_sample_format *format)
+{
+	ao_alsa_internal *internal = (ao_alsa_internal *) device->internal;
+	snd_pcm_hw_params_t *hwparams;
+
+	int err;
+	int fmt;
+	char *cmd;
+
+	internal->buf = malloc(internal->buf_size);
+	internal->buf_end = 0;
+	if (internal->buf == NULL)
+	  return 0;  /* Could not alloc swap buffer */
+
+
+	/* Open the ALSA device */
+	err = snd_pcm_open(&(internal->pcm_handle), internal->dev,
+			SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
+	if (err < 0) {
+		free (internal->buf);
+		return 0;
+	}
+
+	snd_pcm_hw_params_alloca(&hwparams);
+
+	cmd = "snd_pcm_hw_params_any";
+	err = snd_pcm_hw_params_any(internal->pcm_handle, hwparams);
+	if (err < 0)
+		goto error;
+
+	cmd = "snd_pcm_hw_params_set_access";
+	err = snd_pcm_hw_params_set_access(internal->pcm_handle, hwparams,
+			SND_PCM_ACCESS_RW_INTERLEAVED);
+	if (err < 0)
+		goto error;
+
+	switch (format->bits) {
+	case 8  : fmt = SND_PCM_FORMAT_S8;
+		  break;
+	case 16 : fmt = 
+		  device->client_byte_format == AO_FMT_BIG ?
+		  SND_PCM_FORMAT_S16_BE : SND_PCM_FORMAT_S16_LE;
+		  device->driver_byte_format = device->client_byte_format;
+		  break;
+	default : return 0;
+	}
+	cmd = "snd_pcm_hw_params_set_format";
+	err = snd_pcm_hw_params_set_format(internal->pcm_handle, hwparams, fmt);
+	if (err < 0)
+		goto error;
+
+	cmd = "snd_pcm_hw_params_set_channels";
+	if (format->channels == 1 || format->channels == 2)
+		err = snd_pcm_hw_params_set_channels(internal->pcm_handle,
+				hwparams, format->channels);
+	else
+		return 0;
+	if (err < 0)
+		goto error;
+	internal->sample_size = format->bits * format->channels / 8;
+
+	cmd = "snd_pcm_hw_params_set_rate";
+	err = snd_pcm_hw_params_set_rate_near(internal->pcm_handle, hwparams,
+			format->rate, 0);
+	if (err < 0)
+		goto error;
+
+	cmd = "snd_pcm_hw_params_set_period_size";
+	err = snd_pcm_hw_params_set_period_size(internal->pcm_handle, hwparams,
+			internal->buf_size / internal->sample_size, 0);
+	if (err < 0)
+		goto error;
+
+	cmd = "snd_pcm_hw_params_set_periods";
+	err = snd_pcm_hw_params_set_periods(internal->pcm_handle, hwparams,
+			2, 0);
+	if (err < 0)
+		goto error;
+
+	cmd = "snd_pcm_hw_params";
+	err = snd_pcm_hw_params(internal->pcm_handle, hwparams);
+	if (err < 0)
+		goto error;
+
+	cmd = "snd_pcm_prepare";
+	err = snd_pcm_prepare(internal->pcm_handle);
+	if (err < 0)
+		goto error;
+
+	return 1;
+error:
+	fprintf(stderr, "ALSA %s error: %s\n", cmd, snd_strerror(err));
+	snd_pcm_close(internal->pcm_handle);
+	free(internal->buf);
+	return 0;
+}
+
+
+int _alsa_write_buffer(ao_alsa_internal *s)
+{
+	snd_pcm_t *pcm_handle = s->pcm_handle;
+	int len = s->buf_end / s->sample_size;
+	int err;
+	char *buf = s->buf;
+
+	s->buf_end = 0;
+
+	do {
+		err = snd_pcm_writei (pcm_handle, buf, len);
+		if (err == -EAGAIN)
+			snd_pcm_wait (pcm_handle, 1000);
+	} while (err == -EAGAIN);
+	if (err == -EPIPE) {
+		/* fprintf(stderr, "ALSA: underrun. resetting stream\n"); */
+		snd_pcm_prepare(pcm_handle);
+		err = snd_pcm_writei(pcm_handle, buf, len);
+		if (err != len) {
+			fprintf(stderr, "ALSA write error: %s\n", snd_strerror(err));
+			return 0;
+		} else if (err < 0) {
+			fprintf(stderr, "ALSA write error: %s\n", snd_strerror(err));
+			return 0;
+		}
+	}
+
+	return 1;
+}	
+
+
+int ao_plugin_play(ao_device *device, const char *output_samples, 
+		uint_32 num_bytes)
+{
+	ao_alsa_internal *internal = (ao_alsa_internal *) device->internal;
+	
+	int packed = 0;
+	int copy_len;
+	char *samples = (char *) output_samples;
+	int ok = 1;
+
+	while (packed < num_bytes && ok) {
+		/* Pack the buffer */
+		if (num_bytes-packed < internal->buf_size - internal->buf_end)
+			copy_len = num_bytes - packed;
+		else
+			copy_len = internal->buf_size - internal->buf_end;
+
+		memcpy(internal->buf + internal->buf_end, samples + packed, 
+		       copy_len); 
+		packed += copy_len;
+		internal->buf_end += copy_len;
+
+		if(internal->buf_end == internal->buf_size)
+			ok = _alsa_write_buffer(internal);
+	}
+
+	return ok;
+}
+
+
+int ao_plugin_close(ao_device *device)
+{
+	ao_alsa_internal *internal = (ao_alsa_internal *) device->internal;
+	int result;
+
+	/* Clear buffer */
+	result = _alsa_write_buffer(internal);
+	snd_pcm_close(internal->pcm_handle);
+	free(internal->buf);
+
+	return result;
+}
+
+
+void ao_plugin_device_clear(ao_device *device)
+{
+	ao_alsa_internal *internal = (ao_alsa_internal *) device->internal;
+	if (internal->dev)
+		free (internal->dev);
+	free(internal);
+}