[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, ¶m);
+ err = snd_pcm_channel_params(internal->pcm_handle, ¶m);
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