[xiph-commits] r16832 - in trunk/ao: . src/plugins src/plugins/alsa

xiphmont at svn.xiph.org xiphmont at svn.xiph.org
Tue Jan 26 23:40:50 PST 2010


Author: xiphmont
Date: 2010-01-26 23:40:50 -0800 (Tue, 26 Jan 2010)
New Revision: 16832

Added:
   trunk/ao/src/plugins/alsa/
   trunk/ao/src/plugins/alsa/ao_alsa.c
Removed:
   trunk/ao/src/plugins/alsa/ao_alsa09.c
   trunk/ao/src/plugins/alsa05/
   trunk/ao/src/plugins/alsa09/
Modified:
   trunk/ao/configure.ac
   trunk/ao/src/plugins/Makefile.am
   trunk/ao/src/plugins/alsa/Makefile.am
Log:
Remove old alsa05 driver
rename alsa09 to alsa
update alsa option list



Modified: trunk/ao/configure.ac
===================================================================
--- trunk/ao/configure.ac	2010-01-27 07:25:29 UTC (rev 16831)
+++ trunk/ao/configure.ac	2010-01-27 07:40:50 UTC (rev 16832)
@@ -241,58 +241,39 @@
 AM_CONDITIONAL(HAVE_OSS,test "${ac_cv_header_sys_soundcard_h}" = "yes" || test "${ac_cv_header_machine_soundcard_h}" = "yes")
 
 
-dnl Check for ALSA 0.5.x
+dnl Check for ALSA 0.9/1.0
 
-AC_ARG_ENABLE(alsa, [  --enable-alsa           include alsa 0.5 output plugin ],
+AC_ARG_ENABLE(alsa, [  --enable-alsa         include alsa 0.9/1.0 output plugin ],
 [ BUILD_ALSA="$enableval" ],[ BUILD_ALSA="yes" ])
+AC_ARG_ENABLE(alsa-mmap,
+   [  --enable-alsa-mmap          use mmio with alsa ],
+   [ BUILD_ALSAMMIO="$enableval" ],[ BUILD_ALSAMMIO="no" ])
 
 if test "$BUILD_ALSA" = "yes"; then
-   AC_CHECK_LIB(asound, snd_pcm_channel_params, have_alsa=yes, have_alsa=no)
-   AC_CHECK_HEADER(sys/asoundlib.h, , have_alsa=no)
+   AC_CHECK_LIB(asound, snd_pcm_open, have_alsa=yes, have_alsa=no)
+   AC_CHECK_HEADER(alsa/asoundlib.h, , have_alsa=no)
+   if test "$BUILD_ALSAMMIO" = "yes" ; then
+      AC_CHECK_HEADER(sys/mman.h, have_alsammio=yes, have_alsammio=no)
+   fi
+
 fi
 
 if test "x$have_alsa" = xyes; then
 	ALSA_LIBS="-lasound"
+	if test "x$have_alsammio" = xyes; then
+		AC_DEFINE(USE_ALSA_MMIO)
+	fi
 else
 	ALSA_LIBS=""
 fi
 AM_CONDITIONAL(HAVE_ALSA,test "x$have_alsa" = xyes)
 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" ])
-AC_ARG_ENABLE(alsa09-mmap,
-   [  --enable-alsa09-mmap          use mmio with alsa 0.9 (experimental!) ],
-   [ BUILD_ALSA09MMIO="$enableval" ],[ BUILD_ALSA09MMIO="no" ])
-
-if test "$BUILD_ALSA09" = "yes"; then
-   AC_CHECK_LIB(asound, snd_pcm_open, have_alsa09=yes, have_alsa09=no)
-   AC_CHECK_HEADER(alsa/asoundlib.h, , have_alsa09=no)
-   if test "$BUILD_ALSA09MMIO" = "yes" ; then
-      AC_CHECK_HEADER(sys/mman.h, have_alsa09mmio=yes, have_alsa09mmio=no)
-   fi
-
-fi
-
-if test "x$have_alsa09" = xyes; then
-	ALSA09_LIBS="-lasound"
-	if test "x$have_alsa09mmio" = xyes; then
-		AC_DEFINE(USE_ALSA_MMIO)
-	fi
-else
-	ALSA09_LIBS=""
-fi
-AM_CONDITIONAL(HAVE_ALSA09,test "x$have_alsa09" = xyes)
-AC_SUBST(ALSA09_LIBS)
-
 dnl Decide whether we need to enable the workaround for broken OSS APIs
 dnl such as the OSS emulation in ALSA.
 
 AC_ARG_ENABLE(broken-oss, [  --enable-broken-oss           workaround for some OSS drivers (see README for details)],,
-if test "x$have_alsa" = "xyes" -o "x$have_alsa09" = "xyes"; then
+if test "x$have_alsa" = "xyes" -o "x$have_alsa" = "xyes"; then
    enable_broken_oss="yes"
 fi)
 
@@ -421,4 +402,4 @@
 AC_SUBST(PLUGIN_LDFLAGS)
 
 
-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/alsa05/Makefile src/plugins/alsa09/Makefile src/plugins/sun/Makefile src/plugins/irix/Makefile src/plugins/arts/Makefile src/plugins/macosx/Makefile src/plugins/nas/Makefile src/plugins/pulse/Makefile ao.pc)
+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 src/plugins/macosx/Makefile src/plugins/nas/Makefile src/plugins/pulse/Makefile ao.pc)

Modified: trunk/ao/src/plugins/Makefile.am
===================================================================
--- trunk/ao/src/plugins/Makefile.am	2010-01-27 07:25:29 UTC (rev 16831)
+++ trunk/ao/src/plugins/Makefile.am	2010-01-27 07:40:50 UTC (rev 16832)
@@ -1,4 +1,4 @@
 ## Process this file with automake to produce Makefile.in
 
 AUTOMAKE_OPTIONS = foreign
-SUBDIRS = oss esd arts alsa05 alsa09 sun irix macosx nas pulse
+SUBDIRS = oss esd arts alsa sun irix macosx nas pulse

Modified: trunk/ao/src/plugins/alsa/Makefile.am
===================================================================
--- trunk/ao/src/plugins/alsa09/Makefile.am	2010-01-24 10:12:03 UTC (rev 16797)
+++ trunk/ao/src/plugins/alsa/Makefile.am	2010-01-27 07:40:50 UTC (rev 16832)
@@ -2,25 +2,25 @@
 
 AUTOMAKE_OPTIONS = foreign
 
-if HAVE_ALSA09
+if HAVE_ALSA
 
-alsa09ltlibs = libalsa09.la
-alsa09sources = ao_alsa09.c
+alsaltlibs = libalsa.la
+alsasources = ao_alsa.c
 
 else
 
-alsa09ltlibs =
-alsa09sources =
+alsaltlibs =
+alsasources =
 
 endif
 
 INCLUDES = -I$(top_builddir)/include/ao -I$(top_srcdir)/include
 
 libdir = $(plugindir)
-lib_LTLIBRARIES = $(alsa09ltlibs)
+lib_LTLIBRARIES = $(alsaltlibs)
 
-libalsa09_la_LDFLAGS = @PLUGIN_LDFLAGS@
-libalsa09_la_LIBADD = @ALSA09_LIBS@
-libalsa09_la_SOURCES = $(alsa09sources)
+libalsa_la_LDFLAGS = @PLUGIN_LDFLAGS@
+libalsa_la_LIBADD = @ALSA_LIBS@
+libalsa_la_SOURCES = $(alsasources)
 
-EXTRA_DIST = ao_alsa09.c
+EXTRA_DIST = ao_alsa.c

Copied: trunk/ao/src/plugins/alsa/ao_alsa.c (from rev 16797, trunk/ao/src/plugins/alsa09/ao_alsa09.c)
===================================================================
--- trunk/ao/src/plugins/alsa/ao_alsa.c	                        (rev 0)
+++ trunk/ao/src/plugins/alsa/ao_alsa.c	2010-01-27 07:40:50 UTC (rev 16832)
@@ -0,0 +1,568 @@
+/*
+ *
+ *  ao_alsa.c
+ *
+ *      Copyright (C) Stan Seibert - July 2000, July 2001
+ *      Modifications Copyright (C) Monty - January 2010
+ *
+ *  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.
+ *
+ *  Largely rewritten 2/18/2002 Kevin Cody Jr <kevinc at wuff.dhs.org>
+ *
+ */
+
+#define ALSA_PCM_NEW_HW_PARAMS_API
+#define ALSA_PCM_NEW_SW_PARAMS_API
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <string.h>
+
+#include <alsa/asoundlib.h>
+#include <ao/ao.h>
+#include <ao/plugin.h>
+
+/* default 500 millisecond buffer */
+#define AO_ALSA_BUFFER_TIME 500000
+
+/* the period time is calculated if not given as an option */
+#define AO_ALSA_PERIOD_TIME 0
+
+/* number of samples between interrupts
+ * supplying a period_time to ao overrides the use of this  */
+#define AO_ALSA_SAMPLE_XFER 256
+
+/* set mmap to default if enabled at compile time, otherwise, mmap isn't
+   the default */
+#ifdef USE_ALSA_MMIO
+#define AO_ALSA_WRITEI snd_pcm_mmap_writei
+#define AO_ALSA_ACCESS_MASK SND_PCM_ACCESS_MMAP_INTERLEAVED
+#else
+#define AO_ALSA_WRITEI snd_pcm_writei
+#define AO_ALSA_ACCESS_MASK SND_PCM_ACCESS_RW_INTERLEAVED
+#endif
+
+typedef snd_pcm_sframes_t ao_alsa_writei_t(snd_pcm_t *pcm, const void *buffer,
+						snd_pcm_uframes_t size);
+
+static char *ao_alsa_options[] = {
+	"dev",
+	"buffer_time",
+        "period_time",
+	"use_mmap",
+        "matrix",
+        "verbose",
+        "quiet"
+};
+
+
+static ao_info ao_alsa_info =
+{
+	AO_TYPE_LIVE,
+	"Advanced Linux Sound Architecture (ALSA) output",
+	"alsa",
+	"Bill Currie <bill at taniwha.org>/Kevin Cody, Jr. <kevinc at wuff.dhs.org>",
+	"Outputs to the Advanced Linux Sound Architecture version 0.9.x/1.x.x.",
+	AO_FMT_NATIVE,
+	35,
+	ao_alsa_options,
+	7
+};
+
+
+typedef struct ao_alsa_internal
+{
+	snd_pcm_t *pcm_handle;
+	unsigned int buffer_time;
+	unsigned int period_time;
+	snd_pcm_uframes_t buffer_size;
+	snd_pcm_uframes_t period_size;
+	int sample_size;
+	snd_pcm_format_t bitformat;
+	char *dev;
+	char *cmd;
+	ao_alsa_writei_t * writei;
+	snd_pcm_access_t access_mask;
+} ao_alsa_internal;
+
+
+/* determine if parameters are requires for this particular plugin */
+int ao_plugin_test()
+{
+	snd_pcm_t *handle;
+	int err;
+
+	/* Use nonblock flag when testing to avoid getting stuck if the device
+	   is in use. Try several devices, as 'default' usually means 'stereo only'. */
+	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 */
+	}
+}
+
+
+/* return the address of the driver info structure */
+ao_info *ao_plugin_driver_info(void)
+{
+	return &ao_alsa_info;
+}
+
+
+/* initialize internal data structures */
+int ao_plugin_device_init(ao_device *device)
+{
+	ao_alsa_internal *internal;
+
+	internal = (ao_alsa_internal *) calloc(1,sizeof(ao_alsa_internal));
+
+	if (internal == NULL)
+		return 0;
+
+	internal->buffer_time = AO_ALSA_BUFFER_TIME;
+	internal->period_time = AO_ALSA_PERIOD_TIME;
+	internal->writei = AO_ALSA_WRITEI;
+	internal->access_mask = AO_ALSA_ACCESS_MASK;
+
+	device->internal = internal;
+
+	return 1;
+}
+
+
+/* pass application parameters regarding the sound device */
+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);
+		if (!(internal->dev = strdup(value)))
+			return 0;
+	}
+	else if (!strcmp(key, "buffer_time"))
+		internal->buffer_time = atoi(value) * 1000;
+	else if (!strcmp(key, "period_time"))
+		internal->period_time = atoi(value);
+	else if (!strcmp(key,"use_mmap")) {
+		if(!strcmp(value,"yes") || !strcmp(value,"y") || 
+			!strcmp(value,"true") || !strcmp(value,"t") ||
+			!strcmp(value,"1"))
+		{
+			internal->writei = snd_pcm_mmap_writei;
+			internal->access_mask = SND_PCM_ACCESS_MMAP_INTERLEAVED;
+		}
+		else {
+			internal->writei = snd_pcm_writei;
+			internal->access_mask = SND_PCM_ACCESS_RW_INTERLEAVED;
+		}
+	}
+
+	return 1;
+}
+
+
+/* determine the alsa bitformat for a given bitwidth and endianness */
+static inline int alsa_get_sample_bitformat(int bitwidth, int bigendian)
+{
+	int ret;
+
+	switch (bitwidth) {
+	case 8  : ret = SND_PCM_FORMAT_S8;
+		  break;
+	case 16 : ret = SND_PCM_FORMAT_S16;
+		  break;
+	case 24 : ret = SND_PCM_FORMAT_S24;
+		  break;
+	case 32 : ret = SND_PCM_FORMAT_S32;
+		  break;
+	default : fprintf(stderr,"ALSA: invalid bitwidth %d\n", bitwidth);
+		  return -1;
+	}
+
+	return ret;
+}
+
+
+/* setup alsa data format and buffer geometry */
+static inline int alsa_set_hwparams(ao_alsa_internal *internal,
+		ao_sample_format *format)
+{
+	snd_pcm_hw_params_t   *params;
+	int err;
+	unsigned int rate = format->rate;
+
+	/* allocate the hardware parameter structure */
+	snd_pcm_hw_params_alloca(&params);
+
+	/* fetch all possible hardware parameters */
+	internal->cmd = "snd_pcm_hw_params_any";
+	err = snd_pcm_hw_params_any(internal->pcm_handle, params);
+	if (err < 0)
+		return err;
+
+	/* set the access type */
+	internal->cmd = "snd_pcm_hw_params_set_access";
+	err = snd_pcm_hw_params_set_access(internal->pcm_handle,
+			params, internal->access_mask);
+	if (err < 0)
+		return err;
+
+	/* set the sample bitformat */
+	internal->cmd = "snd_pcm_hw_params_set_format";
+	err = snd_pcm_hw_params_set_format(internal->pcm_handle,
+			params, internal->bitformat);
+	if (err < 0)
+		return err;
+
+	/* set the number of channels */
+	internal->cmd = "snd_pcm_hw_params_set_channels";
+	err = snd_pcm_hw_params_set_channels(internal->pcm_handle,
+			params, (unsigned int)format->channels);
+	if (err < 0)
+		return err;
+
+	/* save the sample size in bytes for posterity */
+	internal->sample_size = format->bits * format->channels / 8;
+
+	/* set the sample rate */
+	internal->cmd = "snd_pcm_hw_params_set_rate_near";
+	err = snd_pcm_hw_params_set_rate_near(internal->pcm_handle,
+			params, &rate, 0);
+	if (err < 0)
+		return err;
+	if (rate > 1.05 * format->rate || rate < 0.95 * format->rate) {
+		fprintf(stderr, "warning: sample rate %i not supported "
+			"by the hardware, using %u\n", format->rate, rate);
+	}
+
+	/* set the length of the hardware sample buffer in microseconds */
+	internal->cmd = "snd_pcm_hw_params_set_buffer_time_near";
+	err = snd_pcm_hw_params_set_buffer_time_near(internal->pcm_handle,
+			params, &(internal->buffer_time), 0);
+	if (err < 0)
+		return err;
+
+	/* calculate a period time of one half sample time */
+	if ((internal->period_time == 0) && (rate > 0))
+		internal->period_time =
+			1000000 * AO_ALSA_SAMPLE_XFER / rate;
+
+	/* set the time per hardware sample transfer */
+	internal->cmd = "snd_pcm_hw_params_set_period_time_near";
+	err = snd_pcm_hw_params_set_period_time_near(internal->pcm_handle,
+			params, &(internal->period_time), 0);
+	if (err < 0)
+		return err;
+
+	/* commit the params structure to the hardware via ALSA */
+	internal->cmd = "snd_pcm_hw_params";
+	err = snd_pcm_hw_params(internal->pcm_handle, params);
+	if (err < 0)
+		return err;
+
+	/* save the period size in frames for posterity */
+	internal->cmd = "snd_pcm_hw_get_period_size";
+	err = snd_pcm_hw_params_get_period_size(params, 
+						&(internal->period_size), 0);
+	if (err < 0)
+		return err;
+
+	/* save the buffer size in frames for posterity */
+	internal->cmd = "snd_pcm_hw_get_buffer_size";
+	err = snd_pcm_hw_params_get_buffer_size(params, 
+						&(internal->buffer_size)); 
+	if (err < 0)
+		return err;
+
+	return 1;
+}
+
+
+/* setup alsa data transfer behavior */
+static inline int alsa_set_swparams(ao_alsa_internal *internal)
+{
+	snd_pcm_sw_params_t   *params;
+	int err;
+
+	/* allocate the software parameter structure */
+	snd_pcm_sw_params_alloca(&params);
+
+	/* fetch the current software parameters */
+	internal->cmd = "snd_pcm_sw_params_current";
+	err = snd_pcm_sw_params_current(internal->pcm_handle, params);
+	if (err < 0)
+		return err;
+
+	/* allow transfers to start when there is one period */
+	internal->cmd = "snd_pcm_sw_params_set_start_threshold";
+	err = snd_pcm_sw_params_set_start_threshold(internal->pcm_handle,
+			params, internal->period_size);
+	if (err < 0)
+		return err;
+
+	/* require a minimum of one full transfer in the buffer */
+	internal->cmd = "snd_pcm_sw_params_set_avail_min";
+	err = snd_pcm_sw_params_set_avail_min(internal->pcm_handle, params,
+			internal->period_size);
+	if (err < 0)
+		return err;
+
+	/* do not align transfers */
+	internal->cmd = "snd_pcm_sw_params_set_xfer_align";
+	err = snd_pcm_sw_params_set_xfer_align(internal->pcm_handle, params, 1);
+	if (err < 0)
+		return err;
+
+	/* commit the params structure to ALSA */
+	internal->cmd = "snd_pcm_sw_params";
+	err = snd_pcm_sw_params(internal->pcm_handle, params);
+	if (err < 0)
+		return err;
+
+	return 1;
+}
+
+
+/* prepare the audio device for playback */
+int ao_plugin_open(ao_device *device, ao_sample_format *format)
+{
+	ao_alsa_internal *internal  = (ao_alsa_internal *) device->internal;
+	int err;
+
+	/* Get the ALSA bitformat first to make sure it's valid */
+	err = alsa_get_sample_bitformat(format->bits,
+			device->client_byte_format == AO_FMT_BIG);
+	if (err < 0)
+		goto error;
+
+	internal->bitformat = err;
+
+	/* Open the ALSA device */
+	internal->cmd = "snd_pcm_open";
+        err=0;
+        if(!internal->dev){
+          char *tmp=NULL;
+          /* we don't try just 'default' as it's a plug device that
+             will accept any number of channels but usually plays back
+             everything as stereo. */
+          switch(format->channels){
+          default:
+          case 8:
+          case 7:
+            err = snd_pcm_open(&(internal->pcm_handle), tmp="surround71",
+                               SND_PCM_STREAM_PLAYBACK, 0);
+            break;
+          case 4:
+          case 3:
+            err = snd_pcm_open(&(internal->pcm_handle), tmp="surround40",
+                               SND_PCM_STREAM_PLAYBACK, 0);
+            if(err==0)break;
+          case 6:
+          case 5:
+            err = snd_pcm_open(&(internal->pcm_handle), tmp="surround51",
+                               SND_PCM_STREAM_PLAYBACK, 0);
+          case 1:
+          case 2:
+            break;
+          }
+
+          if(err){
+            fprintf(stderr,"ERROR: Unable to open ALSA surround device '%s'\n"
+                           "       trying default device...\n",tmp);
+            tmp=NULL;
+          }
+          if(!tmp)
+            err = snd_pcm_open(&(internal->pcm_handle), tmp="default",
+                               SND_PCM_STREAM_PLAYBACK, 0);
+          internal->dev=strdup(tmp);
+
+        }else
+          err = snd_pcm_open(&(internal->pcm_handle), internal->dev,
+                             SND_PCM_STREAM_PLAYBACK, 0);
+	if (err < 0) {
+		internal->pcm_handle = NULL;
+		goto error;
+	}
+
+	/* Set up the hardware parameters, ie sample and buffer specs */
+	err = alsa_set_hwparams(internal, format);
+	if (err < 0)
+		goto error;
+
+	/* Set up the software parameters, ie de-buffering specs */
+	err = alsa_set_swparams(internal);
+	if (err < 0)
+		goto error;
+
+	/* alsa's endinness will be the same as the application's */
+	if (format->bits > 8)
+		device->driver_byte_format = device->client_byte_format;
+
+        if(device->verbose>0)
+          fprintf(stderr,"Using alsa device '%s'\n", internal->dev);
+
+        if(!device->output_matrix){
+          if(!strncasecmp(internal->dev,"plug:",5))
+            if(format->channels>2 && device->verbose>=0)
+              fprintf(stderr,"\nWARNING: No way to determine hardware channel mapping of\n"
+                      "ALSA 'plug:' devices.\n");
+          if(!strcasecmp(internal->dev,"default")){
+            if(format->channels>2 && device->verbose>=0)
+              fprintf(stderr,"\nWARNING: ALSA 'default' device plays only L,R channels.\n");
+            device->output_matrix=strdup("L,R");
+          }else
+            device->output_matrix=strdup("L,R,BL,BR,C,LFE,SL,SR");
+        }
+
+	return 1;
+
+error:
+	fprintf(stderr, "ALSA %s error: %s\n",
+			internal->cmd, snd_strerror(err));
+	if (internal->pcm_handle) {
+		snd_pcm_close(internal->pcm_handle);
+		internal->pcm_handle = NULL;
+	}
+	return 0;
+}
+
+
+/* recover from an alsa exception */
+static inline int alsa_error_recovery(ao_alsa_internal *internal, int err)
+{
+	if (err == -EPIPE) {
+		/* FIXME: underrun length detection */
+		//fprintf(stderr,"ALSA: underrun, at least %dms.\n", 0);
+		/* output buffer underrun */
+		internal->cmd = "underrun recovery: snd_pcm_prepare";
+		err = snd_pcm_prepare(internal->pcm_handle);
+		if (err < 0)
+			return err;
+	} else if (err == -ESTRPIPE) {
+		/* application was suspended, wait until suspend flag clears */
+		internal->cmd = "suspend recovery: snd_pcm_prepare";
+		while ((err = snd_pcm_resume(internal->pcm_handle)) == -EAGAIN)
+			sleep (1);
+
+		if (err < 0) {
+			/* unable to wake up pcm device, restart it */
+			internal->cmd = "suspend recovery: snd_pcm_prepare";
+			err = snd_pcm_prepare(internal->pcm_handle);
+			if (err < 0)
+				return err;
+		}
+		return 0;
+	}
+
+	/* error isn't recoverable */
+	return err;
+}
+
+
+/* play num_bytes of audio data */
+int ao_plugin_play(ao_device *device, const char *output_samples, 
+		uint_32 num_bytes)
+{
+	ao_alsa_internal *internal = (ao_alsa_internal *) device->internal;
+       	uint_32 len = num_bytes / internal->sample_size;
+	char *ptr = (char *) output_samples;
+	int err;
+
+	/* the entire buffer might not transfer at once */
+	while (len > 0) {
+		/* try to write the entire buffer at once */
+		err = internal->writei(internal->pcm_handle, ptr, len);
+
+		/* no data transferred or interrupt signal */
+		if (err == -EAGAIN || err == -EINTR) {
+			continue;
+		}
+
+		if (err < 0) {
+			/* this might be an error, or an exception */
+			err = alsa_error_recovery(internal, err);
+			if (err < 0) {
+				fprintf(stderr,"ALSA write error: %s\n",
+						snd_strerror(err));
+				return 0;
+			}else /* recovered, continue */
+                          continue;
+		}
+
+		/* decrement the sample counter */
+		len -= err;
+
+		/* adjust the start pointer */
+		ptr += err * internal->sample_size;
+	}
+
+	return 1;
+}
+
+
+/* close the audio device */
+int ao_plugin_close(ao_device *device)
+{
+	ao_alsa_internal *internal;
+
+	if (device) {
+		if ((internal = (ao_alsa_internal *) device->internal)) {
+			if (internal->pcm_handle) {
+				snd_pcm_drain(internal->pcm_handle);
+				snd_pcm_close(internal->pcm_handle);
+				internal->pcm_handle=NULL;
+			} else
+				fprintf(stderr,"ao_plugin_close called with uninitialized ao_device->internal->pcm_handle\n");
+		} else
+			fprintf(stderr,"ao_plugin_close called with uninitialized ao_device->internal\n");
+	} else
+		fprintf(stderr,"ao_plugin_close called with uninitialized ao_device\n");
+
+	return 1;
+}
+
+
+/* free the internal data structures */
+void ao_plugin_device_clear(ao_device *device)
+{
+	ao_alsa_internal *internal;
+
+	if (device) {
+		if ((internal = (ao_alsa_internal *) device->internal)) {
+			if (internal->dev)
+				free (internal->dev);
+			else
+				fprintf(stderr,"ao_plugin_device_clear called with uninitialized ao_device->internal->dev\n");
+			if (internal->cmd)
+				internal->cmd = NULL;
+
+			free(device->internal);
+		} else
+			fprintf(stderr,"ao_plugin_device_clear called with uninitialized ao_device->internal\n");
+	} else
+		fprintf(stderr,"ao_plugin_device_clear called with uninitialized ao_device\n");
+}
+

Deleted: trunk/ao/src/plugins/alsa/ao_alsa09.c
===================================================================
--- trunk/ao/src/plugins/alsa09/ao_alsa09.c	2010-01-24 10:12:03 UTC (rev 16797)
+++ trunk/ao/src/plugins/alsa/ao_alsa09.c	2010-01-27 07:40:50 UTC (rev 16832)
@@ -1,518 +0,0 @@
-/*
- *
- *  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.
- *
- *  Largely rewritten 2/18/2002 Kevin Cody Jr <kevinc at wuff.dhs.org>
- *
- */
-
-#define ALSA_PCM_NEW_HW_PARAMS_API
-#define ALSA_PCM_NEW_SW_PARAMS_API
-
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <dirent.h>
-#include <sys/stat.h>
-#include <string.h>
-
-#include <alsa/asoundlib.h>
-#include <ao/ao.h>
-#include <ao/plugin.h>
-
-/* default 500 millisecond buffer */
-#define AO_ALSA_BUFFER_TIME 500000
-
-/* the period time is calculated if not given as an option */
-#define AO_ALSA_PERIOD_TIME 0
-
-/* number of samples between interrupts
- * supplying a period_time to ao overrides the use of this  */
-#define AO_ALSA_SAMPLE_XFER 256
-
-/* set mmap to default if enabled at compile time, otherwise, mmap isn't
-   the default */
-#ifdef USE_ALSA_MMIO
-#define AO_ALSA_WRITEI snd_pcm_mmap_writei
-#define AO_ALSA_ACCESS_MASK SND_PCM_ACCESS_MMAP_INTERLEAVED
-#else
-#define AO_ALSA_WRITEI snd_pcm_writei
-#define AO_ALSA_ACCESS_MASK SND_PCM_ACCESS_RW_INTERLEAVED
-#endif
-
-typedef snd_pcm_sframes_t ao_alsa_writei_t(snd_pcm_t *pcm, const void *buffer,
-						snd_pcm_uframes_t size);
-
-static char *ao_alsa_options[] = {
-	"dev",
-	"buffer_time",
-        "period_time",
-	"use_mmap"
-};
-
-
-static ao_info ao_alsa_info =
-{
-	AO_TYPE_LIVE,
-	"Advanced Linux Sound Architecture (ALSA) output",
-	"alsa",
-	"Bill Currie <bill at taniwha.org>/Kevin Cody, Jr. <kevinc at wuff.dhs.org>",
-	"Outputs to the Advanced Linux Sound Architecture version 0.9.x.",
-	AO_FMT_NATIVE,
-	35,
-	ao_alsa_options,
-	3
-};
-
-
-typedef struct ao_alsa_internal
-{
-	snd_pcm_t *pcm_handle;
-	unsigned int buffer_time;
-	unsigned int period_time;
-	snd_pcm_uframes_t buffer_size;
-	snd_pcm_uframes_t period_size;
-	int sample_size;
-	snd_pcm_format_t bitformat;
-	char *dev;
-	char *cmd;
-	ao_alsa_writei_t * writei;
-	snd_pcm_access_t access_mask;
-} ao_alsa_internal;
-
-
-/* determine if parameters are requires for this particular plugin */
-int ao_plugin_test()
-{
-	snd_pcm_t *handle;
-	int err;
-
-	/* Use nonblock flag when testing to avoid getting stuck if the device
-	   is in use. */
-	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 */
-	}
-}
-
-
-/* return the address of the driver info structure */
-ao_info *ao_plugin_driver_info(void)
-{
-	return &ao_alsa_info;
-}
-
-
-/* initialize internal data structures */
-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;
-	
-	internal->buffer_time = AO_ALSA_BUFFER_TIME;
-	internal->period_time = AO_ALSA_PERIOD_TIME;
-	internal->writei = AO_ALSA_WRITEI;
-	internal->access_mask = AO_ALSA_ACCESS_MASK;
-
-	if (!(internal->dev = strdup("default"))) {
-		free (internal);
-		return 0;
-	}
-	
-	device->internal = internal;
-
-	return 1;
-}
-
-
-/* pass application parameters regarding the sound device */
-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);
-		if (!(internal->dev = strdup(value)))
-			return 0;
-	}
-	else if (!strcmp(key, "buffer_time"))
-		internal->buffer_time = atoi(value) * 1000;
-	else if (!strcmp(key, "period_time"))
-		internal->period_time = atoi(value);
-	else if (!strcmp(key,"use_mmap")) {
-		if(!strcmp(value,"yes") || !strcmp(value,"y") || 
-			!strcmp(value,"true") || !strcmp(value,"t") ||
-			!strcmp(value,"1"))
-		{
-			internal->writei = snd_pcm_mmap_writei;
-			internal->access_mask = SND_PCM_ACCESS_MMAP_INTERLEAVED;
-		}
-		else {
-			internal->writei = snd_pcm_writei;
-			internal->access_mask = SND_PCM_ACCESS_RW_INTERLEAVED;
-		}
-	}
-
-	return 1;
-}
-
-
-/* determine the alsa bitformat for a given bitwidth and endianness */
-static inline int alsa_get_sample_bitformat(int bitwidth, int bigendian)
-{
-	int ret;
-
-	switch (bitwidth) {
-	case 8  : ret = SND_PCM_FORMAT_S8;
-		  break;
-	case 16 : ret = SND_PCM_FORMAT_S16;
-		  break;
-	case 24 : ret = SND_PCM_FORMAT_S24;
-		  break;
-	case 32 : ret = SND_PCM_FORMAT_S32;
-		  break;
-	default : fprintf(stderr,"ALSA: invalid bitwidth %d\n", bitwidth);
-		  return -1;
-	}
-
-	return ret;
-}
-
-
-/* setup alsa data format and buffer geometry */
-static inline int alsa_set_hwparams(ao_alsa_internal *internal,
-		ao_sample_format *format)
-{
-	snd_pcm_hw_params_t   *params;
-	int err;
-	unsigned int rate = format->rate;
-
-	/* allocate the hardware parameter structure */
-	snd_pcm_hw_params_alloca(&params);
-
-	/* fetch all possible hardware parameters */
-	internal->cmd = "snd_pcm_hw_params_any";
-	err = snd_pcm_hw_params_any(internal->pcm_handle, params);
-	if (err < 0)
-		return err;
-
-	/* set the access type */
-	internal->cmd = "snd_pcm_hw_params_set_access";
-	err = snd_pcm_hw_params_set_access(internal->pcm_handle,
-			params, internal->access_mask);
-	if (err < 0)
-		return err;
-
-	/* set the sample bitformat */
-	internal->cmd = "snd_pcm_hw_params_set_format";
-	err = snd_pcm_hw_params_set_format(internal->pcm_handle,
-			params, internal->bitformat);
-	if (err < 0)
-		return err;
-
-	/* set the number of channels */
-	internal->cmd = "snd_pcm_hw_params_set_channels";
-	err = snd_pcm_hw_params_set_channels(internal->pcm_handle,
-			params, (unsigned int)format->channels);
-	if (err < 0)
-		return err;
-
-	/* save the sample size in bytes for posterity */
-	internal->sample_size = format->bits * format->channels / 8;
-
-	/* set the sample rate */
-	internal->cmd = "snd_pcm_hw_params_set_rate_near";
-	err = snd_pcm_hw_params_set_rate_near(internal->pcm_handle,
-			params, &rate, 0);
-	if (err < 0)
-		return err;
-	if (rate > 1.05 * format->rate || rate < 0.95 * format->rate) {
-		fprintf(stderr, "warning: sample rate %i not supported "
-			"by the hardware, using %u\n", format->rate, rate);
-	}
-
-	/* set the length of the hardware sample buffer in microseconds */
-	internal->cmd = "snd_pcm_hw_params_set_buffer_time_near";
-	err = snd_pcm_hw_params_set_buffer_time_near(internal->pcm_handle,
-			params, &(internal->buffer_time), 0);
-	if (err < 0)
-		return err;
-
-	/* calculate a period time of one half sample time */
-	if ((internal->period_time == 0) && (rate > 0))
-		internal->period_time =
-			1000000 * AO_ALSA_SAMPLE_XFER / rate;
-
-	/* set the time per hardware sample transfer */
-	internal->cmd = "snd_pcm_hw_params_set_period_time_near";
-	err = snd_pcm_hw_params_set_period_time_near(internal->pcm_handle,
-			params, &(internal->period_time), 0);
-	if (err < 0)
-		return err;
-
-	/* commit the params structure to the hardware via ALSA */
-	internal->cmd = "snd_pcm_hw_params";
-	err = snd_pcm_hw_params(internal->pcm_handle, params);
-	if (err < 0)
-		return err;
-
-	/* save the period size in frames for posterity */
-	internal->cmd = "snd_pcm_hw_get_period_size";
-	err = snd_pcm_hw_params_get_period_size(params, 
-						&(internal->period_size), 0);
-	if (err < 0)
-		return err;
-
-	/* save the buffer size in frames for posterity */
-	internal->cmd = "snd_pcm_hw_get_buffer_size";
-	err = snd_pcm_hw_params_get_buffer_size(params, 
-						&(internal->buffer_size)); 
-	if (err < 0)
-		return err;
-
-	return 1;
-}
-
-
-/* setup alsa data transfer behavior */
-static inline int alsa_set_swparams(ao_alsa_internal *internal)
-{
-	snd_pcm_sw_params_t   *params;
-	int err;
-
-	/* allocate the software parameter structure */
-	snd_pcm_sw_params_alloca(&params);
-
-	/* fetch the current software parameters */
-	internal->cmd = "snd_pcm_sw_params_current";
-	err = snd_pcm_sw_params_current(internal->pcm_handle, params);
-	if (err < 0)
-		return err;
-
-	/* allow transfers to start when there is one period */
-	internal->cmd = "snd_pcm_sw_params_set_start_threshold";
-	err = snd_pcm_sw_params_set_start_threshold(internal->pcm_handle,
-			params, internal->period_size);
-	if (err < 0)
-		return err;
-
-	/* require a minimum of one full transfer in the buffer */
-	internal->cmd = "snd_pcm_sw_params_set_avail_min";
-	err = snd_pcm_sw_params_set_avail_min(internal->pcm_handle, params,
-			internal->period_size);
-	if (err < 0)
-		return err;
-
-	/* do not align transfers */
-	internal->cmd = "snd_pcm_sw_params_set_xfer_align";
-	err = snd_pcm_sw_params_set_xfer_align(internal->pcm_handle, params, 1);
-	if (err < 0)
-		return err;
-
-	/* commit the params structure to ALSA */
-	internal->cmd = "snd_pcm_sw_params";
-	err = snd_pcm_sw_params(internal->pcm_handle, params);
-	if (err < 0)
-		return err;
-
-	return 1;
-}
-
-
-/* prepare the audio device for playback */
-int ao_plugin_open(ao_device *device, ao_sample_format *format)
-{
-	ao_alsa_internal *internal  = (ao_alsa_internal *) device->internal;
-	int err;
-
-	/* Get the ALSA bitformat first to make sure it's valid */
-	err = alsa_get_sample_bitformat(format->bits,
-			device->client_byte_format == AO_FMT_BIG);
-	if (err < 0)
-		goto error;
-
-	internal->bitformat = err;
-
-	/* Open the ALSA device */
-	internal->cmd = "snd_pcm_open";
-	err = snd_pcm_open(&(internal->pcm_handle), internal->dev,
-			   SND_PCM_STREAM_PLAYBACK, 0);
-	if (err < 0) {
-		internal->pcm_handle = NULL;
-		goto error;
-	}
-
-	/* Set up the hardware parameters, ie sample and buffer specs */
-	err = alsa_set_hwparams(internal, format);
-	if (err < 0)
-		goto error;
-
-	/* Set up the software parameters, ie de-buffering specs */
-	err = alsa_set_swparams(internal);
-	if (err < 0)
-		goto error;
-
-	/* alsa's endinness will be the same as the application's */
-	if (format->bits > 8)
-		device->driver_byte_format = device->client_byte_format;
-
-	return 1;
-
-error:
-	fprintf(stderr, "ALSA %s error: %s\n",
-			internal->cmd, snd_strerror(err));
-	if (internal->pcm_handle) {
-		snd_pcm_close(internal->pcm_handle);
-		internal->pcm_handle = NULL;
-	}
-	return 0;
-}
-
-
-/* recover from an alsa exception */
-static inline int alsa_error_recovery(ao_alsa_internal *internal, int err)
-{
-	if (err == -EPIPE) {
-		/* FIXME: underrun length detection */
-		fprintf(stderr,"ALSA: underrun, at least %dms.\n", 0);
-		/* output buffer underrun */
-		internal->cmd = "underrun recovery: snd_pcm_prepare";
-		err = snd_pcm_prepare(internal->pcm_handle);
-		if (err < 0)
-			return err;
-	} else if (err == -ESTRPIPE) {
-		/* application was suspended, wait until suspend flag clears */
-		internal->cmd = "suspend recovery: snd_pcm_prepare";
-		while ((err = snd_pcm_resume(internal->pcm_handle)) == -EAGAIN)
-			sleep (1);
-
-		if (err < 0) {
-			/* unable to wake up pcm device, restart it */
-			internal->cmd = "suspend recovery: snd_pcm_prepare";
-			err = snd_pcm_prepare(internal->pcm_handle);
-			if (err < 0)
-				return err;
-		}
-		return 0;
-	}
-
-	/* error isn't recoverable */
-	return err;
-}
-
-
-/* play num_bytes of audio data */
-int ao_plugin_play(ao_device *device, const char *output_samples, 
-		uint_32 num_bytes)
-{
-	ao_alsa_internal *internal = (ao_alsa_internal *) device->internal;
-       	uint_32 len = num_bytes / internal->sample_size;
-	char *ptr = (char *) output_samples;
-	int err;
-
-	/* the entire buffer might not transfer at once */
-	while (len > 0) {
-		/* try to write the entire buffer at once */
-		err = internal->writei(internal->pcm_handle, ptr, len);
-
-		/* no data transferred or interrupt signal */
-		if (err == -EAGAIN || err == -EINTR) {
-			continue;
-		}
-
-		if (err < 0) {
-			/* this might be an error, or an exception */
-			err = alsa_error_recovery(internal, err);
-			if (err < 0) {
-				fprintf(stderr,"ALSA write error: %s\n",
-						snd_strerror(err));
-				return 0;
-			}
-
-			/* abandon the rest of the buffer */
-			break;
-		}
-
-		/* decrement the sample counter */
-		len -= err;
-
-		/* adjust the start pointer */
-		ptr += err * internal->sample_size;
-	}
-
-	return 1;
-}
-
-
-/* close the audio device */
-int ao_plugin_close(ao_device *device)
-{
-	ao_alsa_internal *internal;
-
-	if (device) {
-		if ((internal = (ao_alsa_internal *) device->internal)) {
-			if (internal->pcm_handle) {
-				snd_pcm_drain(internal->pcm_handle);
-				snd_pcm_close(internal->pcm_handle);
-				internal->pcm_handle=NULL;
-			} else
-				fprintf(stderr,"ao_plugin_close called with uninitialized ao_device->internal->pcm_handle\n");
-		} else
-			fprintf(stderr,"ao_plugin_close called with uninitialized ao_device->internal\n");
-	} else
-		fprintf(stderr,"ao_plugin_close called with uninitialized ao_device\n");
-
-	return 1;
-}
-
-
-/* free the internal data structures */
-void ao_plugin_device_clear(ao_device *device)
-{
-	ao_alsa_internal *internal;
-
-	if (device) {
-		if ((internal = (ao_alsa_internal *) device->internal)) {
-			if (internal->dev)
-				free (internal->dev);
-			else
-				fprintf(stderr,"ao_plugin_device_clear called with uninitialized ao_device->internal->dev\n");
-			if (internal->cmd)
-				internal->cmd = NULL;
-
-			free(device->internal);
-		} else
-			fprintf(stderr,"ao_plugin_device_clear called with uninitialized ao_device->internal\n");
-	} else
-		fprintf(stderr,"ao_plugin_device_clear called with uninitialized ao_device\n");
-}
-



More information about the commits mailing list