[xiph-cvs] cvs commit: ao/src/plugins/sun ao_sun.c

Stan Seibert volsung at xiph.org
Fri Aug 3 19:56:19 PDT 2001



volsung     01/08/03 19:56:18

  Modified:    .        Makefile.am configure.in
               doc      Makefile.am
               include/ao Makefile.am ao.h os_types.h.in
               src      Makefile.am ao_au.c ao_null.c ao_raw.c ao_wav.c
                        audio_out.c
               src/plugins Makefile.am
               src/plugins/alsa ao_alsa.c
               src/plugins/arts ao_arts.c
               src/plugins/esd ao_esd.c
               src/plugins/irix ao_irix.c
               src/plugins/oss ao_oss.c
               src/plugins/sun ao_sun.c
  Added:       .        libao.conf.5
               doc      ao_append_option.html ao_close.html
                        ao_default_driver_id.html ao_device.html
                        ao_driver_id.html ao_driver_info.html
                        ao_driver_info_list.html ao_example.c
                        ao_free_options.html ao_info.html
                        ao_initialize.html ao_open_file.html
                        ao_open_live.html ao_option.html ao_play.html
                        ao_plugin_close.html ao_plugin_device_clear.html
                        ao_plugin_device_init.html
                        ao_plugin_driver_info.html ao_plugin_open.html
                        ao_plugin_play.html ao_plugin_set_option.html
                        ao_plugin_test.html ao_sample_format.html
                        ao_shutdown.html config.html drivers.html
                        index.html libao-api.html overview.html
                        plugin-api.html plugin-overview.html style.css
               include/ao plugin.h
               src      ao_private.h config.c
               src/plugins/irix .cvsignore Makefile.am
  Removed:     doc      API DRIVERS USAGE WANTED
  Log:
  Merger of new API branch (volsung_20010721) with head.

Revision  Changes    Path
1.6       +3 -1      ao/Makefile.am

Index: Makefile.am
===================================================================
RCS file: /usr/local/cvsroot/ao/Makefile.am,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- Makefile.am	2000/11/18 05:59:40	1.5
+++ Makefile.am	2001/08/04 02:56:07	1.6
@@ -7,7 +7,9 @@
 m4datadir = $(datadir)/aclocal
 m4data_DATA = ao.m4
 
-EXTRA_DIST = README AUTHORS CHANGES COPYING libao.spec ao.m4 acinclude.m4
+man_MANS = libao.conf.5
+
+EXTRA_DIST = README AUTHORS CHANGES COPYING libao.spec ao.m4 acinclude.m4 $(man_MANS)
 
 debug:
         $(MAKE) all CFLAGS="@DEBUG@"

1.22      +5 -4      ao/configure.in

Index: configure.in
===================================================================
RCS file: /usr/local/cvsroot/ao/configure.in,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -r1.21 -r1.22
--- configure.in	2001/06/18 00:07:20	1.21
+++ configure.in	2001/08/04 02:56:07	1.22
@@ -1,13 +1,13 @@
 dnl Process this file with autoconf to produce a configure script.
 AC_INIT(src/audio_out.c)
 
-AM_INIT_AUTOMAKE(libao,0.7.0)
+AM_INIT_AUTOMAKE(libao,0.8.0)
 AM_DISABLE_STATIC
 
 dnl Library versioning
-LIB_CURRENT=1
+LIB_CURRENT=2
 LIB_REVISION=1
-LIB_AGE=1
+LIB_AGE=0
 AC_SUBST(LIB_CURRENT)
 AC_SUBST(LIB_REVISION)
 AC_SUBST(LIB_AGE)
@@ -141,6 +141,7 @@
 
 if test "$BUILD_ALSA" = "yes"; then
    AC_CHECK_LIB(asound, snd_pcm_open, have_alsa=yes, have_alsa=no)
+   AC_CHECK_HEADER(sys/asoundlib.h, , have_alsa=no)
    AM_CONDITIONAL(HAVE_ALSA,test "x$have_alsa" = xyes)
 fi
 
@@ -188,4 +189,4 @@
 
 CFLAGS="$CFLAGS -DAO_PLUGIN_PATH=\\\"$plugindir\\\""
 
-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/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/sun/Makefile src/plugins/irix/Makefile src/plugins/arts/Makefile debian/Makefile)

1.2       +68 -0     ao/libao.conf.5

1.5       +1 -1      ao/doc/Makefile.am

Index: Makefile.am
===================================================================
RCS file: /usr/local/cvsroot/ao/doc/Makefile.am,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- Makefile.am	2000/11/18 05:08:46	1.4
+++ Makefile.am	2001/08/04 02:56:07	1.5
@@ -4,6 +4,6 @@
 
 docdir = $(datadir)/doc/$(PACKAGE)-$(VERSION)
 
-doc_DATA = API USAGE DRIVERS WANTED
+doc_DATA = *.html ao_example.c
 
 EXTRA_DIST = $(doc_DATA)

1.2       +68 -0     ao/doc/ao_append_option.html

1.2       +63 -0     ao/doc/ao_close.html

1.2       +62 -0     ao/doc/ao_default_driver_id.html

1.2       +88 -0     ao/doc/ao_device.html

1.2       +63 -0     ao/doc/ao_driver_id.html

1.2       +66 -0     ao/doc/ao_driver_info.html

1.2       +62 -0     ao/doc/ao_driver_info_list.html

1.2       +83 -0     ao/doc/ao_example.c

1.2       +55 -0     ao/doc/ao_free_options.html

1.2       +93 -0     ao/doc/ao_info.html

1.2       +58 -0     ao/doc/ao_initialize.html

1.2       +99 -0     ao/doc/ao_open_file.html

1.2       +85 -0     ao/doc/ao_open_live.html

1.2       +59 -0     ao/doc/ao_option.html

1.2       +67 -0     ao/doc/ao_play.html

1.2       +61 -0     ao/doc/ao_plugin_close.html

1.2       +53 -0     ao/doc/ao_plugin_device_clear.html

1.2       +67 -0     ao/doc/ao_plugin_device_init.html

1.2       +54 -0     ao/doc/ao_plugin_driver_info.html

1.2       +71 -0     ao/doc/ao_plugin_open.html

1.2       +70 -0     ao/doc/ao_plugin_play.html

1.2       +73 -0     ao/doc/ao_plugin_set_option.html

1.2       +59 -0     ao/doc/ao_plugin_test.html

1.2       +62 -0     ao/doc/ao_sample_format.html

1.2       +55 -0     ao/doc/ao_shutdown.html

1.2       +56 -0     ao/doc/config.html

1.2       +209 -0    ao/doc/drivers.html

1.3       +52 -1     ao/doc/index.html

1.2       +60 -0     ao/doc/libao-api.html

1.2       +109 -0    ao/doc/overview.html

1.2       +42 -0     ao/doc/plugin-api.html

1.2       +45 -0     ao/doc/plugin-overview.html

1.2       +7 -0      ao/doc/style.css

1.2       +2 -1      ao/include/ao/Makefile.am

Index: Makefile.am
===================================================================
RCS file: /usr/local/cvsroot/ao/include/ao/Makefile.am,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- Makefile.am	2000/09/03 09:56:05	1.1
+++ Makefile.am	2001/08/04 02:56:13	1.2
@@ -4,4 +4,5 @@
 
 includedir = $(prefix)/include/ao
 
-include_HEADERS = ao.h os_types.h
+include_HEADERS = ao.h os_types.h plugin.h
+

1.14      +91 -54    ao/include/ao/ao.h

Index: ao.h
===================================================================
RCS file: /usr/local/cvsroot/ao/include/ao/ao.h,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -r1.13 -r1.14
--- ao.h	2001/05/13 03:30:39	1.13
+++ ao.h	2001/08/04 02:56:13	1.14
@@ -3,7 +3,7 @@
  *  ao.h 
  *    
  *	Original Copyright (C) Aaron Holtzman - May 1999
- *      Modifications Copyright (C) Stan Seibert - July 2000
+ *      Modifications Copyright (C) Stan Seibert - July 2000, July 2001
  *      More Modifications Copyright (C) Jack Moffitt - October 2000
  *
  *  This file is part of libao, a cross-platform audio outputlibrary.  See
@@ -31,77 +31,114 @@
 extern "C"
 {
 #endif /* __cplusplus */
-
+	
 #include <stdlib.h>
+#include <errno.h>
 #include "os_types.h"
 
-/* --- Structures --- */
+/* --- Constants ---*/
 
-typedef struct ao_option_s {
-	char *key;
-	char *value;
-	struct ao_option_s *next;
-} ao_option_t;
+#define AO_TYPE_LIVE 1
+#define AO_TYPE_FILE 2
+
+
+#define AO_ENODRIVER   1
+#define AO_ENOTFILE    2
+#define AO_ENOTLIVE    3
+#define AO_EBADOPTION  4
+#define AO_EOPENDEVICE 5
+#define AO_EOPENFILE   6
+#define AO_EFILEEXISTS 7
+
+#define AO_EFAIL       100
 
-typedef struct ao_info_s {
-	/* driver name (Ex: "OSS Audio driver") */
-	const char *name;
-	/* short name (for config strings) (Ex: "oss") */
-	const char *short_name;
-	/* author (Ex: "Aaron Holtzman <aholtzma at ess.engr.uvic.ca>") */
-	const char *author;
-	/* any additional comments (Ex: "Needs work.") */
-	const char *comment;
-} ao_info_t;
-
-typedef void ao_internal_t;
-
-typedef struct ao_functions_s {
-	ao_info_t *(*get_driver_info)(void);
-	ao_internal_t *(*open)(uint_32 bits, uint_32 rate, uint_32 channels, ao_option_t *options);
-	void (*play)(ao_internal_t *state, void* output_samples, uint_32 num_bytes);
-	void (*close)(ao_internal_t *state);
-	int (*get_latency)(ao_internal_t *state);
-} ao_functions_t;
-
-typedef struct ao_device_s {
-	ao_functions_t *funcs;
-	ao_internal_t *state;
-} ao_device_t;
 
+#define AO_FMT_LITTLE 1
+#define AO_FMT_BIG    2
+#define AO_FMT_NATIVE 4
 
+/* --- Structures --- */
+
+typedef struct ao_info {
+	int  type; /* live output or file output? */
+	char *name; /* full name of driver */
+	char *short_name; /* short name of driver */
+        char *author; /* driver author */
+	char *comment; /* driver comment */
+	int  preferred_byte_format;
+	int  priority;
+	char **options;
+	int  option_count;
+} ao_info;
+
+typedef struct ao_functions ao_functions; /* Forward decl to make C happy */
+
+typedef struct ao_device {
+	int  type; /* live output or file output? */
+	int  driver_id;
+	ao_functions *funcs;
+	FILE *file; /* File for output if this is a file driver */
+	int  client_byte_format;
+	int  machine_byte_format;
+	int  driver_byte_format;
+	char *swap_buffer;
+	int  swap_buffer_size; /* Bytes allocated to swap_buffer */
+	void *internal; /* Pointer to driver-specific data */
+} ao_device;
+
+typedef struct ao_sample_format {
+	int bits; /* bits per sample */
+	int rate; /* samples per second (in a single channel) */
+	int channels; /* number of audio channels */
+	int byte_format; /* Byte ordering in sample, see constants below */
+} ao_sample_format;
+
+struct ao_functions {
+	int (*test)(void);
+	ao_info* (*driver_info)(void);
+	int (*device_init)(ao_device *device);
+	int (*set_option)(ao_device *device, const char *key, 
+			  const char *value);
+	int (*open)(ao_device *device, ao_sample_format *format);
+	int (*play)(ao_device *device, const char *output_samples,
+			   uint_32 num_bytes);
+	int (*close)(ao_device *device);
+	void (*device_clear)(ao_device *device);
+};
 
-/* --- Standard driver_id numbers --- */
-
-#define AO_NULL     0
-#define AO_WAV      1
-#define AO_RAW	    2
-#define AO_AU	    3
+typedef struct ao_option {
+	char *key;
+	char *value;
+	struct ao_option *next;
+} ao_option;		
 
 /* --- Functions --- */
 
-/* library init/shutdown */
+/* library setup/teardown */
 void ao_initialize(void);
 void ao_shutdown(void);
 
-/* driver information */
-int ao_get_driver_id(const char *short_name);
-ao_info_t *ao_get_driver_info(int driver_id);
+/* device setup/playback/teardown */
+int ao_append_option(ao_option **options, const char *key, 
+		     const char *value);
+void ao_free_options(ao_option *options);
+ao_device* ao_open_live(int driver_id, ao_sample_format *format,
+				ao_option *option);
+ao_device* ao_open_file(int driver_id, const char *filename, int overwrite,
+			ao_sample_format *format, ao_option *option);
+
+int ao_play(ao_device *device, char *output_samples, uint_32 num_bytes);
+int ao_close(ao_device *device);
 
-/* driver options */
-int ao_append_option(ao_option_t **options, const char *key, const char *value);
-void ao_free_options(ao_option_t *options);
-
-/* the meat: open/play/close */
-ao_device_t *ao_open(int driver_id, uint_32 bits, uint_32 rate, uint_32 channels, ao_option_t *options);
-void ao_play(ao_device_t *device, void* output_samples, uint_32 num_bytes);
-void ao_close(ao_device_t *device);
+/* driver information */
+int ao_driver_id(const char *short_name);
+int ao_default_driver_id();
+ao_info *ao_driver_info(int driver_id);
+ao_info **ao_driver_info_list(int *driver_count);
 
-/* misc functions */
+/* miscellaneous */
 int ao_is_big_endian(void);
 
-/* returns the number of bytes buffered by the driver / output device */
-int ao_get_latency(ao_device_t *device);
 
 #ifdef __cplusplus
 }

1.3       +5 -0      ao/include/ao/os_types.h.in

Index: os_types.h.in
===================================================================
RCS file: /usr/local/cvsroot/ao/include/ao/os_types.h.in,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- os_types.h.in	2000/10/30 00:46:40	1.2
+++ os_types.h.in	2001/08/04 02:56:13	1.3
@@ -26,9 +26,14 @@
 
 /* Set type sizes for this platform (Requires Autoconf) */
 
+#ifndef __OS_TYPES_H__
+#define __OS_TYPES_H__
+
 typedef unsigned char     uint_8;
 typedef unsigned @SIZE16@ uint_16;
 typedef unsigned @SIZE32@ uint_32;
 typedef signed   char     sint_32;
 typedef signed   @SIZE16@ sint_16;
 typedef signed   @SIZE32@ sint_8;
+
+#endif /* __OS_TYPES_H__ */

1.2       +50 -0     ao/include/ao/plugin.h

1.7       +1 -1      ao/src/Makefile.am

Index: Makefile.am
===================================================================
RCS file: /usr/local/cvsroot/ao/src/Makefile.am,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- Makefile.am	2001/05/13 03:30:40	1.6
+++ Makefile.am	2001/08/04 02:56:13	1.7
@@ -7,7 +7,7 @@
 
 lib_LTLIBRARIES = libao.la
 
-libao_la_SOURCES = audio_out.c ao_au.c ao_raw.c ao_wav.c ao_null.c
+libao_la_SOURCES = audio_out.c config.c ao_null.c ao_wav.c ao_au.c ao_raw.c ao_private.h
 libao_la_LDFLAGS = -version-info @LIB_CURRENT@:@LIB_REVISION@:@LIB_AGE@
 
 

1.3       +95 -142   ao/src/ao_au.c

Index: ao_au.c
===================================================================
RCS file: /usr/local/cvsroot/ao/src/ao_au.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- ao_au.c	2001/05/29 11:13:20	1.2
+++ ao_au.c	2001/08/04 02:56:14	1.3
@@ -31,6 +31,7 @@
 #include <errno.h>
 #include <unistd.h>
 #include <ao/ao.h>
+#include <ao/plugin.h>
 
 #define AUDIO_FILE_MAGIC ((uint_32)0x2e736e64)  /* ".snd" */
 
@@ -51,7 +52,7 @@
         *((buf)+2) = (unsigned char)(((x)>>8)&0xff);\
         *((buf)+3) = (unsigned char)((x)&0xff);
 
-typedef struct {
+typedef struct Audio_filehdr {
         uint_32 magic; /* magic number */
         uint_32 hdr_size; /* offset of the data */
         uint_32 data_size; /* length of data (optional) */
@@ -61,171 +62,131 @@
         char info[4]; /* optional text information */
 } Audio_filehdr;
 
-static ao_info_t ao_au_info =
+static ao_info ao_au_info =
 {
+	AO_TYPE_FILE,
         "AU file output",
         "au",
         "Wil Mahan <wtm2 at duke.edu>",
-	"Sends output to a .au file"
+	"Sends output to a .au file",
+	AO_FMT_BIG,
+	0,
+	NULL, /* No options */
+	0
 };
 
-typedef struct ao_au_internal_s
+typedef struct ao_au_internal
 {
-	char *output_file;
-	int fd;
-	int byte_swap;
-	char *swap_buffer;
-	int buffer_size;
         Audio_filehdr au; 		
-} ao_au_internal_t;
+} ao_au_internal;
 
 
-static void ao_au_parse_options(ao_au_internal_t *state, ao_option_t *options)
+static int ao_au_test()
 {
-	state->output_file = NULL;
-
-	while (options) {
-		if (!strcmp(options->key, "file"))
-			state->output_file = strdup(options->value);
+	return 1; /* File driver always works */
+}
 
-		options = options->next;
-	}
 
-	if (state->output_file == NULL)
-		state->output_file = strdup("output.au");
+static ao_info *ao_au_driver_info(void)
+{
+	return &ao_au_info;
 }
 
-static ao_internal_t *ao_au_open(uint_32 bits, uint_32 rate, uint_32 channels, ao_option_t *options)
+
+static int ao_au_device_init(ao_device *device)
 {
-	ao_au_internal_t *state;
-	unsigned char buf[AU_HEADER_LEN];
-	int i;
+	ao_au_internal *internal;
 
-	state = malloc(sizeof(ao_au_internal_t));
-	if (state == NULL) {
-		fprintf(stderr, "ao_au: Could not allocate state memory.\n");
-		goto ERR;
-	}
-	state->output_file = NULL;
+	internal = (ao_au_internal *) malloc(sizeof(ao_au_internal));
 
-	/* Grab options here */
-	ao_au_parse_options(state, options);
+	if (internal == NULL)	
+		return 0; /* Could not initialize device memory */
+	
+	memset(&(internal->au), 0, sizeof(internal->au));
+	
+	device->internal = internal;
 
-	/* The AU format is big-endian */
-	state->byte_swap = (bits == 16) && (!ao_is_big_endian());
-		
-	if (state->byte_swap) {
-		state->buffer_size = DEFAULT_SWAP_BUFFER_SIZE;
-		state->swap_buffer = calloc(sizeof(char), state->buffer_size);
-	       
-		if (state->swap_buffer == NULL) {
-			fprintf(stderr, "ao_au: Could not allocate byte-swapping buffer.\n");
-			goto ERR;
-		}
-	}
+	return 1; /* Memory alloc successful */
+}
 
-	/* Set up output file */
-	if (strncmp(state->output_file, "-", 2) == 0)
-		state->fd = STDOUT_FILENO;
-	else
-		state->fd = open(state->output_file,
-			O_WRONLY | O_TRUNC | O_CREAT, 0644);
 
-	if(state->fd < 0) {
-		fprintf(stderr,"%s: Opening audio output %s\n", strerror(errno), state->output_file);
-		goto ERR;
-	}
+static int ao_au_set_option(ao_device *device, const char *key, 
+			    const char *value)
+{
+	return 1; /* No options! */
+}
 
-	/* Write a zeroed au header first */
-	memset(&(state->au), 0, sizeof(state->au));
 
+static int ao_au_open(ao_device *device, ao_sample_format *format)
+{
+	ao_au_internal *internal = (ao_au_internal *) device->internal;
+	unsigned char buf[AU_HEADER_LEN];
+
+	/* The AU format is big-endian */
+	device->driver_byte_format = AO_FMT_BIG;
+		
         /* Fill out the header */
-	state->au.magic = AUDIO_FILE_MAGIC;
-	state->au.channels = channels;
-	if (bits == 8)
-		state->au.encoding = AUDIO_FILE_ENCODING_LINEAR_8;
-	else if (bits == 16)
-		state->au.encoding = AUDIO_FILE_ENCODING_LINEAR_16;
+	internal->au.magic = AUDIO_FILE_MAGIC;
+	internal->au.channels = format->channels;
+	if (format->bits == 8)
+		internal->au.encoding = AUDIO_FILE_ENCODING_LINEAR_8;
+	else if (format->bits == 16)
+		internal->au.encoding = AUDIO_FILE_ENCODING_LINEAR_16;
         else {
                 /* Only 8 and 16 bits are supported at present. */
-		fprintf(stderr,"ao_au: unsupported number of bits");
+		return 0;
         }	
-	state->au.sample_rate = rate;
-	state->au.hdr_size = AU_HEADER_LEN;
+	internal->au.sample_rate = format->rate;
+	internal->au.hdr_size = AU_HEADER_LEN;
 
         /* From the AU specification:  "When audio files are passed
          * through pipes, the 'data_size' field may not be known in
          * advance.  In such cases, the 'data_size' should be set
          * to AUDIO_UNKNOWN_SIZE."
          */
-	state->au.data_size = AUDIO_UNKNOWN_SIZE;
+	internal->au.data_size = AUDIO_UNKNOWN_SIZE;
         /* strncpy(state->au.info, "OGG ", 4); */
 
         /* Write the header in big-endian order */
-	WRITE_U32(buf, state->au.magic);
-	WRITE_U32(buf + 4, state->au.hdr_size);
-	WRITE_U32(buf + 8, state->au.data_size);
-	WRITE_U32(buf + 12, state->au.encoding);
-	WRITE_U32(buf + 16, state->au.sample_rate);
-	WRITE_U32(buf + 20, state->au.channels);
-	strncpy (buf + 24, state->au.info, 4);
-
-	if (write(state->fd, buf, AU_HEADER_LEN) != AU_HEADER_LEN) {
-		fprintf(stderr,"ao_au: writing header: %s\n", strerror(errno));
-		goto ERR;
+	WRITE_U32(buf, internal->au.magic);
+	WRITE_U32(buf + 4, internal->au.hdr_size);
+	WRITE_U32(buf + 8, internal->au.data_size);
+	WRITE_U32(buf + 12, internal->au.encoding);
+	WRITE_U32(buf + 16, internal->au.sample_rate);
+	WRITE_U32(buf + 20, internal->au.channels);
+	strncpy (buf + 24, internal->au.info, 4);
+
+	if (fwrite(buf, sizeof(char), AU_HEADER_LEN, device->file) 
+	    != AU_HEADER_LEN) {
+		return 0; /* Error writing header */
         }
 
-	return state;
-
-ERR:
-	if(state->fd >= 0) { close(state->fd); }
-	return NULL;
+	return 1;
 }
 
 
 /*
  * play the sample to the already opened file descriptor
  */
-static void ao_au_play(ao_internal_t *state, void *output_samples, uint_32 num_bytes)
+static int ao_au_play(ao_device *device, const char *output_samples, 
+		       uint_32 num_bytes)
 {
-	int i;
-	ao_au_internal_t *s = (ao_au_internal_t *)state;
-
-	/* Swap all of the bytes if things are not big-endian */
-	if (s->byte_swap) {
-		/* Resize buffer larger if needed */
-		if (num_bytes > s->buffer_size) {
-			s->swap_buffer = realloc(s->swap_buffer, sizeof(char)*num_bytes);
-			if (s->swap_buffer == NULL) {
-				fprintf(stderr, "ao_au: Could not resize swap buffer.\n");
-				return;
-			} else {
-				s->buffer_size = num_bytes;
-			}
-		}
-
-		/* Swap the bytes into the swap buffer (so we don't
-		 mess up the output_samples buffer) */
-		for(i = 0; i < num_bytes; i+=2) {
-			s->swap_buffer[i]   = ((char *) output_samples)[i+1];
-			s->swap_buffer[i+1] = ((char *) output_samples)[i];
-		}
-
-		write(s->fd, s->swap_buffer, num_bytes);
-	} else {
-		/* Otherwise just write the output buffer directly */
-		write(s->fd, output_samples, num_bytes);
-	}
+	if (fwrite(output_samples, sizeof(char), num_bytes, 
+		   device->file) < num_bytes)
+		return 0;
+	else
+		return 1;
 }
 
-static void ao_au_close(ao_internal_t *state)
+static int ao_au_close(ao_device *device)
 {
-	ao_au_internal_t *s = (ao_au_internal_t *)state; 
+	ao_au_internal *internal = (ao_au_internal *) device->internal;
+
         off_t size;
         unsigned char buf[4];
 
         /* Try to find the total file length, including header */
-	size = lseek(s->fd, 0, SEEK_CUR);
+	size = ftell(device->file);
 
         /* It's not a problem if the lseek() fails; the AU
          * format does not require a file length.  This is
@@ -233,48 +194,40 @@
          * pipes).
          */
         if (size > 0) {
-		s->au.data_size = size - AU_HEADER_LEN;
+		internal->au.data_size = size - AU_HEADER_LEN;
 
                 /* Rewind the file */
-		if (lseek(s->fd, 8 /* offset of data_size */,
+		if (fseek(device->file, 8 /* offset of data_size */,
                                         SEEK_SET) < 0)
                 {
-			fprintf(stderr,"ao_au: rewind failed\n");
-			goto ERR;
+			return 1; /* Seek failed; that's okay  */
                 }
 
                 /* Fill in the file length */
-		WRITE_U32 (buf, s->au.data_size);
-		if (write(s->fd, buf, 4) < 4) {
-			fprintf(stderr,"ao_au: header write failed\n");
-			goto ERR;
+		WRITE_U32 (buf, internal->au.data_size);
+		if (fwrite(buf, sizeof(char), 4, device->file) < 4) {
+			return 1; /* Header write failed; that's okay */
                 }
         }
 
-ERR:
-	close(s->fd);
-	free(s->output_file);
-	if (s->byte_swap)
-		free(s->swap_buffer);
-	free(s);
+	return 1;
 }
 
-static int ao_au_get_latency(ao_internal_t *state)
-{
-	return 0;
-}
 
-static ao_info_t *ao_au_get_driver_info(void)
+static void ao_au_device_clear(ao_device *device)
 {
-	return &ao_au_info;
+	ao_au_internal *internal = (ao_au_internal *) device->internal;
+
+	free(internal);
 }
 
-ao_functions_t ao_au =
-{
-        ao_au_get_driver_info,
-        ao_au_open,
-        ao_au_play,
-        ao_au_close,
-	ao_au_get_latency
+ao_functions ao_au = {
+	ao_au_test,
+	ao_au_driver_info,
+	ao_au_device_init,
+	ao_au_set_option,
+	ao_au_open,
+	ao_au_play,
+	ao_au_close,
+	ao_au_device_clear
 };
-

1.5       +79 -33    ao/src/ao_null.c

Index: ao_null.c
===================================================================
RCS file: /usr/local/cvsroot/ao/src/ao_null.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- ao_null.c	2001/02/28 07:50:11	1.4
+++ ao_null.c	2001/08/04 02:56:14	1.5
@@ -3,7 +3,7 @@
  *  ao_null.c
  *
  *      Original Copyright (C) Aaron Holtzman - May 1999
- *      Modifications Copyright (C) Stan Seibert - July 2000
+ *      Modifications Copyright (C) Stan Seibert - July 2000, July 2001
  *
  *  This file is part of libao, a cross-platform audio output library.  See
  *  README for a history of this source code.
@@ -27,61 +27,107 @@
 #include <stdio.h>
 #include <ao/ao.h>
 
-typedef struct ao_null_internal_s {
-	unsigned long byte_counter;
-} ao_null_internal_t;
-
-static ao_info_t ao_null_info = {
+static ao_info ao_null_info = {
+	AO_TYPE_LIVE,
         "Null output",
         "null",
-	"Aaron Holtzman <aholtzma at ess.engr.uvic.ca>",
-	"This plugin does nothing"
+	"Stan Seibert <volsung at asu.edu>",
+	"This driver does nothing.",
+	AO_FMT_NATIVE,
+	0,
+	NULL, /* No options */
+	0
 };
+
+
+typedef struct ao_null_internal {
+	unsigned long byte_counter;
+} ao_null_internal;
 
-static ao_internal_t *ao_null_open(uint_32 bits, uint_32 rate, uint_32 channels, ao_option_t *options)
+
+static int ao_null_test()
 {
-	ao_null_internal_t *state;
+	return 1; /* Null always works */
+}
 
-	state = malloc(sizeof(ao_null_internal_t));
 
-	if (state != NULL) {
-		state->byte_counter = 0;
-		return state;
-	} else {
-		return NULL;
-	}
+static ao_info *ao_null_driver_info(void)
+{
+	return &ao_null_info;
+}
+
+
+static int ao_null_device_init(ao_device *device)
+{
+	ao_null_internal *internal;
 
-	return NULL;
+	internal = (ao_null_internal *) malloc(sizeof(ao_null_internal));
+
+	if (internal == NULL)	
+		return 0; /* Could not initialize device memory */
+	
+	internal->byte_counter = 0;
+	
+	device->internal = internal;
+
+	return 1; /* Memory alloc successful */
 }
 
-static void ao_null_close(ao_internal_t *state)
+
+static int ao_null_set_option(ao_device *device, const char *key, 
+			      const char *value)
 {
-        /* why would we print in a lib :)
-	fprintf(stderr, "ao_null: %ld bytes sent to null device.\n",
-		((ao_null_internal_t *) state)->byte_counter);
-	*/
-	if (state) free(state);
+	return 1; /* No options! */
 }
 
-static void ao_null_play(ao_internal_t *state, void* output_samples, uint_32 num_bytes)
+
+
+static int ao_null_open(ao_device *device, ao_sample_format *format)
 {
-	((ao_null_internal_t *)state)->byte_counter += num_bytes;
+	/* Use whatever format the client requested */
+	device->driver_byte_format = device->client_byte_format;
+
+	return 1;
 }
 
-static ao_info_t *ao_null_get_driver_info(void)
+
+static int ao_null_play(ao_device *device, const char *output_samples, 
+			uint_32 num_bytes)
 {
-	return &ao_null_info;
+	ao_null_internal *internal = (ao_null_internal *)device->internal;
+
+	internal->byte_counter += num_bytes;
+
+	return 1;
 }
 
-static int ao_null_get_latency(ao_internal_t *state)
+
+static int ao_null_close(ao_device *device)
 {
-	return 0;
+	ao_null_internal *internal = (ao_null_internal *) device->internal;
+
+	fprintf(stderr, "ao_null: %ld bytes sent to null device.\n",
+		internal->byte_counter);
+
+	return 1;
+}
+
+
+static void ao_null_device_clear(ao_device *device)
+{
+	ao_null_internal *internal = (ao_null_internal *) device->internal;
+
+	free(internal);
 }
+
 
-ao_functions_t ao_null = {
-	ao_null_get_driver_info,
+ao_functions ao_null = {
+	ao_null_test,
+	ao_null_driver_info,
+	ao_null_device_init,
+	ao_null_set_option,
         ao_null_open,
         ao_null_play,
         ao_null_close,
-	ao_null_get_latency
+	ao_null_device_clear
 };

1.2       +82 -148   ao/src/ao_raw.c

Index: ao_raw.c
===================================================================
RCS file: /usr/local/cvsroot/ao/src/ao_raw.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- ao_raw.c	2001/05/06 00:14:18	1.1
+++ ao_raw.c	2001/08/04 02:56:14	1.2
@@ -2,7 +2,7 @@
  *
  *  ao_raw.c
  *
- *      Copyright (C) Stan Seibert - January 2001
+ *      Copyright (C) Stan Seibert - January 2001, July 2001
  *
  *  This file is part of libao, a cross-platform audio output library.  See
  *  README for a history of this source code.
@@ -25,190 +25,124 @@
 
 #include <stdio.h>
 #include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
 #include <errno.h>
-#include <unistd.h>
 #include <ao/ao.h>
+#include <ao/plugin.h>
 
-/* Byte ordering constants */
-#define BYTEORDER_NATIVE        1
-#define BYTEORDER_BIG_ENDIAN    2
-#define BYTEORDER_LITTLE_ENDIAN 3
-
-#define DEFAULT_SWAP_BUFFER_SIZE 2048
-
-
-static ao_info_t ao_raw_info =
+static char *ao_raw_options[] = {"byteorder"};
+static ao_info ao_raw_info =
 {
+	AO_TYPE_FILE,
         "RAW sample output",
         "raw",
         "Stan Seibert <indigo at aztec.asu.edu>",
-	"Writes raw audio samples to a file"
+	"Writes raw audio samples to a file",
+	AO_FMT_NATIVE,
+	0,
+	ao_raw_options,
+	1
 };
 
-typedef struct ao_raw_internal_s
+typedef struct ao_raw_internal
 {
-	char *output_file;
-	int fd;
-	int byteorder;
-	int byte_swap;
-	char *swap_buffer;
-	int buffer_size;
-} ao_raw_internal_t;
-
-
-static void ao_raw_parse_options(ao_raw_internal_t *state, ao_option_t *options)
-{
-	state->output_file = NULL;
-
-	while (options) {
-		if (!strcmp(options->key, "file"))
-			state->output_file = strdup(options->value);
-		else if (!strcmp(options->key, "byteorder")) {
-			
-			if (!strcmp(options->value, "native"))
-				state->byteorder = BYTEORDER_NATIVE;
-			else if (!strcmp(options->value, "big"))
-				state->byteorder = BYTEORDER_BIG_ENDIAN;
-			else if (!strcmp(options->value, "little"))
-				state->byteorder = BYTEORDER_LITTLE_ENDIAN;
-		}
-		options = options->next;
-	}
+	int byte_order;
+} ao_raw_internal;
 
-	if (state->output_file == NULL)
-		state->output_file = strdup("output.raw");
-	if (state->byteorder == 0)
-		state->byteorder = BYTEORDER_NATIVE;
+
+static int ao_raw_test()
+{
+	return 1; /* Always works */
 }
+
 
-static ao_internal_t *ao_raw_open(uint_32 bits, uint_32 rate, uint_32 channels, ao_option_t *options)
+static ao_info *ao_raw_driver_info(void)
 {
-	ao_raw_internal_t *state;
+	return &ao_raw_info;
+}
 
-	state = malloc(sizeof(ao_raw_internal_t));
-	if (state == NULL) {
-		fprintf(stderr, "ao_raw: Could not allocate state memory.\n");
-		goto ERR;
-	}
-	state->byteorder = 0;
-	state->output_file = NULL;
 
-	/* Grab options here */
-	ao_raw_parse_options(state, options);
+static int ao_raw_device_init(ao_device *device)
+{
+	ao_raw_internal *internal;
 
-	/* Figure out byte swapping */
-	if (bits == 16) {
-		switch (state->byteorder) {
-		case BYTEORDER_NATIVE :
-			state->byte_swap = 0;
-			break;
-		case BYTEORDER_BIG_ENDIAN :
-			state->byte_swap = !ao_is_big_endian();
-			break;
-		case BYTEORDER_LITTLE_ENDIAN :
-			state->byte_swap = ao_is_big_endian();
-			break;
-		default :
-			fprintf(stderr, "ao_raw: Internal error - incorrect byte order constant %d\n", state->byteorder);
-			goto ERR;
-		}
-	} else 
-		state->byte_swap = 0;
-		
-	if (state->byte_swap) {
-		state->buffer_size = DEFAULT_SWAP_BUFFER_SIZE;
-		state->swap_buffer = calloc(sizeof(char), state->buffer_size);
-	       
-		if (state->swap_buffer == NULL) {
-			fprintf(stderr, "ao_raw: Could not allocate byte-swapping buffer.\n");
-			goto ERR;
-		}
+	internal = (ao_raw_internal *) malloc(sizeof(ao_raw_internal));
+
+	if (internal == NULL)	
+		return 0; /* Could not initialize device memory */
+	
+	internal->byte_order = AO_FMT_NATIVE;
+	
+	device->internal = internal;
+
+	return 1; /* Memory alloc successful */
+}
+
+static int ao_raw_set_option(ao_device *device, const char *key, 
+			      const char *value)
+{
+	ao_raw_internal *internal = (ao_raw_internal *)device->internal;
+	
+	if (!strcmp(key, "byteorder")) {    
+		if (!strcmp(value, "native"))
+			internal->byte_order = AO_FMT_NATIVE;
+		else if (!strcmp(value, "big"))
+			internal->byte_order = AO_FMT_BIG;
+		else if (!strcmp(value, "little"))
+			internal->byte_order = AO_FMT_LITTLE;
+		else
+			return 0; /* Bad option value */
         }
 
+	return 1;
+}
 
-	/* Setup output file */
-	if (strncmp(state->output_file, "-", 2) == 0)
-	  state->fd = STDOUT_FILENO;
-	else
-	  state->fd = open(state->output_file,
-			   O_WRONLY | O_TRUNC | O_CREAT, 0644);
 
-	if(state->fd < 0) {
-		fprintf(stderr,"%s: Opening audio output %s\n", strerror(errno), state->output_file);
-		goto ERR;
-	}
+static int ao_raw_open(ao_device *device, ao_sample_format *format)
+{
+	ao_raw_internal *internal = (ao_raw_internal *)device->internal;
 
-	return state;
+	device->driver_byte_format = internal->byte_order;
 
-ERR:
-	if(state->fd >= 0) { close(state->fd); }
-	return NULL;
+	return 1;
 }
 
 
 /*
  * play the sample to the already opened file descriptor
  */
-static void ao_raw_play(ao_internal_t *state, void *output_samples, uint_32 num_bytes)
+static int ao_raw_play(ao_device *device, const char *output_samples, 
+		       uint_32 num_bytes)
 {
-	int i;
-	ao_raw_internal_t *s = (ao_raw_internal_t *)state;
-
-	/* Swap all of the bytes if things are not little_endian */
-	if (s->byte_swap) {
-		/* Resize buffer larger if needed */
-		if (num_bytes > s->buffer_size) {
-			s->swap_buffer = realloc(s->swap_buffer, sizeof(char)*num_bytes);
-			if (s->swap_buffer == NULL) {
-				fprintf(stderr, "ao_raw: Could not resize swap buffer.\n");
-				return;
-			} else {
-				s->buffer_size = num_bytes;
-			}
-		}
-
-		/* Swap the bytes into the swap buffer (so we don't
-		 mess up the output_samples buffer) */
-		for(i = 0; i < num_bytes; i+=2) {
-			s->swap_buffer[i]   = ((char *) output_samples)[i+1];
-			s->swap_buffer[i+1] = ((char *) output_samples)[i];
-		}
-
-		write(s->fd, s->swap_buffer, num_bytes );
-	} else {
-		/* Otherwise just write the output buffer directly */
-		write(s->fd, output_samples, num_bytes );
-	}
+	if (fwrite(output_samples, sizeof(char), num_bytes, 
+		   device->file) < num_bytes)
+		return 0;
+	else
+		return 1;
 }
 
-static void ao_raw_close(ao_internal_t *state)
-{
-	ao_raw_internal_t *s = (ao_raw_internal_t *)state;
 
-	close(s->fd);
-	if (s->byte_swap)
-		free(s->swap_buffer);
-	free(s);
-}
-
-static int ao_raw_get_latency(ao_internal_t *state)
+static int ao_raw_close(ao_device *device)
 {
-	return 0;
+	/* No closeout needed */
+	return 1;
 }
+
 
-static ao_info_t *ao_raw_get_driver_info(void)
+static void ao_raw_device_clear(ao_device *device)
 {
-	return &ao_raw_info;
+	ao_raw_internal *internal = (ao_raw_internal *) device->internal;
+
+	free(internal);
 }
 
-ao_functions_t ao_raw =
-{
-        ao_raw_get_driver_info,
-        ao_raw_open,
-        ao_raw_play,
-        ao_raw_close,
-	ao_raw_get_latency
+
+ao_functions ao_raw = {
+	ao_raw_test,
+	ao_raw_driver_info,
+	ao_raw_device_init,
+	ao_raw_set_option,
+	ao_raw_open,
+	ao_raw_play,
+	ao_raw_close,
+	ao_raw_device_clear
 };

1.9       +112 -198  ao/src/ao_wav.c

Index: ao_wav.c
===================================================================
RCS file: /usr/local/cvsroot/ao/src/ao_wav.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- ao_wav.c	2001/03/17 07:44:17	1.8
+++ ao_wav.c	2001/08/04 02:56:14	1.9
@@ -3,7 +3,7 @@
  *  ao_wav.c
  *
  *      Original Copyright (C) Aaron Holtzman - May 1999
- *      Modifications Copyright (C) Stan Seibert - July 2000
+ *      Modifications Copyright (C) Stan Seibert - July 2000, July 2001
  *
  *  This file is part of libao, a cross-platform audio output library.  See
  *  README for a history of this source code.
@@ -28,8 +28,6 @@
 #include <stdio.h>
 #include <errno.h>
 #include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
 #include <signal.h>
 #include <ao/ao.h>
 
@@ -82,260 +80,176 @@
 };
 
 
-static ao_info_t ao_wav_info =
+static ao_info ao_wav_info =
 {
+	AO_TYPE_FILE,
         "WAV file output",
         "wav",
         "Aaron Holtzman <aholtzma at ess.engr.uvic.ca>",
-	"Sends output to a .wav file"
+	"Sends output to a .wav file",
+	AO_FMT_LITTLE,
+	0,
+	NULL, /* No options */
+	0
 };
 
-typedef struct ao_wav_internal_s
+typedef struct ao_wav_internal
 {
-	char *output_file;
-	int fd;
-	int byte_swap;
-	char *swap_buffer;
-	int buffer_size;
         struct wave_header wave;
-} ao_wav_internal_t;
+} ao_wav_internal;
 
 
-/* Ack! This is icky.  We have to keep a global linked list of states
-   so the signal handler can shut them all down when asked. */
-typedef struct ao_wav_state_list_s {
-	ao_wav_internal_t *state;
-	struct ao_wav_state_list_s *next;
-} ao_wav_state_list_t;
-
-static ao_wav_state_list_t *states = NULL;
-static ao_wav_state_list_t *last = NULL;
+static int ao_wav_test()
+{
+	return 1; /* File driver always works */
+}
 
 
-static void (*old_sig)(int);
-static void signal_handler(int sig);
+static ao_info *ao_wav_driver_info(void)
+{
+	return &ao_wav_info;
+}
 
 
-static void ao_wav_parse_options(ao_wav_internal_t *state, ao_option_t *options)
+static int ao_wav_device_init(ao_device *device)
 {
-	state->output_file = NULL;
+	ao_wav_internal *internal;
 
-	while (options) {
-		if (!strcmp(options->key, "file"))
-			state->output_file = strdup(options->value);
-		
-		options = options->next;
-	}
-
-	if (state->output_file == NULL)
-		state->output_file = strdup("output.wav");
-}
+	internal = (ao_wav_internal *) malloc(sizeof(ao_wav_internal));
 
-static ao_internal_t *ao_wav_open(uint_32 bits, uint_32 rate, uint_32 channels, ao_option_t *options)
-{
-	ao_wav_internal_t *state;
-	unsigned char buf[WAV_HEADER_LEN];
+	if (internal == NULL)	
+		return 0; /* Could not initialize device memory */
+	
+	memset(&(internal->wave), 0, sizeof(internal->wave));
+	
+	device->internal = internal;
 
-	memset(buf, 0, WAV_HEADER_LEN);
+	return 1; /* Memory alloc successful */
+}
 
-	state = malloc(sizeof(ao_wav_internal_t));
-	if (state == NULL) {
-		fprintf(stderr, "ao_wav: Could not allocate state memory.\n");
-		goto ERR;
-	}
 
-	/* Grab options here */
-	ao_wav_parse_options(state, options);
-	state->byte_swap = (bits == 16) && (ao_is_big_endian());
-	if (state->byte_swap) {
-		state->buffer_size = DEFAULT_SWAP_BUFFER_SIZE;
-		state->swap_buffer = calloc(sizeof(char), state->buffer_size);
-	       
-		if (state->swap_buffer == NULL) {
-			fprintf(stderr, "ao_wav: Could not allocate byte-swapping buffer.\n");
-			goto ERR;
-		}
-	}
-		
-	state->fd=open(state->output_file,O_WRONLY | O_TRUNC | O_CREAT, 0644);
+static int ao_wav_set_option(ao_device *device, const char *key, 
+			     const char *value)
+{
+	return 1; /* No options! */
+}
 
-	if(state->fd < 0) {
-		fprintf(stderr,"%s: Opening audio output %s\n", strerror(errno), state->output_file);
-		goto ERR;
-	}
 
-	/* Write out a ZEROD wave header first */
-	memset(&(state->wave), 0, sizeof(state->wave));
+static int ao_wav_open(ao_device *device, ao_sample_format *format)
+{
+	ao_wav_internal *internal = (ao_wav_internal *) device->internal;
+	unsigned char buf[WAV_HEADER_LEN];
 
         /* Store information */
-	state->wave.common.wChannels = channels;
-	state->wave.common.wBitsPerSample = bits;
-	state->wave.common.dwSamplesPerSec = rate;
-
-	if (write(state->fd, buf, WAV_HEADER_LEN) != WAV_HEADER_LEN) {
-		fprintf(stderr,"failed to write wav-header: %s\n", strerror(errno));
-		goto ERR;
-	}
+	internal->wave.common.wChannels = format->channels;
+	internal->wave.common.wBitsPerSample = format->bits;
+	internal->wave.common.dwSamplesPerSec = format->rate;
 
-	if (last == NULL) {
-		/* Empty list, install our signal handler only once */
-		old_sig = signal(SIGINT,signal_handler);		
-
-		last = states = malloc(sizeof(ao_wav_state_list_t));
-	} else {
-		last->next = malloc(sizeof(ao_wav_state_list_t));
-		last = last->next;
+	memset(buf, 0, WAV_HEADER_LEN);
+	if (fwrite(buf, sizeof(char), WAV_HEADER_LEN, device->file) 
+	    != WAV_HEADER_LEN) {
+		return 0; /* Could not write wav header */
         }
-
-	last->state = state;
-	last->next = NULL;
 
-	return state;
+	device->driver_byte_format = AO_FMT_LITTLE;
 
-ERR:
-	if(state->fd >= 0) { close(state->fd); }
-	return NULL;
+	return 1;
 }
 
 
 /*
  * play the sample to the already opened file descriptor
  */
-static void ao_wav_play(ao_internal_t *state, void *output_samples, uint_32 num_bytes)
+static int ao_wav_play(ao_device *device, const char *output_samples, 
+			uint_32 num_bytes)
 {
-	int i;
-	ao_wav_internal_t *s = (ao_wav_internal_t *)state;
-
-	/* Swap all of the bytes if things are not little_endian */
-	if (s->byte_swap) {
-		/* Resize buffer larger if needed */
-		if (num_bytes > s->buffer_size) {
-			s->swap_buffer = realloc(s->swap_buffer, sizeof(char)*num_bytes);
-			if (s->swap_buffer == NULL) {
-				fprintf(stderr, "ao_wav: Could not resize swap buffer.\n");
-				return;
-			} else {
-				s->buffer_size = num_bytes;
-			}
-		}
-
-		/* Swap the bytes into the swap buffer (so we don't
-		 mess up the output_samples buffer) */
-		for(i = 0; i < num_bytes; i+=2) {
-			s->swap_buffer[i]   = ((char *) output_samples)[i+1];
-			s->swap_buffer[i+1] = ((char *) output_samples)[i];
-		}
-
-		write(s->fd, s->swap_buffer, num_bytes );
-	} else {
-		/* Otherwise just write the output buffer directly */
-		write(s->fd, output_samples, num_bytes );
-	}
+	if (fwrite(output_samples, sizeof(char), num_bytes, 
+		   device->file) < num_bytes)
+		return 0;
+	else
+		return 1;
+	
 }
 
-static void ao_wav_close(ao_internal_t *state)
+static int ao_wav_close(ao_device *device)
 {
+	ao_wav_internal *internal = (ao_wav_internal *) device->internal;
         unsigned char buf[WAV_HEADER_LEN];
-
-	ao_wav_internal_t *s = (ao_wav_internal_t *)state;
 
-	off_t size;
+	long size;
 
         /* Find how long our file is in total, including header */
-	size = lseek(s->fd, 0, SEEK_CUR);
+	size = ftell(device->file);
 
         if (size < 0) {
-		fprintf(stderr,"lseek failed - wav-header is corrupt\n");
-		goto ERR;
+		return 0;  /* Wav header corrupt */
         }
 
         /* Rewind file */
-	if (lseek(s->fd, 0, SEEK_SET) < 0) {
-		fprintf(stderr,"rewind failed - wav-header is corrupt\n");
-		goto ERR;
+	if (fseek(device->file, 0, SEEK_SET) < 0) {
+		return 0; /* Wav header corrupt */
         }
 
         /* Fill out our wav-header with some information. */
 
-	strncpy(s->wave.riff.id, "RIFF",4);
-	s->wave.riff.len = size - 8;
-	strncpy(s->wave.riff.wave_id, "WAVE",4);
-
-	strncpy(s->wave.format.id, "fmt ",4);
-	s->wave.format.len = 16;
-
-	s->wave.common.wFormatTag = WAVE_FORMAT_PCM;
-	s->wave.common.dwAvgBytesPerSec = 
-		s->wave.common.wChannels * s->wave.common.dwSamplesPerSec *
-		(s->wave.common.wBitsPerSample >> 3);
-
-	s->wave.common.wBlockAlign = s->wave.common.wChannels * 
-		(s->wave.common.wBitsPerSample >> 3);
-
-	strncpy(s->wave.data.id, "data",4);
-
-	s->wave.data.len = size - 44;
-
-	strncpy(buf, s->wave.riff.id, 4);
-	WRITE_U32(buf+4, s->wave.riff.len);
-	strncpy(buf+8, s->wave.riff.wave_id, 4);
-	strncpy(buf+12, s->wave.format.id,4);
-	WRITE_U32(buf+16, s->wave.format.len);
-	WRITE_U16(buf+20, s->wave.common.wFormatTag);
-	WRITE_U16(buf+22, s->wave.common.wChannels);
-	WRITE_U32(buf+24, s->wave.common.dwSamplesPerSec);
-	WRITE_U32(buf+28, s->wave.common.dwAvgBytesPerSec);
-	WRITE_U16(buf+32, s->wave.common.wBlockAlign);
-	WRITE_U16(buf+34, s->wave.common.wBitsPerSample);
-	strncpy(buf+36, s->wave.data.id, 4);
-	WRITE_U32(buf+40, s->wave.data.len);
-
-	if (write(s->fd, buf, WAV_HEADER_LEN) < WAV_HEADER_LEN) {
-		fprintf(stderr,"wav-header write failed -- file is corrupt\n");
-		goto ERR;
-	}
+	strncpy(internal->wave.riff.id, "RIFF",4);
+	internal->wave.riff.len = size - 8;
+	strncpy(internal->wave.riff.wave_id, "WAVE",4);
 
-ERR:
-	close(s->fd);
-	free(s->output_file);
-	if (s->byte_swap)
-		free(s->swap_buffer);
-	free(s);
-}
+	strncpy(internal->wave.format.id, "fmt ",4);
+	internal->wave.format.len = 16;
 
-static int ao_wav_get_latency(ao_internal_t *state)
-{
-	return 0;
-}
+	internal->wave.common.wFormatTag = WAVE_FORMAT_PCM;
+	internal->wave.common.dwAvgBytesPerSec = 
+		internal->wave.common.wChannels * 
+		internal->wave.common.dwSamplesPerSec *
+		(internal->wave.common.wBitsPerSample >> 3);
 
-static ao_info_t *ao_wav_get_driver_info(void)
-{
-	return &ao_wav_info;
-}
+	internal->wave.common.wBlockAlign = 
+		internal->wave.common.wChannels * 
+		(internal->wave.common.wBitsPerSample >> 3);
 
+	strncpy(internal->wave.data.id, "data",4);
 
-static void signal_handler(int sig)
-{
-	ao_wav_state_list_t *temp = states;
-	
-	while (states) {
-		ao_wav_close(states->state);
-		temp = states;
-		states = states->next;
-		free(temp);
-	}
+	internal->wave.data.len = size - 44;
+
+	strncpy(buf, internal->wave.riff.id, 4);
+	WRITE_U32(buf+4, internal->wave.riff.len);
+	strncpy(buf+8, internal->wave.riff.wave_id, 4);
+	strncpy(buf+12, internal->wave.format.id,4);
+	WRITE_U32(buf+16, internal->wave.format.len);
+	WRITE_U16(buf+20, internal->wave.common.wFormatTag);
+	WRITE_U16(buf+22, internal->wave.common.wChannels);
+	WRITE_U32(buf+24, internal->wave.common.dwSamplesPerSec);
+	WRITE_U32(buf+28, internal->wave.common.dwAvgBytesPerSec);
+	WRITE_U16(buf+32, internal->wave.common.wBlockAlign);
+	WRITE_U16(buf+34, internal->wave.common.wBitsPerSample);
+	strncpy(buf+36, internal->wave.data.id, 4);
+	WRITE_U32(buf+40, internal->wave.data.len);
 
-	states = NULL;
+	if (fwrite(buf, sizeof(char), WAV_HEADER_LEN, device->file) 
+	    < WAV_HEADER_LEN)
+	  return 0;
 
-	signal(sig, old_sig);
-	raise(sig);
+	return 1;
 }
 
-ao_functions_t ao_wav =
+static void ao_wav_device_clear(ao_device *device)
 {
-        ao_wav_get_driver_info,
-        ao_wav_open,
-        ao_wav_play,
-        ao_wav_close,
-        ao_wav_get_latency
+	ao_wav_internal *internal = (ao_wav_internal *) device->internal;
+
+	free(internal);
+}
+
+
+ao_functions ao_wav = {
+	ao_wav_test,
+	ao_wav_driver_info,
+	ao_wav_device_init,
+	ao_wav_set_option,
+	ao_wav_open,
+	ao_wav_play,
+	ao_wav_close,
+	ao_wav_device_clear
 };
+

1.16      +528 -156  ao/src/audio_out.c

Index: audio_out.c
===================================================================
RCS file: /usr/local/cvsroot/ao/src/audio_out.c,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -r1.15 -r1.16
--- audio_out.c	2001/05/13 03:30:40	1.15
+++ audio_out.c	2001/08/04 02:56:14	1.16
@@ -32,12 +32,10 @@
 #include <sys/stat.h>
 #include <unistd.h>
 #include <dirent.h>
-#include <ao/ao.h>
+#include "ao/ao.h"
+#include "ao_private.h"
 
 /* These should have been set by the Makefile */
-#ifndef AO_DEFAULT
-#define AO_DEFAULT AO_NULL
-#endif
 #ifndef AO_PLUGIN_PATH
 #define AO_PLUGIN_PATH "/usr/local/lib/ao"
 #endif
@@ -45,49 +43,103 @@
 #define SHARED_LIB_EXT ".so"
 #endif
 
+/* --- Other constants --- */
+#define DEF_SWAP_BUF_SIZE  1024
+
 /* --- Driver Table --- */
 
-typedef struct driver_tree_s {
-	ao_functions_t *functions;
+typedef struct driver_list {
+	ao_functions *functions;
         void *handle;
-	struct driver_tree_s *next;
-} driver_tree_t;
+	struct driver_list *next;
+} driver_list;
+
+
+extern ao_functions ao_null;
+extern ao_functions ao_wav;
+extern ao_functions ao_raw;
+extern ao_functions ao_au;
+
+ao_functions *static_drivers[] = {
+	&ao_null, /* Must have at least one static driver! */
+	&ao_wav,
+	&ao_raw,
+	&ao_au,
+	NULL /* End of list */
+};
+
+driver_list *driver_head = NULL;
+ao_config config = {
+	NULL, /* default_driver */
+	-1,   /* default_driver_id */
+};
+
+ao_info **info_table = NULL;
+int driver_count = 0;
 
-extern ao_functions_t ao_null;
-extern ao_functions_t ao_wav;
-extern ao_functions_t ao_raw;
-extern ao_functions_t ao_au;
+/* ---------- Helper functions ---------- */
 
-driver_tree_t *driver_head = NULL;
+/* Clear out all of the library configuration options and set them to
+   defaults.   The defaults should match the initializer above. */
+void _clear_config()
+{
+	free(config.default_driver);
+	config.default_driver = NULL;
+	config.default_driver_id = -1;
+}
+
+
+/* Load a plugin from disk and put the function table into a driver_list
+   struct. */
 
-driver_tree_t *_get_plugin(char *plugin_file)
+driver_list *_get_plugin(char *plugin_file)
 {
-	driver_tree_t *dt;
+	driver_list *dt;
         void *handle;
-	
-	handle = dlopen(plugin_file, RTLD_NOW);
+
+	handle = dlopen(plugin_file, DLOPEN_FLAG /* See ao_private.h */);
+
         if (handle) {
-		dt = (driver_tree_t *)malloc(sizeof(driver_tree_t));
+		dt = (driver_list *)malloc(sizeof(driver_list));
                 if (!dt) return NULL;
 
                 dt->handle = handle;
                 
-		dt->functions = (ao_functions_t *)malloc(sizeof(ao_functions_t));
+		dt->functions = (ao_functions *)malloc(sizeof(ao_functions));
                 if (!(dt->functions)) {
                         free(dt);
                         return NULL;
                 }
 
-		dt->functions->get_driver_info = dlsym(dt->handle, "plugin_get_driver_info");
+		dt->functions->test = dlsym(dt->handle, "ao_plugin_test");
                 if (dlerror()) { free(dt->functions); free(dt); return NULL; }
-		dt->functions->open = dlsym(dt->handle, "plugin_open");
+
+		dt->functions->driver_info = 
+		  dlsym(dt->handle, "ao_plugin_driver_info");
+		if (dlerror()) { free(dt->functions); free(dt); return NULL; }
+
+		dt->functions->device_init = 
+		  dlsym(dt->handle, "ao_plugin_device_init");
+		if (dlerror()) { free(dt->functions); free(dt); return NULL; }
+
+		dt->functions->set_option = 
+		  dlsym(dt->handle, "ao_plugin_set_option");
+		if (dlerror()) { free(dt->functions); free(dt); return NULL; }
+
+		dt->functions->open = dlsym(dt->handle, "ao_plugin_open");
                 if (dlerror()) { free(dt->functions); free(dt); return NULL; }
-		dt->functions->play = dlsym(dt->handle, "plugin_play");
+
+		dt->functions->play = dlsym(dt->handle, "ao_plugin_play");
                 if (dlerror()) { free(dt->functions); free(dt); return NULL; }
-		dt->functions->close = dlsym(dt->handle, "plugin_close");
+
+		dt->functions->close = dlsym(dt->handle, "ao_plugin_close");
                 if (dlerror()) { free(dt->functions); free(dt); return NULL; }
-		dt->functions->get_latency = dlsym(dt->handle, "plugin_get_latency");
+
+		dt->functions->device_clear = 
+		  dlsym(dt->handle, "ao_plugin_device_clear");
                 if (dlerror()) { free(dt->functions); free(dt); return NULL; }
+
+
         } else {
                 return NULL;
         }
@@ -95,117 +147,151 @@
         return dt;
 }
 
-void ao_initialize(void)
+
+/* If *name is a valid driver name, return its driver number.
+   Otherwise, test all of available live drivers until one works. */
+int _find_default_driver_id (const char *name)
+{
+	int def_id;
+	int id;
+	int priority;
+	ao_info *info;
+	driver_list *driver = driver_head;
+
+	if ( name == NULL || (def_id = ao_driver_id(name)) < 0 ) {
+		/* No default specified. Find one among available drivers. */
+		def_id = -1;
+		
+		id = 0;
+		priority = 0; /* This forces the null driver to be skipped */ 
+		while (driver != NULL) {
+
+			info = driver->functions->driver_info();
+
+			if ( info->type == AO_TYPE_LIVE && 
+			     info->priority > priority &&
+			     driver->functions->test() ) {
+				priority = info->priority;
+				def_id = id; /* Found a usable driver */
+			}
+
+			driver = driver->next;
+			id++;
+		}
+	}
+
+	return def_id;
+}
+
+
+/* Convert the static drivers table into a linked list of drivers. */ 
+driver_list* _load_static_drivers(driver_list **end)
 {
-	driver_tree_t *dnull;
-	driver_tree_t *dwav;
-	driver_tree_t *draw;
-	driver_tree_t *dau;
-	driver_tree_t *plugin;
-	driver_tree_t *driver;
-	DIR *plugindir;
+	driver_list *head;
+	driver_list *driver;
+	int i;
+       
+	/* insert first driver */
+	head = driver = malloc(sizeof(driver_list));
+	if (driver != NULL) {
+		driver->functions = static_drivers[0];
+		driver->handle = NULL;
+		driver->next = NULL;
+
+		i = 1;
+		while (static_drivers[i] != NULL) {
+			driver->next = malloc(sizeof(driver_list));
+			if (driver->next == NULL)
+				break;
+
+			driver->next->functions = static_drivers[i];
+			driver->next->handle = NULL;
+			driver->next->next = NULL;
+			
+			driver = driver->next;
+			i++;
+		}
+	}
+
+	if (end != NULL)
+		*end = driver;
+
+	return head;
+}
+
+
+/* Load the dynamic drivers from disk and append them to end of the
+   driver list.  end points the driver_list node to append to. */
+void _append_dynamic_drivers(driver_list *end)
+{
         struct dirent *plugin_dirent;
         char *ext;
         struct stat statbuf;
-	void *plughand;
         char fullpath[FILENAME_MAX];
+	DIR *plugindir;
+	driver_list *plugin;
+	driver_list *driver = end;
 
-	if (driver_head == NULL) {
-		/* insert the null, wav, raw, and au drivers into the tree */
-		dnull = (driver_tree_t *)malloc(sizeof(driver_tree_t));
-		dnull->functions = &ao_null;
-		dnull->handle = NULL;
-		dwav = (driver_tree_t *)malloc(sizeof(driver_tree_t));
-		dwav->functions = &ao_wav;
-		dwav->handle = NULL;
-		draw = (driver_tree_t *)malloc(sizeof(driver_tree_t));
-		draw->functions = &ao_raw;
-		draw->handle = NULL;
-		dau = (driver_tree_t *)malloc(sizeof(driver_tree_t));
-		dau->functions = &ao_au;
-		dau->handle = NULL;
-		
-		dnull->next = dwav;
-		dwav->next = draw;
-		draw->next = dau;
-		dau->next = NULL;
-
-		driver_head = dnull;		
-		driver = dau;
-
-		/* now insert any plugins we find */
-		plugindir = opendir(AO_PLUGIN_PATH);
-		if (plugindir != NULL) {
-			while ((plugin_dirent = readdir(plugindir)) != NULL) {
-				snprintf(fullpath, FILENAME_MAX, "%s/%s", AO_PLUGIN_PATH, plugin_dirent->d_name);
-				if (!stat(fullpath, &statbuf) && S_ISREG(statbuf.st_mode) && (ext = strrchr(plugin_dirent->d_name, '.')) != NULL) {
-					if (strcmp(ext, SHARED_LIB_EXT) == 0) {
-						plugin = _get_plugin(fullpath);
-						if (plugin) {
-							driver->next = plugin;
-							plugin->next = NULL;
-							driver = driver->next;
-						}
+	/* now insert any plugins we find */
+	plugindir = opendir(AO_PLUGIN_PATH);
+	if (plugindir != NULL) {
+		while ((plugin_dirent = readdir(plugindir)) != NULL) {
+			snprintf(fullpath, FILENAME_MAX, "%s/%s", 
+				 AO_PLUGIN_PATH, plugin_dirent->d_name);
+			if (!stat(fullpath, &statbuf) && 
+			    S_ISREG(statbuf.st_mode) && 
+			 (ext = strrchr(plugin_dirent->d_name, '.')) != NULL) {
+				if (strcmp(ext, SHARED_LIB_EXT) == 0) {
+					plugin = _get_plugin(fullpath);
+					if (plugin) {
+						driver->next = plugin;
+						plugin->next = NULL;
+						driver = driver->next;
                                         }
                                 }
                         }
-			
-			closedir(plugindir);
                 }
+		
+		closedir(plugindir);
         }
 }
 
-void ao_shutdown(void)
-{
-	driver_tree_t *driver = driver_head;
-	driver_tree_t *next_driver;
 
-	if (!driver_head) return;
+/* Make a table of driver info structures for ao_driver_info_list(). */
+ao_info ** _make_info_table (driver_list *head, int *driver_count)
+{
+	driver_list *list;
+	int i;
+	ao_info **table;
 
-	/* unload and free all the plugins */
-	driver = driver->next->next->next->next;  /* Skip null, wav, raw, and au driver */
-	while (driver) {
-		if (driver->functions) free(driver->functions);
-		if (driver->handle) dlclose(driver->handle);
-		next_driver = driver->next;
-		free(driver);
-		driver = next_driver;
+	/* Count drivers */
+	list = head;
+	i = 0;
+	while (list != NULL) {
+		i++;
+		list = list->next;
         }
 
-	/* free the standard drivers */
-	if (driver_head) {
-		if(driver_head->next)
-			free(driver_head->next);
-		free(driver_head);
-	}
         
-	/* NULL out driver_head or ao_initialize won't work */
-	driver_head = NULL;
+	/* Alloc table */
+	table = (ao_info **) calloc(i, sizeof(ao_info *));
+	if (table != NULL) {
+		*driver_count = i;
+		list = head;
+		for (i = 0; i < *driver_count; i++, list = list->next)
+			table[i] = list->functions->driver_info();
+	} else
+		*driver_count = 0;
+
+	return table;
 }
 
-int ao_get_driver_id(const char *short_name)
-{
-	int i;
-	driver_tree_t *driver = driver_head;
-
-	if (short_name == NULL) {
-		return AO_NULL;
-	} else {
-		i = 0;
-		while (driver) {
-			if (strcmp(short_name, driver->functions->get_driver_info()->short_name) == 0)
-				return i;
-			driver = driver->next;
-			i++;
-		}
-		
-		return -1; /* No driver by that name */
-	}
-}
 
-driver_tree_t *_get_driver(int driver_id) {
+/* Return the driver struct corresponding to particular driver id
+   number. */
+driver_list *_get_driver(int driver_id) {
         int i = 0;
-	driver_tree_t *driver = driver_head;
+	driver_list *driver = driver_head;
 
         if (driver_id < 0) return NULL;
 
@@ -220,10 +306,12 @@
         return NULL;
 }
 
+
+/* Check if driver_id is a valid id number */
 int _check_driver_id(int driver_id)
 {
         int i = 0;
-	driver_tree_t *driver = driver_head;
+	driver_list *driver = driver_head;
 
         if (driver_id < 0) return 0;
 
@@ -237,63 +325,227 @@
 
         return 0;
 }	
+
+
+/* helper function to convert a byte_format of AO_FMT_NATIVE to the
+   actual byte format of the machine, otherwise just return
+   byte_format */
+int _real_byte_format(int byte_format)
+{
+	if (byte_format == AO_FMT_NATIVE) {
+		if (ao_is_big_endian())
+			return AO_FMT_BIG;
+		else
+			return AO_FMT_LITTLE;
+	} else
+		return byte_format;
+}
+
 
-ao_info_t *ao_get_driver_info(int driver_id)
+/* Create a new ao_device structure and populate it with data */
+ao_device* _create_device(int driver_id, driver_list *driver,
+			  ao_sample_format *format, FILE *file)
 {
-	driver_tree_t *driver;
+	ao_device *device;
+	
+	device = malloc(sizeof(ao_device));
+	
+	if (device != NULL) {		
+		device->type = driver->functions->driver_info()->type;
+		device->driver_id = driver_id;
+		device->funcs = driver->functions;
+		device->file = file;
+		device->machine_byte_format = 
+		  ao_is_big_endian() ? AO_FMT_BIG : AO_FMT_LITTLE;
+		device->client_byte_format =
+		  _real_byte_format(format->byte_format);
+		device->swap_buffer = NULL;
+		device->swap_buffer_size = 0;
+		device->internal = NULL;
+	}
 
-	if (driver = _get_driver(driver_id))
-		return driver->functions->get_driver_info();
-	else
-		return NULL;
+	return device;
 }
 
 
+/* Expand the swap buffer in this device if it is smaller than
+   min_size. */
+int _realloc_swap_buffer(ao_device *device, int min_size)
+{
+	void *temp;
+
+	if (min_size > device->swap_buffer_size) {
+		temp = realloc(device->swap_buffer, min_size);
+		if (temp != NULL) {
+			device->swap_buffer = temp;
+			device->swap_buffer_size = min_size;
+			return 1; /* Success, realloc worked */
+		} else
+			return 0; /* Fail to realloc */
+	} else
+		return 1; /* Success, no need to realloc */
+}
 
-/* -- Audio Functions --- */
 
-ao_device_t* ao_open(int driver_id, uint_32 bits, uint_32 rate, uint_32 channels, ao_option_t *options)
+/* Swap and copy the byte order of samples from the source buffer to
+   the target buffer. */
+void _swap_samples(char *target_buffer, char* source_buffer, uint_32 num_bytes)
 {
-	ao_functions_t *funcs;
-	ao_internal_t *state;
-	ao_device_t *device;
-	driver_tree_t *driver = driver_head;
-
-	if (driver = _get_driver(driver_id)) {
-		funcs = driver->functions;
-		state = funcs->open(bits, rate, channels, options);
-		if (state != NULL) {
-			device = malloc(sizeof(ao_device_t));
-			device->funcs = funcs;
-			device->state = state;
-			return device;
+	int i;
+
+	for (i = 0; i < num_bytes; i += 2) {
+		target_buffer[i] = source_buffer[i+1];
+		target_buffer[i+1] = source_buffer[i];
+	}
+}
+		
+
+/* Open a device.  If this is a live device, file == NULL. */
+ao_device* _open_device(int driver_id, ao_sample_format *format, 
+			ao_option *options, FILE *file)
+{
+	ao_functions *funcs;
+	driver_list *driver;
+	ao_device *device;
+	int result;
+	
+	/* Get driver id */
+	if ( (driver = _get_driver(driver_id)) == NULL ) {
+		errno = AO_ENODRIVER;
+		return NULL; /* No driver exists */
+	}
+
+	funcs = driver->functions;
+
+	/* Check the driver type */
+	if (file == NULL && 
+	    funcs->driver_info()->type != AO_TYPE_LIVE) {
+
+		errno = AO_ENOTLIVE;
+		return NULL;
+	} else if (file != NULL && 
+		   funcs->driver_info()->type != AO_TYPE_FILE) {
+
+		errno = AO_ENOTFILE;
+		return NULL;
+	}
+	
+	/* Make a new device structure */
+	if ( (device = _create_device(driver_id, driver, 
+				      format, file)) == NULL ) {
+		errno = AO_EFAIL;
+		return NULL; /* Couldn't alloc device */
+	}
+		
+	/* Initialize the device memory */
+	if (!funcs->device_init(device)) {
+		free(device);
+		errno = AO_EFAIL;
+		return NULL; /* Couldn't init internal memory */
+	}
+	
+	/* Load options */
+	while (options != NULL) {
+		if (!funcs->set_option(device, options->key, options->value)) {
+			/* Problem setting options */
+			free(device);
+			errno = AO_EOPENDEVICE;
+			return NULL;
                 }
+			
+		options = options->next;
         }
+
+	/* Open the device */
+	result = funcs->open(device, format);
+	if (!result) {
+		funcs->device_clear(device);
+		free(device);
+		errno = AO_EOPENDEVICE;
+		return NULL; /* Couldn't open device */
+	}
+		
+	/* Resolve actual driver byte format */
+	device->driver_byte_format = 
+		_real_byte_format(device->driver_byte_format);
         
-	return NULL;
-}	
+	/* Only create swap buffer for 16 bit samples if needed */
+	if (format->bits == 16 &&
+	    device->client_byte_format != device->driver_byte_format) {
+		
+		result = _realloc_swap_buffer(device, DEF_SWAP_BUF_SIZE);
+		
+		if (!result) {
+			
+			device->funcs->close(device);
+			device->funcs->device_clear(device);
+			free(device);
+			errno = AO_EFAIL;
+			return NULL; /* Couldn't alloc swap buffer */
+		}
+	}
+	
+	/* If we made it this far, everything is OK. */
+	return device; 
+}
+
+
+/* ---------- Public Functions ---------- */
 
-void ao_play(ao_device_t *device, void* output_samples, uint_32 num_bytes)
+/* -- Library Setup/Teardown -- */
+
+void ao_initialize(void)
 {
-	device->funcs->play(device->state, output_samples, num_bytes);
+	driver_list *end;
+
+	/* Read config files */
+	read_config_files(&config);
+
+	if (driver_head == NULL) {
+		driver_head = _load_static_drivers(&end);
+		_append_dynamic_drivers(end);
+	}
+
+	/* Find the default driver in the list of loaded drivers */
+	config.default_driver_id = 
+	  _find_default_driver_id(config.default_driver);
+
+	/* Create the table of driver info structs */
+	info_table = _make_info_table(driver_head, &driver_count);
 }
 
 
-void ao_close(ao_device_t *device)
+void ao_shutdown(void)
 {
-	device->funcs->close(device->state);
-	free(device);
-}
+	driver_list *driver = driver_head;
+	driver_list *next_driver;
+
+	if (!driver_head) return;
+
+	/* unload and free all the drivers */
+	while (driver) {
+		if (driver->handle) {
+		  dlclose(driver->handle);
+		  free(driver->functions); /* DON'T FREE STATIC FUNC TABLES */
+		}
+		next_driver = driver->next;
+		free(driver);
+		driver = next_driver;
+	}
 
+        _clear_config();
+	/* NULL out driver_head or ao_initialize() won't work */
+	driver_head = NULL;
+}
 
 
-/* --- Option Functions --- */
+/* -- Device Setup/Playback/Teardown -- */
 
-int ao_append_option(ao_option_t **options, const char *key, const char *value)
+int ao_append_option(ao_option **options, const char *key, const char *value)
 {
-	ao_option_t *op, *list;
+	ao_option *op, *list;
 
-	op = malloc(sizeof(ao_option_t));
+	op = malloc(sizeof(ao_option));
         if (op == NULL) return 0;
 
         op->key = strdup(key);
@@ -313,9 +565,9 @@
 }
 
 
-void ao_free_options(ao_option_t *options)
+void ao_free_options(ao_option *options)
 {
-	ao_option_t *rest;
+	ao_option *rest;
 
         while (options != NULL) {
                 rest = options->next;
@@ -325,8 +577,134 @@
                 options = rest;
         }
 }
+
+
+ao_device *ao_open_live (int driver_id, ao_sample_format *format, 
+			ao_option *options)
+{
+	return _open_device(driver_id, format, options, NULL);		
+}
+
+
+ao_device *ao_open_file (int driver_id, const char *filename, int overwrite, 
+			 ao_sample_format *format, ao_option *options)
+{
+	FILE *file;
+	ao_device *device;
+
+	if (strcmp("-", filename) == 0)
+		file = stdout;
+	else {
+
+		if (!overwrite) {
+			/* Test for file existence */
+			file = fopen(filename, "r");
+			if (file != NULL) {
+				fclose(file);
+				errno = AO_EFILEEXISTS;
+				return NULL;
+			}
+		}
+
+
+		file = fopen(filename, "w");
+	}
+
+
+	if (file == NULL) {
+		errno = AO_EOPENFILE;
+		return NULL;
+	}
+		
+	device = _open_device(driver_id, format, options, file);
+	
+	if (device == NULL) {
+		fclose(file);
+		/* errno already set by _open_device() */
+		return NULL;
+	}
+
+	return device;
+}
+
+
+int ao_play(ao_device *device, char* output_samples, uint_32 num_bytes)
+{
+	char *playback_buffer;
+
+	if (device->swap_buffer != NULL) {
+		if (_realloc_swap_buffer(device, num_bytes)) {
+			_swap_samples(device->swap_buffer, 
+				      output_samples, num_bytes);
+			playback_buffer = device->swap_buffer;
+		} else
+			return 0; /* Could not expand swap buffer */
+	} else
+		playback_buffer = output_samples;
+
+	return device->funcs->play(device, playback_buffer, num_bytes);
+}
+
+
+int ao_close(ao_device *device)
+{
+	int result;
+
+	result = device->funcs->close(device);
+	device->funcs->device_clear(device);
+	free(device);
+
+	return result;
+}
+
 
-/* Helper function lifted from Vorbis' lib/vorbisfile.c */
+/* -- Driver Information -- */
+
+int ao_driver_id(const char *short_name)
+{
+	int i;
+	driver_list *driver = driver_head;
+
+	i = 0;
+	while (driver) {
+		if (strcmp(short_name, 
+			   driver->functions->driver_info()->short_name) == 0)
+			return i;
+		driver = driver->next;
+		i++;
+	}
+	
+	return -1; /* No driver by that name */
+}
+
+
+int ao_default_driver_id ()
+{
+	return config.default_driver_id;
+}
+
+
+ao_info *ao_driver_info(int driver_id)
+{
+	driver_list *driver;
+
+	if ( (driver = _get_driver(driver_id)) )
+		return driver->functions->driver_info();
+	else
+		return NULL;
+}
+
+
+ao_info **ao_driver_info_list(int *count)
+{
+	*count = driver_count;
+	return info_table;
+}
+
+
+/* -- Miscellaneous -- */
+
+/* Stolen from Vorbis' lib/vorbisfile.c */
 int ao_is_big_endian(void) 
 {
         uint_16 pattern = 0xbabe;
@@ -335,9 +713,3 @@
         if (bytewise[0] == 0xba) return 1;
         return 0;
 }
-
-int ao_get_latency(ao_device_t *device)
-{
-	return device->funcs->get_latency(device->state);
-}
-

1.2       +69 -0     ao/src/ao_private.h

1.2       +76 -0     ao/src/config.c

1.4       +1 -1      ao/src/plugins/Makefile.am

Index: Makefile.am
===================================================================
RCS file: /usr/local/cvsroot/ao/src/plugins/Makefile.am,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- Makefile.am	2001/05/17 15:28:44	1.3
+++ Makefile.am	2001/08/04 02:56:15	1.4
@@ -1,4 +1,4 @@
 ## Process this file with automake to produce Makefile.in
 
 AUTOMAKE_OPTIONS = foreign
-SUBDIRS = oss sun esd alsa arts # irix
+SUBDIRS = oss esd arts alsa sun irix # macosx

1.6       +133 -87   ao/src/plugins/alsa/ao_alsa.c

Index: ao_alsa.c
===================================================================
RCS file: /usr/local/cvsroot/ao/src/plugins/alsa/ao_alsa.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- ao_alsa.c	2001/02/26 04:40:24	1.5
+++ ao_alsa.c	2001/08/04 02:56:16	1.6
@@ -2,7 +2,7 @@
  *
  *  ao_alsa.c
  *
- *      Copyright (C) Stan Seibert - July 2000
+ *      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.
@@ -32,10 +32,27 @@
 
 #include <sys/asoundlib.h>
 #include <ao/ao.h>
+#include <ao/plugin.h>
 
 #define AO_ALSA_BUF_SIZE 32768
 
-typedef struct ao_alsa_internal_s
+
+static char *ao_alsa_options[] = {"card","dev","buf_size"};
+static ao_info ao_alsa_info =
+{
+	AO_TYPE_LIVE,
+	"Advanced Linux Sound Architecture (ALSA) output",
+	"alsa",
+	"Stan Seibert <volsung at asu.edu>",
+	"Outputs to the Advanced Linux Sound Architecture version 0.5.x.",
+	AO_FMT_NATIVE,
+	30,
+	ao_alsa_options,
+	3
+};
+
+
+typedef struct ao_alsa_internal
 {
         snd_pcm_t *pcm_handle;
         char *buf;
@@ -43,46 +60,65 @@
         int buf_end;
         int card;
         int dev;
-} ao_alsa_internal_t;
+} ao_alsa_internal;
+
 
-ao_info_t ao_alsa_info =
+int ao_plugin_test()
 {
-	"Advanced Linux Sound Architecture (ALSA) output",
-	"alsa",
-	"Stan Seibert <volsung at asu.edu>",
-	"Outputs to the Advanced Linux Sound Architecture."
-};
+	snd_pcm_t *handle;
+
+	if (snd_pcm_open(&handle, 0, 0, 
+			 SND_PCM_OPEN_PLAYBACK | SND_PCM_OPEN_NONBLOCK) != 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;
+}
 
-static int _is_big_endian(void)
+
+int ao_plugin_device_init(ao_device *device)
 {
-        uint_16 pattern = 0xbabe;
-        unsigned char *bytewise = (unsigned char *)&pattern;
+	ao_alsa_internal *internal;
+
+	internal = (ao_alsa_internal *) malloc(sizeof(ao_alsa_internal));
 
-        if (bytewise[0] == 0xba) return 1;
-        return 0;
+	if (internal == NULL)	
+		return 0; /* Could not initialize device memory */
+	
+	internal->buf_size = AO_ALSA_BUF_SIZE;
+	internal->card = 0;
+	internal->dev = 0;
+	
+	device->internal = internal;
+
+	return 1; /* Memory alloc successful */
 }
+
 
-void ao_alsa_parse_options(ao_alsa_internal_t *state, ao_option_t *options)
+int ao_plugin_set_option(ao_device *device, const char *key, const char *value)
 {
-	state->card = 0;
-	state->dev = 0;
-	state->buf_size = AO_ALSA_BUF_SIZE;
+	ao_alsa_internal *internal = (ao_alsa_internal *) device->internal;
+	if (!strcmp(key, "card"))
+		internal->card = atoi(value);
+	else if (!strcmp(key, "dev"))
+		internal->dev = atoi(value);
+	else if (!strcmp(key, "buf_size"))
+		internal->buf_size = atoi(value);
 
-	while (options) {
-		if (!strcmp(options->key, "card"))
-			state->card = atoi(options->value);
-		else if (!strcmp(options->key, "dev"))
-			state->dev = atoi(options->value);
-		else if (!strcmp(options->key, "buf_size"))
-			state->buf_size = atoi(options->value);
-		
-		options = options->next;
-	}
+	return 1;
 }
 
-ao_internal_t *plugin_open(uint_32 bits, uint_32 rate, uint_32 channels, ao_option_t *options)
+int ao_plugin_open(ao_device *device, ao_sample_format *format)
 {
-	ao_alsa_internal_t *state;
+	ao_alsa_internal *internal = (ao_alsa_internal *) device->internal;
+
         snd_pcm_channel_params_t param;
         int err;
 
@@ -93,74 +129,66 @@
 
         param.format.interleave = 1;
 
-	switch (bits) {
+	switch (format->bits) {
         case 8  : param.format.format = SND_PCM_SFMT_S8;
                   break;
-        case 16 : param.format.format = _is_big_endian() ?
+        case 16 : param.format.format = 
+		    device->client_byte_format == AO_FMT_BIG ?
                     SND_PCM_SFMT_S16_BE : SND_PCM_SFMT_S16_LE;
+	          device->driver_byte_format = device->client_byte_format;
                   break;
-	default : return NULL;
+	default : return 0;
         }
 
-	if (channels > 0 && channels < 3)
-		param.format.voices = channels;
+	if (format->channels == 1 || format->channels == 2)
+		param.format.voices = format->channels;
         else
-		return NULL;
-
-	// Allocate the state structure and parse the options
-	state = malloc(sizeof(ao_alsa_internal_t));
+		return 0;
 
-	if (state == NULL)
-		return NULL;
-
-	ao_alsa_parse_options(state, options);
-
         // Finish filling in the parameter structure
-	param.format.rate = rate;
+	param.format.rate = format->rate;
 
         param.start_mode = SND_PCM_START_FULL;
         
         param.stop_mode = SND_PCM_STOP_STOP;
 
-	param.buf.block.frag_size = state->buf_size;
+	param.buf.block.frag_size = internal->buf_size;
         param.buf.block.frags_min = 1;
         param.buf.block.frags_max = 8;
 
+	internal->buf = malloc(internal->buf_size);
+	internal->buf_end = 0;
+	if (internal->buf == NULL)
+	  return 0;  /* Could not alloc swap buffer */
+
 
-	err = snd_pcm_open(&(state->pcm_handle), 
-			   state->card, 
-			   state->dev,
+	/* Open the ALSA device */
+	err = snd_pcm_open(&(internal->pcm_handle), 
+			   internal->card, 
+			   internal->dev,
                            SND_PCM_OPEN_PLAYBACK | SND_PCM_OPEN_NONBLOCK);
         if (err < 0) {
-		free(state);
-		return NULL;
+		free(internal->buf);
+		return 0;
         }
 
-	err = snd_pcm_channel_params(state->pcm_handle, &param);
+	err = snd_pcm_channel_params(internal->pcm_handle, &param);
 
         if (err < 0) {
-		snd_pcm_close(state->pcm_handle);
-		free(state);
-		return NULL;
+		snd_pcm_close(internal->pcm_handle);
+		free(internal->buf);
+		return 0;
         }
 
-	state->buf = malloc(state->buf_size);
-	state->buf_end = 0;
+	snd_pcm_nonblock_mode(internal->pcm_handle, 0);
+	snd_pcm_channel_prepare(internal->pcm_handle, 
+				SND_PCM_CHANNEL_PLAYBACK);
 
-	snd_pcm_nonblock_mode(state->pcm_handle, 0);
-	snd_pcm_channel_prepare(state->pcm_handle, SND_PCM_CHANNEL_PLAYBACK);
-
-	return state;
+	return 1;
 }
 
-void plugin_close(ao_internal_t *state)
-{
-	ao_alsa_internal_t *s = (ao_alsa_internal_t *) state;
-	snd_pcm_close(s->pcm_handle);
-	free(s);
-}
 
-void ao_alsa_write_buffer(ao_alsa_internal_t *s)
+int _alsa_write_buffer(ao_alsa_internal *s)
 {
         snd_pcm_channel_status_t status;
         snd_pcm_t *pcm_handle = s->pcm_handle;
@@ -171,7 +199,7 @@
         memset(&status, 0, sizeof(status));
         if (snd_pcm_channel_status(pcm_handle, &status) < 0) {
                 fprintf(stderr, "ALSA: could not get channel status\n");
-		return;
+		return 0;
         }       
         if (status.underrun) {
                 fprintf(stderr, "ALSA: underrun. resetting channel\n");
@@ -180,47 +208,65 @@
                 snd_pcm_write(pcm_handle, s->buf, len);
                 if (snd_pcm_channel_status(pcm_handle, &status) < 0) {
                         fprintf(stderr, "ALSA: could not get channel status. giving up\n");
-			return;
+			return 0;
                 }
                 if (status.underrun) {
                         fprintf(stderr, "ALSA: write error. giving up\n");
-					return;
+					return 0;
                 }               
         }
+
+	return 1;
 }	
+
 
-void plugin_play(ao_internal_t *state, void* output_samples, uint_32 num_bytes)
+int ao_plugin_play(ao_device *device, const char *output_samples, 
+		uint_32 num_bytes)
 {
-	ao_alsa_internal_t *s = (ao_alsa_internal_t *) state;
+	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) {
+	while (packed < num_bytes && ok) {
                 /* Pack the buffer */
-		if (num_bytes-packed < s->buf_size-s->buf_end)
+		if (num_bytes-packed < internal->buf_size - internal->buf_end)
                         copy_len = num_bytes - packed;
                 else
-			copy_len = s->buf_size-s->buf_end;
+			copy_len = internal->buf_size - internal->buf_end;
 
-		memcpy(s->buf + s->buf_end, samples + packed, copy_len); 
+		memcpy(internal->buf + internal->buf_end, samples + packed, 
+		       copy_len); 
                 packed += copy_len;
-		s->buf_end += copy_len;
+		internal->buf_end += copy_len;
 
-		if(s->buf_end == s->buf_size)
-			ao_alsa_write_buffer(s);
+		if(internal->buf_end == internal->buf_size)
+			ok = _alsa_write_buffer(internal);
         }
+
+	return ok;
 }
+
 
-int plugin_get_latency(ao_internal_t *state)
+int ao_plugin_close(ao_device *device)
 {
-	ao_alsa_internal_t * s = (ao_alsa_internal_t *) state;
-	snd_pcm_channel_status_t status;
-	int err = snd_pcm_channel_status(s->pcm_handle, &status);
-	return (err < 0 ? 0 : status.count);
+	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;
 }
+
 
-ao_info_t *plugin_get_driver_info(void)
+void ao_plugin_device_clear(ao_device *device)
 {
-	return &ao_alsa_info;
+	ao_alsa_internal *internal = (ao_alsa_internal *) device->internal;
+
+	free(internal);
 }

1.4       +83 -70    ao/src/plugins/arts/ao_arts.c

Index: ao_arts.c
===================================================================
RCS file: /usr/local/cvsroot/ao/src/plugins/arts/ao_arts.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- ao_arts.c	2001/02/28 07:50:12	1.3
+++ ao_arts.c	2001/08/04 02:56:16	1.4
@@ -2,7 +2,7 @@
  *
  *  ao_arts.c
  *
- *      Copyright (C) Rik Hemsley (rikkus) <rik at kde.org 2000
+ *      Copyright (C) Rik Hemsley (rikkus) <rik at kde.org> 2000
  *
  *  This file is part of libao, a cross-platform library.  See
  *  README for a history of this source code.
@@ -28,100 +28,113 @@
 
 #include <artsc.h>
 #include <ao/ao.h>
+#include <ao/plugin.h>
 
-typedef struct ao_arts_internal_s
+
+static ao_info ao_arts_info =
 {
-  arts_stream_t stream;
-	uint_32 bits;
-	uint_32 rate;
-	uint_32 channels;
-} ao_arts_internal_t;
-
-ao_info_t ao_arts_info =
-{
-  "aRts output",
-  "arts",
-  "Rik Hemsley (rikkus) <rik at kde.org>",
-  "Outputs to the aRts soundserver."
+	AO_TYPE_LIVE,
+	"aRts output",
+	"arts",
+	"Rik Hemsley (rikkus) <rik at kde.org>",
+	"Outputs to the aRts soundserver.",
+	AO_FMT_NATIVE,
+	10,
+	NULL,
+	0
 };
+
+
+typedef struct ao_arts_internal
+{
+	arts_stream_t stream;
+} ao_arts_internal;
+
 
-  ao_internal_t *
-plugin_open
-(
- uint_32 bits,
- uint_32 rate,
- uint_32 channels,
- ao_option_t * options
-)
+int ao_plugin_test()
 {
-  ao_arts_internal_t * state;
-  int errorcode;
+	if (arts_init() == 0) {
+		arts_free();
+		return 1;
+	} else
+		return 0;
+}
 
-  state = malloc(sizeof(ao_arts_internal_t));
 
-  if (NULL == state)
-  {
-    fprintf(stderr, "libao: Can't initialise aRts driver. Out of memory.\n");
-    return NULL;
-  }
+ao_info *ao_plugin_driver_info(void)
+{
+	return &ao_arts_info;
+}
 
-  errorcode = arts_init();
 
-  if (0 != errorcode)
-  {
-    fprintf(stderr, "libao: Can't initialise aRts driver.\n");
-    fprintf(stderr, "libao: Error: %s\n", arts_error_text(errorcode));
-    free(state);
-    return NULL;
-  }
+int ao_plugin_device_init(ao_device *device)
+{
+	ao_arts_internal *internal;
 
-  state->stream = arts_play_stream(rate, bits, channels, "ao stream");
+	internal = (ao_arts_internal *) malloc(sizeof(ao_arts_internal));
 
-	state->bits = bits;
-	state->rate = rate;
-	state->channels = channels;
+	if (internal == NULL)	
+		return 0; /* Could not initialize device memory */
+	
+	device->internal = internal;
 
-  return state;
+	return 1; /* Memory alloc successful */
 }
+
 
-  void
-plugin_close(ao_internal_t * state)
+int ao_plugin_set_option(ao_device *device, const char *key, const char *value)
 {
-  arts_close_stream(((ao_arts_internal_t *)state)->stream);
-  arts_free();
-  free(state);
+	return 1; /* No options */
 }
 
-  void
-plugin_play
-(
- ao_internal_t * state,
- void * buf,
- uint_32 count
-)
+int ao_plugin_open(ao_device *device, ao_sample_format *format)
 {
-  int bytes_written;
+	ao_arts_internal *internal = (ao_arts_internal *) device->internal;
+	int errorcode;
 
-  bytes_written = arts_write(((ao_arts_internal_t *)state)->stream, buf, count);
+	errorcode = arts_init();
 
-  if (bytes_written != count)
-  {
-    fprintf(stderr, "libao: aRts driver would not write all data !\n");
-  }
+	if (0 != errorcode)
+	{
+		return 0; /* Could not connect to server */
+	}
+
+	device->driver_byte_format = AO_FMT_NATIVE;
+
+	internal->stream = arts_play_stream(format->rate, 
+					    format->bits, 
+					    format->channels, 
+					    "libao stream");
+	return 1;
 }
+
 
-  int
-plugin_get_latency(ao_internal_t * state)
+int ao_plugin_play(ao_device *device, const char *output_samples, 
+		uint_32 num_bytes)
 {
-  ao_arts_internal_t * s = (ao_arts_internal_t *)state;
-	int ms = arts_stream_get(s->stream, ARTS_P_TOTAL_LATENCY);
-	int sample_rate = (s->bits / 8) * s->rate * s->channels;
-	return (sample_rate * ms) / 1000;
+	ao_arts_internal *internal = (ao_arts_internal *) device->internal;
+
+	if (arts_write(internal->stream, output_samples, 
+		       num_bytes) < num_bytes)
+		return 0;
+	else
+		return 1;
 }
+
 
-  ao_info_t *
-plugin_get_driver_info(void)
+int ao_plugin_close(ao_device *device)
 {
-  return &ao_arts_info;
+	ao_arts_internal *internal = (ao_arts_internal *) device->internal;
+	arts_close_stream(internal->stream);
+	arts_free();
+
+	return 1;
 }
 
+
+void ao_plugin_device_clear(ao_device *device)
+{
+	ao_arts_internal *internal = (ao_arts_internal *) device->internal;
+
+	free(internal);
+}

1.5       +95 -51    ao/src/plugins/esd/ao_esd.c

Index: ao_esd.c
===================================================================
RCS file: /usr/local/cvsroot/ao/src/plugins/esd/ao_esd.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- ao_esd.c	2001/03/07 04:18:01	1.4
+++ ao_esd.c	2001/08/04 02:56:16	1.5
@@ -2,7 +2,7 @@
  *
  *  ao_esd.c
  *
- *      Copyright (C) Stan Seibert - July 2000
+ *      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.
@@ -32,100 +32,144 @@
 
 #include <esd.h>
 #include <ao/ao.h>
+#include <ao/plugin.h>
 
-typedef struct ao_esd_internal_s
+static char *ao_esd_options[] = {"host"};
+static ao_info ao_esd_info =
 {
-	int sock;
-	char *host;
-} ao_esd_internal_t;
-
-ao_info_t ao_esd_info =
-{
+	AO_TYPE_LIVE,
         "ESounD output",
         "esd",
         "Stan Seibert <volsung at asu.edu>",
-	"Outputs to the Enlightened Sound Daemon."
+	"Outputs to the Enlightened Sound Daemon.",
+	AO_FMT_NATIVE,
+	10,
+	ao_esd_options,
+	1
 };
+
+
+typedef struct ao_esd_internal
+{
+	int sock;
+	char *host;
+} ao_esd_internal;
+
+
+int ao_plugin_test()
+{
+	int sock;
+
+	sock = esd_open_sound(NULL);
+	if (sock < 0) 
+		return 0;
+	else {
+		esd_close(sock);
+		return 1;
+	}
+}
+
+
+ao_info *ao_plugin_driver_info(void)
+{
+	return &ao_esd_info;
+}
+
 
-void ao_esd_parse_options(ao_esd_internal_t *state, ao_option_t *options)
+int ao_plugin_device_init(ao_device *device)
 {
-	state->host = NULL;
+	ao_esd_internal *internal;
 
-	while (options) {
-		if (!strcmp(options->key, "host"))
-			state->host = strdup(options->value);
-		
-		options = options->next;
+	internal = (ao_esd_internal *) malloc(sizeof(ao_esd_internal));
+
+	if (internal == NULL)	
+		return 0; /* Could not initialize device memory */
+	
+	internal->host = NULL;
+	
+	device->internal = internal;
+
+	return 1; /* Memory alloc successful */
+}
+
+int ao_plugin_set_option(ao_device *device, const char *key, const char *value)
+{
+	ao_esd_internal *internal = (ao_esd_internal *) device->internal;
+
+	if (!strcmp(key, "host")) {
+		free(internal->host);
+		internal->host = strdup(value);
         }
+
+	return 1;
 }
 
-ao_internal_t *plugin_open(uint_32 bits, uint_32 rate, uint_32 channels, ao_option_t *options)
+int ao_plugin_open(ao_device *device, ao_sample_format *format)
 {
-	ao_esd_internal_t *state;
+	ao_esd_internal *internal = (ao_esd_internal *) device->internal;
         int esd_bits;
         int esd_channels;
         int esd_mode = ESD_STREAM;
         int esd_func = ESD_PLAY;
         int esd_format;
 
-	switch (bits)
+	switch (format->bits)
         {
         case 8  : esd_bits = ESD_BITS8;
                   break;
         case 16 : esd_bits = ESD_BITS16;
                   break;
-	default : return NULL;
+	default : return 0;
         }
 
-	switch (channels)
+	switch (format->channels)
         {
         case 1 : esd_channels = ESD_MONO;
                  break;
         case 2 : esd_channels = ESD_STEREO;
                  break;
-	default: return NULL;
+	default: return 0;
         }
         
         esd_format = esd_bits | esd_channels | esd_mode | esd_func;
-
-	state = malloc(sizeof(ao_esd_internal_t));
-
-	if (state == NULL)
-		return NULL;
 
-	ao_esd_parse_options(state, options);
-
-	state->sock = esd_play_stream(esd_format, rate, state->host,
-				      "libao output");
-	if ( state->sock <= 0 ) {
-		free(state->host);
-		free(state);
-		return NULL;
-	}
+	internal->sock = esd_play_stream(esd_format, format->rate, 
+					 internal->host,
+					 "libao output");
+	if (internal->sock < 0)
+		return 0; /* Could not contact ESD server */
+	
+	device->driver_byte_format = AO_FMT_NATIVE;
 
-	return state;
+	return 1;
 }
 
-void plugin_close(ao_internal_t *state)
+int ao_plugin_play(ao_device *device, const char* output_samples, 
+		uint_32 num_bytes)
 {
-	ao_esd_internal_t *s = (ao_esd_internal_t *)state;
-	close(s->sock);
-	free(s->host);
-	free(s);
-}
+	ao_esd_internal *internal = (ao_esd_internal *) device->internal;
 
-void plugin_play(ao_internal_t *state, void* output_samples, uint_32 num_bytes)
-{
-	write(((ao_esd_internal_t *) state)->sock, output_samples, num_bytes);
+	if (write(internal->sock, output_samples, num_bytes) < 0)
+		return 0;
+	else
+		return 1;
 }
+
 
-int plugin_get_latency(ao_internal_t *state)
+int ao_plugin_close(ao_device *device)
 {
-	ao_esd_internal_t *s = (ao_esd_internal_t *)state;
-	return (esd_get_latency(s->sock));
+	ao_esd_internal *internal = (ao_esd_internal *) device->internal;
+
+	close(internal->sock);
+
+	return 1;
 }
+
 
-ao_info_t *plugin_get_driver_info(void)
+void ao_plugin_device_clear(ao_device *device)
 {
-	return &ao_esd_info;
+	ao_esd_internal *internal = (ao_esd_internal *) device->internal;
+
+	free(internal->host);
+	free(internal);
 }

1.4       +101 -52   ao/src/plugins/irix/ao_irix.c

Index: ao_irix.c
===================================================================
RCS file: /usr/local/cvsroot/ao/src/plugins/irix/ao_irix.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- ao_irix.c	2001/02/24 01:31:48	1.3
+++ ao_irix.c	2001/08/04 02:56:17	1.4
@@ -4,7 +4,7 @@
  *
  *      Original Copyright (C) Aaron Holtzman - May 1999
  *      Port to IRIX by Jim Miller, SGI - Nov 1999
- *      Modifications Copyright (C) Stan Seibert - July 2000
+ *      Modifications 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.
@@ -37,98 +37,143 @@
 #include <ao/ao.h>
 
 
-typedef struct ao_irix_internal_s {
+typedef struct ao_irix_internal {
         static ALport alport = 0;
         static ALconfig alconfig = 0;
         static int bytesPerWord = 1;
         static int nChannels = 2;
-} ao_irix_internal_t;
+} ao_irix_internal;
 
 
-ao_info_t ao_irix_info =
+static ao_info ao_irix_info =
 {
+	AO_TYPE_LIVE,
         "Irix audio output ",
         "irix",
         "Jim Miller <???@sgi.com>",
         "WARNING: This driver is untested!"
+	AO_FMT_NATIVE,
+	20,
+	NULL,
+	1
 };
 
 
+int ao_plugin_test()
+{
+	char *dev_path;
+	ALport port;
+
+
+	if ( !(port = alOpenPort("libao test", "w", 0)) )
+		return 0; /* Cannot use this plugin with default parameters */
+	else {
+		alClosePort(port);
+		return 1; /* This plugin works in default mode */
+	}
+}
+
+
+ao_info *ao_plugin_driver_info(void)
+{
+	return &ao_irix_info;
+}
+
+
+int ao_plugin_device_init(ao_device *device)
+{
+	ao_irix_internal *internal;
+
+	internal = (ao_irix_internal *) malloc(sizeof(ao_irix_internal));
+
+	if (internal == NULL)	
+		return 0; /* Could not initialize device memory */
+
+	internal->alconfig = alNewConfig();
+		
+	device->internal = internal;
+
+	return 1; /* Memory alloc successful */
+}
+
+
+int ao_plugin_set_option(ao_device *device, const char *key, const char *value)
+{
+	return 1; /* No options */
+}
+
+
 /*
  * open the audio device for writing to
  */
-ao_internal_t *plugin_open(uint_32 bits, uint_32 rate, uint_32 channels, ao_option_t *options)
+int ao_plugin_open(ao_device *device, ao_sample_format *format)
 {
+	ao_irix_internal *internal = (ao_irix_internal *) device->internal;
         ALpv params[2];
         int  dev = AL_DEFAULT_OUTPUT;
         int  wsize = AL_SAMPLE_16;
-	ao_irix_internal_t *state;
-
-	state = malloc(sizeof(ao_irix_internal_t));
-	if (state == NULL)
-		return NULL;
-	
 
-	state->nChannels = channels;
 
+	internal->nChannels = channels;
 
-	state->alconfig = alNewConfig();
-
-	if (alSetQueueSize(state->alconfig, BUFFER_SIZE) < 0) {
+	if (alSetQueueSize(internal->alconfig, BUFFER_SIZE) < 0) {
                 fprintf(stderr, "alSetQueueSize failed: %s\n", 
-			alGetErrorString(oserror()));
+		alGetErrorString(oserror()));
                 return 0;
         }
 
-	if (alSetChannels(state->alconfig, channels) < 0) {
+	if (alSetChannels(internal->alconfig, channels) < 0) {
                 fprintf(stderr, "alSetChannels(%d) failed: %s\n", 
-			channels, alGetErrorString(oserror()));
+		channels, alGetErrorString(oserror()));
                 return 0;
         }
         
-	if (alSetDevice(state->alconfig, dev) < 0) {
+	if (alSetDevice(internal->alconfig, dev) < 0) {
                 fprintf(stderr, "alSetDevice failed: %s\n", 
-			alGetErrorString(oserror()));
+		alGetErrorString(oserror()));
                 return 0;
         }
         
-	if (alSetSampFmt(state->alconfig, AL_SAMPFMT_TWOSCOMP) < 0) {
+	if (alSetSampFmt(internal->alconfig, AL_SAMPFMT_TWOSCOMP) < 0) {
                 fprintf(stderr, "alSetSampFmt failed: %s\n", 
-			alGetErrorString(oserror()));
+		alGetErrorString(oserror()));
                 return 0;
         }
 
-	state->alport = alOpenPort("AC3Decode", "w", 0);
-
-	if (!state->alport) {
-		fprintf(stderr, "alOpenPort failed: %s\n", 
-			alGetErrorString(oserror()));
-		return 0;
-	}
-
-	switch (bits) {
+	switch (format->bits) {
         case 8:         
-		state->bytesPerWord = 1;
+		internal->bytesPerWord = 1;
                 wsize = AL_SAMPLE_8;
                 break;
                 
         case 16: 
-		state->bytesPerWord = 2;
+		internal->bytesPerWord = 2;
                 wsize = AL_SAMPLE_16;
                 break;
                 
         case 24:
-		state->bytesPerWord = 4;
+		internal->bytesPerWord = 4;
                 wsize = AL_SAMPLE_24;
                 break;
                 
         default:
-		fprintf(stderr,"Irix audio: unsupported bit with %d\n", bits);
+	    fprintf(stderr,"Irix audio: unsupported bit with %d\n", bits);
                 break;
         }
+
+
+	internal->alport = alOpenPort("libao", "w", 0);
+
+	if (!internal->alport) {
+		fprintf(stderr, "alOpenPort failed: %s\n", 
+			alGetErrorString(oserror()));
+		return 0;
+	}
 
-	if (alSetWidth(state->alconfig, wsize) < 0) {
+
+	if (alSetWidth(internal->alconfig, wsize) < 0) {
                 fprintf(stderr, "alSetWidth failed: %s\n", alGetErrorString(oserror()));
+		alClosePort(internal->alport);
                 return 0;
         }
         
@@ -138,38 +183,42 @@
         params[1].value.i = AL_CRYSTAL_MCLK_TYPE;
         if ( alSetParams(dev, params, 1) < 0) {
                 printf("alSetParams() failed: %s\n", alGetErrorString(oserror()));
+		alClosePort(internal->alport);
                 return 0;
         }
+	
+	device->driver_byte_format = AO_FMT_NATIVE;
         
-	return state;
+	return 1;
 }
 
 /*
  * play the sample to the already opened file descriptor
  */
-
-void plugin_play(ao_internal_t *state, void* output_samples, uint_32 num_bytes)
+int ao_plugin_play(ao_device *device, const char *output_samples, 
+		uint_32 num_bytes)
 {
-	alWriteFrames(((ao_irix_internal_t *)state)->alport, output_samples, num_bytes); 
+	ao_irix_internal *internal = (ao_irix_internal *) device->internal;
+	
+	alWriteFrames(internal->alport, output_samples, num_bytes); 
+
+	return 1; /* FIXME: Need to check if the above function failed */
 }
 
-void plugin_close(ao_internal_t *state)
+int ao_plugin_close(ao_device *device)
 {
-	ao_irix_internal_t *s = (ao_irix_internal_t *)state;
+	ao_irix_internal *internal = (ao_irix_internal *) device->internal;
 
-	alClosePort(s->alport);
-	alFreeConfig(s->alconfig);
+	alClosePort(internal->alport);
 
-	free(state);
+	return 1;
 }
 
-int plugin_get_latency(ao_internal_t *state)
-{
-	/* TODO */
-	return 0;
-}
 
-ao_info_t *plugin_get_driver_info(void)
+void ao_plugin_device_clear(ao_device *device)
 {
-	return &ao_irix_info;
+	ao_irix_internal *internal = (ao_irix_internal *) device->internal;
+
+	alFreeConfig(internal->alconfig);
+	free(internal);
 }

1.2       +2 -0      ao/src/plugins/irix/.cvsignore

1.2       +27 -0     ao/src/plugins/irix/Makefile.am

1.7       +147 -99   ao/src/plugins/oss/ao_oss.c

Index: ao_oss.c
===================================================================
RCS file: /usr/local/cvsroot/ao/src/plugins/oss/ao_oss.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- ao_oss.c	2001/02/24 01:31:48	1.6
+++ ao_oss.c	2001/08/04 02:56:17	1.7
@@ -3,7 +3,7 @@
  *  ao_oss.c
  *
  *      Original Copyright (C) Aaron Holtzman - May 1999
- *      Modifications Copyright (C) Stan Seibert - July 2000
+ *      Modifications Copyright (C) Stan Seibert - July 2000, June 2001
  *
  *  This file is part of libao, a cross-platform library.  See
  *  README for a history of this source code.
@@ -39,170 +39,218 @@
 #endif
 #include <sys/ioctl.h>
 
-#include <ao/ao.h>
+#include "ao/ao.h"
+#include "ao/plugin.h"
 
-ao_info_t ao_oss_info =
+
+static char *ao_oss_options[] = {"dev"};
+static ao_info ao_oss_info =
 {
+	AO_TYPE_LIVE,
         "OSS audio driver output ",
         "oss",
         "Aaron Holtzman <aholtzma at ess.engr.uvic.ca>",
-	"Outputs audio to the Open Sound System driver."
+	"Outputs audio to the Open Sound System driver.",
+	AO_FMT_NATIVE,
+	20,
+	ao_oss_options,
+	1
 };
 
 
-typedef struct ao_oss_internal_s {
+typedef struct ao_oss_internal {
         char *dev;
         int fd;
-} ao_oss_internal_t;
+} ao_oss_internal;
+
 
-static int _is_big_endian(void)
+/*
+ * open either the devfs device or the traditional device and return a
+ * file handle.  Also strdup() path to the selected device into
+ * *dev_path.  Assumes that *dev_path does not need to be free()'ed
+ * initially.
+ */
+int _open_default_oss_device (char **dev_path)
 {
-	uint_16 pattern = 0xbabe;
-	unsigned char *bytewise = (unsigned char *)&pattern;
+	int fd;
+
+	/* default: first try the devfs path */
+	*dev_path = strdup("/dev/sound/dsp");
+	fd = open(*dev_path, O_WRONLY);
+
+	if(fd < 0) 
+	{
+		/* no? then try the traditional path */
+		char *err = strdup(strerror(errno));
+		char *dev = strdup(*dev_path);
+		free(*dev_path);
+		*dev_path = strdup("/dev/dsp");
+		fd = open(*dev_path,O_WRONLY);
 
-	if (bytewise[0] == 0xba) return 1;
-	return 0;
+		if(fd < 0) 
+		{
+		  /*			fprintf(stderr,
+				"libao - error: Could not open either default device:\n"
+				"  %s - %s\n"
+				"  %s - %s\n",
+				err, dev,
+				strerror(errno), *dev_path); */
+			free(err);
+			free(dev);
+			free(*dev_path);
+			*dev_path = NULL;
+		}
+	}
+
+	return fd;
 }
+
 
-void ao_oss_parse_options(ao_oss_internal_t *state, ao_option_t *options)
+int ao_plugin_test()
 {
-	state->dev = NULL;
+	char *dev_path;
+	int fd;
 
-	while (options) {
-		if (!strcmp(options->key, "dsp"))
-			state->dev = strdup(options->value);
-		
-		options = options->next;
+	if ( (fd = _open_default_oss_device(&dev_path)) < 0 )
+		return 0; /* Cannot use this plugin with default parameters */
+	else {
+		close(fd);
+		return 1; /* This plugin works in default mode */
         }
+}
+
 
-	/* otherwise, the NULL setting indicates the open()
-	   routine should choose something from hardwired defaults */
+ao_info *ao_plugin_driver_info(void)
+{
+	return &ao_oss_info;
 }
 
-/*
- * open the audio device for writing to
- */
-ao_internal_t *plugin_open(uint_32 bits, uint_32 rate, uint_32 channels, ao_option_t *options)
+
+int ao_plugin_device_init(ao_device *device)
 {
-	ao_oss_internal_t *state;
-	int tmp;
+	ao_oss_internal *internal;
+
+	internal = (ao_oss_internal *) malloc(sizeof(ao_oss_internal));
+
+	if (internal == NULL)	
+		return 0; /* Could not initialize device memory */
         
-	/* Allocate a state structure to hold instance
-	   information.  (Long live C++!) */
-	state = malloc(sizeof(ao_oss_internal_t));
+	internal->dev = NULL;
+	
+	device->internal = internal;
 
-	if (state == NULL)	
-	{
-		fprintf(stderr,"libao - %s: Allocating state memory.\n",
-			strerror(errno));
-		goto ERR;
+	return 1; /* Memory alloc successful */
+}
+
+int ao_plugin_set_option(ao_device *device, const char *key, const char *value)
+{
+	ao_oss_internal *internal = (ao_oss_internal *) device->internal;
+
+
+	if (!strcmp(key, "dev")) {
+		/* Free old string in case "dev" set twice in options */
+		free(internal->dev); 
+		internal->dev = strdup(value);
         }
+
+	return 1;
+}
 
-	ao_oss_parse_options(state, options);
 
+/*
+ * open the audio device for writing to
+ */
+int ao_plugin_open(ao_device *device, ao_sample_format *format)
+{
+	ao_oss_internal *internal = (ao_oss_internal *) device->internal;
+	int tmp;
+
         /* Open the device driver */
         
-	if (state->dev != NULL) {
+	if (internal->dev != NULL) {
                 /* open the user-specified path */
-		state->fd=open(state->dev,O_WRONLY);
-		if(state->fd < 0) 
-		{
-			fprintf(stderr,"libao - %s: Opening audio device %s\n",
-				strerror(errno), state->dev);
-			goto ERR;
+		internal->fd = open(internal->dev, O_WRONLY);
+
+		if(internal->fd < 0) {
+		  /* fprintf(stderr,"libao - %s: Opening audio device %s\n",
+		     strerror(errno), internal->dev); */
+			return 0;  /* Cannot open device */
                 }
+
         } else {
-		/* default: first try the devfs path */
-		state->dev = strdup("/dev/sound/dsp");
-		state->fd=open(state->dev,O_WRONLY);
-		if(state->fd < 0) 
-		{
-			/* no? then try the traditional path */
-			char *err = strdup(strerror(errno));
-			char *dev = strdup(state->dev);
-			free(state->dev);
-			state->dev = strdup("/dev/dsp");
-			state->fd=open(state->dev,O_WRONLY);
-			if(state->fd < 0) 
-			{
-				fprintf(stderr,
-					"libao - error: Could not open either default device:\n"
-					"  %s - %s\n"
-					"  %s - %s\n",
-					err, dev,
-					strerror(errno), state->dev);
-				free(err);
-				free(dev);
-				goto ERR;
-			}
-		}
+		internal->fd = _open_default_oss_device(&internal->dev);
+		if (internal->fd < 0)
+			return 0;  /* Cannot open default device */
         }
 
-	switch (channels)
+	/* Now set all of the parameters */
+
+	switch (format->channels)
         {
         case 1: tmp = 0;
                 break;
         case 2: tmp = 1;
                 break;
         default:fprintf(stderr,"libao - Unsupported number of channels: %d.",
-			channels);
+			format->channels);
                 goto ERR;
         }
-	ioctl(state->fd,SNDCTL_DSP_STEREO,&tmp);
+	ioctl(internal->fd,SNDCTL_DSP_STEREO,&tmp);
         
-	switch (bits)
+	/* To eliminate the need for a swap buffer, we set the device
+	   to use whatever byte format the client selected. */
+	switch (format->bits)
         {
         case 8: tmp = AFMT_S8;
                 break;
-        case 16: tmp = _is_big_endian() ? AFMT_S16_BE : AFMT_S16_LE;
+        case 16: tmp = device->client_byte_format == AO_FMT_BIG ? 
+		   AFMT_S16_BE : AFMT_S16_LE;
+	        device->driver_byte_format = device->client_byte_format;
                 break;
         default:fprintf(stderr,"libao - Unsupported number of bits: %d.",
-			bits);
+			format->bits);
                 goto ERR;
         }
-	ioctl(state->fd,SNDCTL_DSP_SAMPLESIZE,&tmp);
+	ioctl(internal->fd,SNDCTL_DSP_SAMPLESIZE,&tmp);
         
-	tmp = rate;
-	ioctl(state->fd,SNDCTL_DSP_SPEED, &tmp);
+	tmp = format->rate;
+	ioctl(internal->fd,SNDCTL_DSP_SPEED, &tmp);
         
-	return state;
+	return 1; /* Open successful */
 
  ERR:
-	if(state != NULL)
-	{ 
-		if (state->fd >= 0) { close(state->fd); }
-		if (state->dev) { free(state->dev); }
-		free(state);
-	}
-
-	return NULL;
+	close(internal->fd);
+	return 0; /* Failed to open device */
 }
 
 /*
  * play the sample to the already opened file descriptor
  */
-void plugin_play(ao_internal_t *state, void *output_samples, uint_32 num_bytes)
+int ao_plugin_play(ao_device *device, const char *output_samples, 
+		uint_32 num_bytes)
 {
-	write( ((ao_oss_internal_t *)state)->fd, output_samples, num_bytes);
+	ao_oss_internal *internal = (ao_oss_internal *) device->internal;
+
+	if (write(internal->fd, output_samples, num_bytes) < 0)
+		return 0;
+	else
+		return 1;
 }
 
 
-void plugin_close(ao_internal_t *state)
+int ao_plugin_close(ao_device *device)
 {
-	ao_oss_internal_t *s = (ao_oss_internal_t *) state;
-	close(s->fd);
-	free(s->dev);
-	free(s);
-}
+	ao_oss_internal *internal = (ao_oss_internal *) device->internal;
+	close(internal->fd);
 
-int plugin_get_latency(ao_internal_t *state)
-{
-	int odelay = 0;
-	ioctl(((ao_oss_internal_t *)state)->fd, SNDCTL_DSP_GETODELAY, &odelay);
-	return odelay;
+	return 1;
 }
 
-ao_info_t *plugin_get_driver_info(void)
+
+void ao_plugin_device_clear(ao_device *device)
 {
-	return &ao_oss_info;
+	ao_oss_internal *internal = (ao_oss_internal *) device->internal;
+
+	free(internal->dev);
+	free(internal);
 }

1.2       +101 -71   ao/src/plugins/sun/ao_sun.c

Index: ao_sun.c
===================================================================
RCS file: /usr/local/cvsroot/ao/src/plugins/sun/ao_sun.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- ao_sun.c	2001/05/17 15:28:44	1.1
+++ ao_sun.c	2001/08/04 02:56:18	1.2
@@ -32,119 +32,149 @@
 #include <unistd.h>
 #include <sys/audioio.h>
 
+#include <ao/ao.h>
+#include <ao/plugin.h>
+
+
 #ifndef AUDIO_ENCODING_SLINEAR
 #define AUDIO_ENCODING_SLINEAR AUDIO_ENCODING_LINEAR	/* Solaris */
 #endif
 
-#include <ao/ao.h>
+#ifndef AO_SUN_DEFAULT_DEV
+#define AO_SUN_DEFAULT_DEV "/dev/audio"
+#endif
 
-ao_info_t ao_sun_info = {
+
+static char *ao_sun_options[] = {"dev"};
+ao_info ao_sun_info = {
+	AO_TYPE_LIVE,
         "Sun audio driver output",
         "sun",
         "Christian Weisgerber <naddy at openbsd.org>",
-	"Outputs to the sun audio system."
+	"Outputs to the sun audio system.",
+	AO_FMT_NATIVE,
+	20,
+	ao_sun_options,
+	1
 };
+
 
-typedef struct ao_sun_internal_s {
+typedef struct ao_sun_internal {
         char *dev;
         int fd;
-} ao_sun_internal_t;
+} ao_sun_internal;
 
-void ao_sun_parse_options(ao_sun_internal_t *state, ao_option_t *options)
+
+int ao_plugin_test()
 {
-	state->dev = NULL;
+	int fd;
 
-	while (options) {
-		if (!strcmp(options->key, "dev"))
-			state->dev = strdup(options->value);
-		options = options->next;
+	if ( (fd = open(AO_SUN_DEFAULT_DEV, O_WRONLY)) < 0 )
+		return 0; /* Cannot use this plugin with default parameters */
+	else {
+		close(fd);
+		return 1; /* This plugin works in default mode */
         }
 }
 
-ao_internal_t *plugin_open(uint_32 bits, uint_32 rate, uint_32 channels, ao_option_t *options)
+
+ao_info *ao_plugin_driver_info(void)
 {
-	ao_sun_internal_t *state;
-	audio_info_t info;
+	return &ao_sun_info;
+}
 
-	state = malloc(sizeof(ao_sun_internal_t));
 
-	if (state == NULL) {
-		fprintf(stderr,"libao: Error allocating state memory: %s\n",
-			strerror(errno));
-		goto ERR;
+int ao_plugin_device_init(ao_device *device)
+{
+	ao_sun_internal *internal;
+
+	internal = (ao_sun_internal *) malloc(sizeof(ao_sun_internal));
+
+	if (internal == NULL)	
+		return 0; /* Could not initialize device memory */
+	
+	internal->dev = strdup(AO_SUN_DEFAULT_DEV);
+	
+	if (internal->dev == NULL) {
+		free(internal);
+		return 0;
         }
+		
+	device->internal = internal;
+
+	return 1; /* Memory alloc successful */
+}
 
-	ao_sun_parse_options(state, options);
+int ao_plugin_set_option(ao_device *device, const char *key, const char *value)
+{
+	ao_sun_internal *internal = (ao_sun_internal *) device->internal;
+
 
-	if (state->dev != NULL) {
-		/* open the user-specified path */
-		state->fd = open(state->dev, O_WRONLY);
-		if (state->fd < 0) {
-			fprintf(stderr, "libao: Error opening audio device %s: %s\n",
-				state->dev, strerror(errno));
-			goto ERR;
-		}
-	} else {
-		/* default */
-		state->dev = strdup("/dev/audio");
-		state->fd = open(state->dev, O_WRONLY);
-		if (state->fd < 0) {
-			fprintf(stderr,
-				"libao: Could not open default device %s: %s\n",
-				state->dev, strerror(errno));
-			goto ERR;
-		}
+	if (!strcmp(key, "dev")) {
+		/* Free old string in case "dsp" set twice in options */
+		free(internal->dev); 
+		internal->dev = strdup(value);
         }
 
+	return 1;
+}
+
+
+int ao_plugin_open(ao_device *device, ao_sample_format *format)
+{
+	ao_sun_internal *internal = (ao_sun_internal *) device->internal;
+	
+	audio_info_t info;
+
+	if ( (internal->fd = open(internal->dev, O_WRONLY)) < 0 )
+		return 0;
+
         AUDIO_INITINFO(&info);
 #ifdef AUMODE_PLAY	/* NetBSD/OpenBSD */
         info.mode = AUMODE_PLAY;
 #endif
         info.play.encoding = AUDIO_ENCODING_SLINEAR;
-	info.play.precision = bits;
-	info.play.sample_rate = rate;
-	info.play.channels = channels;
-
- 	if (ioctl(state->fd, AUDIO_SETINFO, &info) < 0) {
-		fprintf(stderr,
-			"libao: Cannot set device to %d bits, %d Hz, %d channels: %s\n",
-			bits, rate, channels, strerror(errno));
-		goto ERR;
+	info.play.precision = format->bits;
+	info.play.sample_rate = format->rate;
+	info.play.channels = format->channels;
+
+ 	if (ioctl(internal->fd, AUDIO_SETINFO, &info) < 0) {
+		close(internal->fd);
+		return 0;  /* Unsupported audio format */
         }
 
-	return state;
+	device->driver_byte_format = AO_FMT_NATIVE;
 
-ERR:
-	if (state != NULL) {
-		if (state->fd >= 0)
-			close(state->fd);
-		if (state->dev)
-			free(state->dev);
-		free(state);
-	}
-	return NULL;
+	return 1;
 }
 
-void plugin_play(ao_internal_t *state, void *output_samples, uint_32 num_bytes)
-{
-	write(((ao_sun_internal_t *)state)->fd, output_samples, num_bytes);
-}
 
-void plugin_close(ao_internal_t *state)
+int ao_plugin_play(ao_device *device, const char *output_samples, 
+		uint_32 num_bytes)
 {
-	ao_sun_internal_t *s = (ao_sun_internal_t *)state;
-	close(s->fd);
-	free(s->dev);
-	free(s);
+	ao_sun_internal *internal = (ao_sun_internal *) device->internal;
+	
+	if (write(internal->fd, output_samples, num_bytes) < 0)
+		return 0;
+	else
+		return 1;
 }
 
-int plugin_get_latency(ao_internal_t *state)
+
+int ao_plugin_close(ao_device *device)
 {
-	/* dummy */
-	return 0;
+	ao_sun_internal *internal = (ao_sun_internal *) device->internal;
+
+	close(internal->fd);
+
+	return 1;
 }
+
 
-ao_info_t *plugin_get_driver_info(void)
+void ao_plugin_device_clear(ao_device *device)
 {
-	return &ao_sun_info;
+	ao_sun_internal *internal = (ao_sun_internal *) device->internal;
+
+	free(internal->dev);
+	free(internal);
 }

--- >8 ----
List archives:  http://www.xiph.org/archives/
Ogg project homepage: http://www.xiph.org/ogg/
To unsubscribe from this list, send a message to 'cvs-request at xiph.org'
containing only the word 'unsubscribe' in the body.  No subject is needed.
Unsubscribe messages sent to the list will be ignored/filtered.



More information about the commits mailing list