From 3c4067b90e097e6e3eb0f81a730fae6b4d289310 Mon Sep 17 00:00:00 2001 From: Stan Seibert <volsung@xiph.org> Date: Sat, 4 Aug 2001 02:56:18 +0000 Subject: [PATCH] Merger of new API branch (volsung_20010721) with head. git-svn-id: http://svn.xiph.org/trunk/ao@1677 0101bb08-14d6-0310-b084-bc0e0c8e3800 --- Makefile.am | 4 +- configure.in | 9 +- doc/API | 148 ------- doc/DRIVERS | 85 ---- doc/Makefile.am | 2 +- doc/USAGE | 19 - doc/WANTED | 9 - doc/ao_append_option.html | 68 ++++ doc/ao_close.html | 63 +++ doc/ao_default_driver_id.html | 62 +++ doc/ao_device.html | 88 ++++ doc/ao_driver_id.html | 63 +++ doc/ao_driver_info.html | 66 +++ doc/ao_driver_info_list.html | 62 +++ doc/ao_example.c | 83 ++++ doc/ao_free_options.html | 55 +++ doc/ao_info.html | 93 +++++ doc/ao_initialize.html | 58 +++ doc/ao_open_file.html | 99 +++++ doc/ao_open_live.html | 85 ++++ doc/ao_option.html | 59 +++ doc/ao_play.html | 67 ++++ doc/ao_plugin_close.html | 61 +++ doc/ao_plugin_device_clear.html | 53 +++ doc/ao_plugin_device_init.html | 67 ++++ doc/ao_plugin_driver_info.html | 54 +++ doc/ao_plugin_open.html | 71 ++++ doc/ao_plugin_play.html | 70 ++++ doc/ao_plugin_set_option.html | 73 ++++ doc/ao_plugin_test.html | 59 +++ doc/ao_sample_format.html | 62 +++ doc/ao_shutdown.html | 55 +++ doc/config.html | 56 +++ doc/drivers.html | 209 ++++++++++ doc/index.html | 52 +++ doc/libao-api.html | 60 +++ doc/overview.html | 109 +++++ doc/plugin-api.html | 42 ++ doc/plugin-overview.html | 45 +++ doc/style.css | 7 + include/ao/Makefile.am | 3 +- include/ao/ao.h | 137 ++++--- include/ao/os_types.h.in | 5 + include/ao/plugin.h | 50 +++ libao.conf.5 | 68 ++++ src/Makefile.am | 2 +- src/ao_au.c | 237 +++++------ src/ao_null.c | 112 ++++-- src/ao_private.h | 69 ++++ src/ao_raw.c | 228 ++++------- src/ao_wav.c | 316 ++++++--------- src/audio_out.c | 686 ++++++++++++++++++++++++-------- src/config.c | 76 ++++ src/plugins/Makefile.am | 2 +- src/plugins/alsa/ao_alsa.c | 222 +++++++---- src/plugins/arts/ao_arts.c | 151 +++---- src/plugins/esd/ao_esd.c | 146 ++++--- src/plugins/irix/.cvsignore | 2 + src/plugins/irix/Makefile.am | 27 ++ src/plugins/irix/ao_irix.c | 153 ++++--- src/plugins/oss/ao_oss.c | 246 +++++++----- src/plugins/sun/ao_sun.c | 174 ++++---- 62 files changed, 4233 insertions(+), 1431 deletions(-) delete mode 100644 doc/API delete mode 100644 doc/DRIVERS delete mode 100644 doc/USAGE delete mode 100644 doc/WANTED create mode 100644 doc/ao_append_option.html create mode 100644 doc/ao_close.html create mode 100644 doc/ao_default_driver_id.html create mode 100644 doc/ao_device.html create mode 100644 doc/ao_driver_id.html create mode 100644 doc/ao_driver_info.html create mode 100644 doc/ao_driver_info_list.html create mode 100644 doc/ao_example.c create mode 100644 doc/ao_free_options.html create mode 100644 doc/ao_info.html create mode 100644 doc/ao_initialize.html create mode 100644 doc/ao_open_file.html create mode 100644 doc/ao_open_live.html create mode 100644 doc/ao_option.html create mode 100644 doc/ao_play.html create mode 100644 doc/ao_plugin_close.html create mode 100644 doc/ao_plugin_device_clear.html create mode 100644 doc/ao_plugin_device_init.html create mode 100644 doc/ao_plugin_driver_info.html create mode 100644 doc/ao_plugin_open.html create mode 100644 doc/ao_plugin_play.html create mode 100644 doc/ao_plugin_set_option.html create mode 100644 doc/ao_plugin_test.html create mode 100644 doc/ao_sample_format.html create mode 100644 doc/ao_shutdown.html create mode 100644 doc/config.html create mode 100644 doc/drivers.html create mode 100644 doc/index.html create mode 100644 doc/libao-api.html create mode 100644 doc/overview.html create mode 100644 doc/plugin-api.html create mode 100644 doc/plugin-overview.html create mode 100644 doc/style.css create mode 100644 include/ao/plugin.h create mode 100644 libao.conf.5 create mode 100644 src/ao_private.h create mode 100644 src/config.c create mode 100644 src/plugins/irix/.cvsignore create mode 100644 src/plugins/irix/Makefile.am diff --git a/Makefile.am b/Makefile.am index 4971281..fa764c1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -7,7 +7,9 @@ SUBDIRS = src include doc debian 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@" diff --git a/configure.in b/configure.in index 37122aa..9f02cf8 100644 --- a/configure.in +++ b/configure.in @@ -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 @@ AC_ARG_ENABLE(alsa, [ --enable-alsa include alsa 0.5 output plugin ], 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 @@ AM_CONDITIONAL(HAVE_SOLARIS,test "x$have_solaris" = xyes) 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) diff --git a/doc/API b/doc/API deleted file mode 100644 index 3445184..0000000 --- a/doc/API +++ /dev/null @@ -1,148 +0,0 @@ -API - -The libao API makes a distinction between drivers and devices. A -driver is a set of functions that allow audio to be played on a -particular platform (i.e. Solaris, ESD, etc.). A device is a -particular output target that uses a driver. For example, on my -system, I use the OSS driver to play to the /dev/dsp device. - -Using the libao API is fairly simple. Your program should go like -this: - - * Include the <ao/ao.h> header into your program. - - * Call ao_initialize() to initialize the library. - - * Call ao_get_driver_id() with a string corresponding to the short - name of the device (i.e. "oss", "wav", etc.). - - * Create an option list pointer of type (ao_option_t *) and - initialize it to NULL. - - * Through successive calls to ao_append_option(), add any driver - specific options you need. Note that the options take the - form of key-value pairs where supported keys are listed in the - DRIVER file. - - * Call ao_open() and save the returned device pointer. - - * Call ao_play() to output each block of audio. - - * Call ao_close() to close the device. Note that this will - automatically free the memory that was allocated for the device. - Do not attempt to free the device pointer yourself - - * Call ao_shutdown() to close the library. - - -FUNCTIONS - -Before reading the function descriptions below, you should read -through the <ao/ao.h> header file and see the data structures used. - ---- - -void ao_initialize(void) - -Purpose: initialize the library. - -Parameters: none. - ---- - -void ao_shutdown(void) - -Purpose: shuts down the library. - -Parameters: none. - ---- - -int ao_get_driver_id(const char *short_name) - -Purpose: Get the id number for a particular driver. - -Parameters: - const char* short_name - The short name of the driver - -Returns: The driver id number or -1 if the driver does not exist. - ---- - -ao_info_t *ao_get_driver_info(int driver_id) - -Parameters: - int driver_id - The number returned from ao_get_driver_id(). Or one - of the standard drivers. - -Purpose: To get the ao_info_t structure that describes this driver. - -Returns: A pointer to the info structure. Do not modify this -structure. - ---- - -int ao_append_option(ao_option_t **options, const char *key, const char *value) - -Purpose: Append an option to a linked list of options. - -Parameters: - ao_option_t **options - Address of a pointer to the head of the - option list, which may be NULL. - const char* key - The option key - const char* value - the setting for this particular option - -Returns: 1 if the option was appended successfully - 0 if the option was not appended (either due to memory - allocation failure or incorrect option format) - ---- - -void ao_free_options(ao_option_t *options) - -Purpose: Free all of the memory allocated to an option list, including -the key and value strings. - -Parameters: - ao_option_t *options - A pointer to the option list. - ---- - -ao_device_t* ao_open(int driver_id, uint_32 bits, uint_32 rate, - uint_32 channels, ao_option_t *options) - -Purpose: To open a particular device for writing. - -Parameters: - int driver_id - ID number for the driver to use with this device - uint_32 bits - Bits per audio sample (8 or 16) - uint_32 rate - Samples per second (44100, 22050, etc.) - uint_32 channels - Audio channels (1 = mono, 2 = stereo) - ao_option_t *options - Option list - -Returns: Pointer to internal data used for this device. Must be used -in later calls to ao_play() or ao_close(). NULL is returned if the -device cannot be opened. - ---- - -void ao_play(ao_device_t *device, void* output_samples, - uint_32 num_bytes) - -Purpose: To ouput some audio data to the device. - -Parameters: - ao_device_t *device - Device pointer - void *output_samples - Memory buffer containing audio data - uint_32 num_bytes - Number of bytes of audio data in memory buffer - ---- - -void ao_close(ao_device_t *device) - -Purpose: To close the audio device and free device memory. [Do not free -device memory yourself!] - -Parameters - ao_device_t *device - Device pointer - diff --git a/doc/DRIVERS b/doc/DRIVERS deleted file mode 100644 index 2dd4117..0000000 --- a/doc/DRIVERS +++ /dev/null @@ -1,85 +0,0 @@ -DEVICE DRIVERS - -Below are the short names of the devices that libao supports: - -null ----- -Null device. This is just a test device. It counts the -number of bytes sent, but does not write them anywhere. - Option keys: None. - -oss ---- -Open Sound System. This is the audio driver system for -Linux and Free/Net/OpenBSD as well as other UNIX-like systems. - Option keys: - "dsp" - set the dsp device. By default, it tries - "/dev/sound/dsp", followed by "/dev/dsp". - -irix ----- -IRIX audio driver. This was inherited from the original -libao, but has not been tested. Use at your own risk. (Better yet, -fix it! I don't have access to an IRIX system.) - Option keys: None. - -solaris -------- -Solaris audio driver. This was also inherited from the -original libao. Same caveats apply. - Option keys: None. - -alsa ----- -Advanced Linux Sound Architecture. This driver borrows some code from -Jaroslav Kysela's <perex@suse.cz> GPLed aplay that is included with -the alsa-util distribution. It defaults to device 0 on card 0. -Because of the way ALSA reads data, this driver packs sound from -successive calls into a fixed size buffer (defaults to 32kB) and sends -it to the card. - Option keys: - "card" - Sound card number - "dev" - Device number on the sound card - "buf_size" - Override the default buffer size (in bytes) - -esd ---- -ESounD audio driver. This driver by default connects to the ESounD -Daemon on the localhost. - Option keys: - "host" - The hostname where esd is running. by default sound - is played on the local host. A port number can be - specified after a colon, as in "whizbang.com:555". - -wav ---- -WAV file output. This produces a wav file from the audio -data you output. - Option keys: - "file" - Sets the output file. By default, this is - "output.wav". - -raw ---- -Raw sample output. Writes the sound data to disk in uncompressed, -headerless form using the byte order specified. - Option keys: - "file" - Sets the output file. Use "-" if you want to write - to stdout. By default this is "output.raw". - - "byteorder" - Sets the byte order used in the output. Use - "native" for native machine byte order, "big" for - big-endian order, and "little" for little-endian order. By - default this is "native". - -au --- -Sun audio file output. Writes an au file from the audio data you -ouput. - Option keys: - "file" - Sets the output file. Use '-' to write - to stdout. By default this is "output.au" - -ADDING NEW DRIVERS - -[To be written. - Stan] diff --git a/doc/Makefile.am b/doc/Makefile.am index 92f9a25..496b293 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -4,6 +4,6 @@ AUTOMAKE_OPTIONS = foreign docdir = $(datadir)/doc/$(PACKAGE)-$(VERSION) -doc_DATA = API USAGE DRIVERS WANTED +doc_DATA = *.html ao_example.c EXTRA_DIST = $(doc_DATA) diff --git a/doc/USAGE b/doc/USAGE deleted file mode 100644 index c9d7a0a..0000000 --- a/doc/USAGE +++ /dev/null @@ -1,19 +0,0 @@ -USAGE - -Libao is currently a dynamically-linked library. This means if you -want to use it, you have to rewrite your program to use the libao API -and link libao to your programs. - -If you are using autoconf and automake, include the ao.m4 project in -your project (acinclude.m4 is the usual place) and call - -AM_PATH_AO(action-if-found, action-if-not-found) - -in your configure.in. Please look at the ogg123 project for an example -of how this works. - -If you do not use autoconf, you need to link against libao and use -ao-config to figure out where the libs and headers are on your -machine. - -Finally, you need to modify your program to use the libao API. diff --git a/doc/WANTED b/doc/WANTED deleted file mode 100644 index 272b5df..0000000 --- a/doc/WANTED +++ /dev/null @@ -1,9 +0,0 @@ -WANTED - -* Testers to check out the IRIX and Solaris drivers. -* Win32 driver -* BeOS driver -* Other audio file formats. - - - diff --git a/doc/ao_append_option.html b/doc/ao_append_option.html new file mode 100644 index 0000000..f52955d --- /dev/null +++ b/doc/ao_append_option.html @@ -0,0 +1,68 @@ +<html> + +<head> +<title>libao - function - ao_append_option</title> +<link rel=stylesheet href="style.css" type="text/css"> +</head> + +<body bgcolor=white text=black link="#5555ff" alink="#5555ff" vlink="#5555ff"> +<table border=0 width=100%> +<tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +<h1>ao_append_option</h1> + +<p><i>declared in "ao/ao.h";</i></p> + +<p>Append a key-value pair to a linked list of options. The key and +value strings are duplicated into newly allocated memory, so the +calling function retains ownership of the string parameters. + +<br><br> +<table border=0 color=black cellspacing=0 cellpadding=7> +<tr bgcolor=#cccccc> + <td> +<pre><b> +int ao_append_option(<a href="ao_option.html">ao_option</a> **options, const char *key, const char *value); +</b></pre> + </td> +</tr> +</table> + +<h3>Parameters</h3> +<dl> +<dt><i>options</i></dt> +<dd>Address of the pointer to the head of the option list. For an empty list +<tt>*options</tt> will be NULL.</dd> +<dt><i>key</i></dt> +<dd>A string holding the option key.</dd> +<dt><i>num_bytes</i></dt> +<dd>A string holding the option value.</dd> +</dl> + +<h3>Return Values</h3> +<blockquote> +<li>1 indicates success.</li> + +<li>0 indicates memory allocation failure.</li> +</blockquote> +<p> + +<br><br> +<hr noshade> +<table border=0 width=100%> +<tr valign=top> +<td><p class=tiny>copyright © 2001 Stan Seibert</p></td> +<td align=right><p class=tiny><a href="http://www.xiph.org/">xiph.org</a><br><a href="mailto:indigo@aztec.asu.edu">indigo@aztec.asu.edu</a></p></td> +</tr><tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +</body> + +</html> diff --git a/doc/ao_close.html b/doc/ao_close.html new file mode 100644 index 0000000..e78bf54 --- /dev/null +++ b/doc/ao_close.html @@ -0,0 +1,63 @@ +<html> + +<head> +<title>libao - function - ao_close</title> +<link rel=stylesheet href="style.css" type="text/css"> +</head> + +<body bgcolor=white text=black link="#5555ff" alink="#5555ff" vlink="#5555ff"> +<table border=0 width=100%> +<tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +<h1>ao_close</h1> + +<p><i>declared in "ao/ao.h";</i></p> + +<p>Closes the audio device and frees the memory allocated by the +device structure. + +<br><br> +<table border=0 color=black cellspacing=0 cellpadding=7> +<tr bgcolor=#cccccc> + <td> +<pre><b> +int ao_close(<a href="ao_device.html">ao_device</a> *device); +</b></pre> + </td> +</tr> +</table> + +<h3>Parameters</h3> +<dl> +<dt><i>device</i></dt> +<dd>Pointer to device structure as returned by <a href="ao_open_live.html">ao_open_live()</a> or <a href="ao_open_file.html">ao_open_file()</a></dd> +</dl> + +<h3>Return Values</h3> +<blockquote> +<li>1 indicates remaining data written correctly and device +closed.</li> +<li>0 indicates an error while the device was being closed. If this +device was writing to a file, the file may be corrupted.</li> +</blockquote> + + +<br><br> +<hr noshade> +<table border=0 width=100%> +<tr valign=top> +<td><p class=tiny>copyright © 2001 Stan Seibert</p></td> +<td align=right><p class=tiny><a href="http://www.xiph.org/">xiph.org</a><br><a href="mailto:indigo@aztec.asu.edu">indigo@aztec.asu.edu</a></p></td> +</tr><tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +</body> + +</html> diff --git a/doc/ao_default_driver_id.html b/doc/ao_default_driver_id.html new file mode 100644 index 0000000..1942768 --- /dev/null +++ b/doc/ao_default_driver_id.html @@ -0,0 +1,62 @@ +<html> + +<head> +<title>libao - function - ao_default_driver_id</title> +<link rel=stylesheet href="style.css" type="text/css"> +</head> + +<body bgcolor=white text=black link="#5555ff" alink="#5555ff" vlink="#5555ff"> +<table border=0 width=100%> +<tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +<h1>ao_default_driver_id</h1> + +<p><i>declared in "ao/ao.h";</i></p> + +<p>Returns the ID number of the default live output driver. +If the <a href="ao_conf.html">configuration files</a> specify a +default driver, its ID is returned, otherwise the library tries to +pick a live output driver that will work on the host platform. + +<br><br> +<table border=0 color=black cellspacing=0 cellpadding=7> +<tr bgcolor=#cccccc> + <td> +<pre><b> +int ao_default_driver_id(); +</b></pre> + </td> +</tr> +</table> + +<h3>Return Values</h3> +<blockquote> +<li>a non-negative value is the ID number of the default driver.</li> + +<li>-1 indicates failure to find a usable audio output device.</li> +</blockquote> +<p> + +<h3>Notes</h3> +<p>If no default device is available, you may still use the null device +to test your application.</p> + +<br><br> +<hr noshade> +<table border=0 width=100%> +<tr valign=top> +<td><p class=tiny>copyright © 2001 Stan Seibert</p></td> +<td align=right><p class=tiny><a href="http://www.xiph.org/">xiph.org</a><br><a href="mailto:indigo@aztec.asu.edu">indigo@aztec.asu.edu</a></p></td> +</tr><tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +</body> + +</html> diff --git a/doc/ao_device.html b/doc/ao_device.html new file mode 100644 index 0000000..3f3806b --- /dev/null +++ b/doc/ao_device.html @@ -0,0 +1,88 @@ +<html> + +<head> +<title>libao - datatype - ao_device</title> +<link rel=stylesheet href="style.css" type="text/css"> +</head> + +<body bgcolor=white text=black link="#5555ff" alink="#5555ff" vlink="#5555ff"> +<table border=0 width=100%> +<tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +<h1>ao_device</h1> + +<p><i>declared in "ao/ao.h";</i></p> + +<p>This structure holds all of the data for an open device. + +<br><br> +<table border=0 width=100% color=black cellspacing=0 cellpadding=7> +<tr bgcolor=#cccccc> + <td> +<pre><b>typedef struct { + 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;</b></pre> + </td> +</tr> +</table> + +<h3>Relevant Struct Members</h3> +<dl> +<dt><i>type</i></dt> +<dd>The output type of the driver: +<ul> +<li>AO_TYPE_LIVE - Live output.</li> +<li>AO_TYPE_FILE - File output.</li> +</ul> +</dd> +<dt><i>driver_id</i></dt> +<dd>The ID number for the driver used with this device.</dd> +<dt><i>funcs</i></dt> +<dd>Function table for the driver associated with this device.</dd> +<dt><i>client_byte_format</i></dt> +<dd>The byte format (use constants from +<a href="ao_sample_format.html">ao_sample_format</a>) of samples provided by +the client to <a href="ao_sample_format.html">ao_play()</a>. +</dd> +<dt><i>machine_byte_format</i></dt> +<dd>The native byte format of the computer. Will be either +<tt>AO_FMT_BIG</tt> or <tt>AO_FMT_LITTLE</tt>. +</dd> +<dt><i>driver_byte_format</i></dt> +<dd>The byte format of samples requested by +the driver. +</dd> +<dt><i>swap_buffer</i></dt> +<dd>Scratch buffer used to swap the byte order of samples. Only allocated +if <tt>client_byte_format</tt> and <tt>driver_byte_format</tt> correspond to +different byte orders, otherwise set to NULL</dd> +</dl> + +<br><br> +<hr noshade> +<table border=0 width=100%> +<tr valign=top> +<td><p class=tiny>copyright © 2001 Stan Seibert</p></td> +<td align=right><p class=tiny><a href="http://www.xiph.org/">xiph.org</a><br><a href="mailto:indigo@aztec.asu.edu">indigo@aztec.asu.edu</a></p></td> +</tr><tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +</body> + +</html> diff --git a/doc/ao_driver_id.html b/doc/ao_driver_id.html new file mode 100644 index 0000000..703e2a7 --- /dev/null +++ b/doc/ao_driver_id.html @@ -0,0 +1,63 @@ +<html> + +<head> +<title>libao - function - ao_driver_id</title> +<link rel=stylesheet href="style.css" type="text/css"> +</head> + +<body bgcolor=white text=black link="#5555ff" alink="#5555ff" vlink="#5555ff"> +<table border=0 width=100%> +<tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +<h1>ao_driver_id</h1> + +<p><i>declared in "ao/ao.h";</i></p> + +<p>Looks up the ID number for a driver based upon its short name. The +ID number is need to open the driver or get info on it. + +<br><br> +<table border=0 color=black cellspacing=0 cellpadding=7> +<tr bgcolor=#cccccc> + <td> +<pre><b> +int ao_driver_id(char *short_name); +</b></pre> + </td> +</tr> +</table> + +<h3>Parameters</h3> +<dl> +<dt><i>short_name</i></dt> +<dd>The short name of the driver. See the <a href="drivers.html">list of +drivers</a> for valid short names.</dd> +</dl> + +<h3>Return Values</h3> +<blockquote> +<li>a non-negative value is the ID number of the driver.</li> + +<li>-1 indicates failure. No driver by that name exists.</li> +</blockquote> +<p> + +<br><br> +<hr noshade> +<table border=0 width=100%> +<tr valign=top> +<td><p class=tiny>copyright © 2001 Stan Seibert</p></td> +<td align=right><p class=tiny><a href="http://www.xiph.org/">xiph.org</a><br><a href="mailto:indigo@aztec.asu.edu">indigo@aztec.asu.edu</a></p></td> +</tr><tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +</body> + +</html> diff --git a/doc/ao_driver_info.html b/doc/ao_driver_info.html new file mode 100644 index 0000000..6cad651 --- /dev/null +++ b/doc/ao_driver_info.html @@ -0,0 +1,66 @@ +<html> + +<head> +<title>libao - function - ao_driver_info</title> +<link rel=stylesheet href="style.css" type="text/css"> +</head> + +<body bgcolor=white text=black link="#5555ff" alink="#5555ff" vlink="#5555ff"> +<table border=0 width=100%> +<tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +<h1>ao_driver_info</h1> + +<p><i>declared in "ao/ao.h";</i></p> + +<p>Get information about a particular driver. + +<br><br> +<table border=0 color=black cellspacing=0 cellpadding=7> +<tr bgcolor=#cccccc> + <td> +<pre><b> +<a href="ao_info.html">ao_info</a>* ao_driver_info(int driver_id); +</b></pre> + </td> +</tr> +</table> + +<h3>Parameters</h3> +<dl> +<dt><i>driver_id</i></dt> +<dd>The ID number of the driver as returned by either +<a href="ao_driver_id.html">ao_driver_id()</a> or +<a href="ao_default_driver_id.html">ao_default_driver_id()</a>.</dd> +</dl> + +<h3>Return Values</h3> +<blockquote> +<li> +non-NULL pointer inicates success. It points to a static info structure that +should not be modified under any circumstances.</li> + +<li>NULL indicates failure because <tt>driver_id</tt> does not correspond to +an actual driver</li> +</blockquote> +<p> + +<br><br> +<hr noshade> +<table border=0 width=100%> +<tr valign=top> +<td><p class=tiny>copyright © 2001 Stan Seibert</p></td> +<td align=right><p class=tiny><a href="http://www.xiph.org/">xiph.org</a><br><a href="mailto:indigo@aztec.asu.edu">indigo@aztec.asu.edu</a></p></td> +</tr><tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +</body> + +</html> diff --git a/doc/ao_driver_info_list.html b/doc/ao_driver_info_list.html new file mode 100644 index 0000000..c1aa042 --- /dev/null +++ b/doc/ao_driver_info_list.html @@ -0,0 +1,62 @@ +<html> + +<head> +<title>libao - function - ao_driver_info_list</title> +<link rel=stylesheet href="style.css" type="text/css"> +</head> + +<body bgcolor=white text=black link="#5555ff" alink="#5555ff" vlink="#5555ff"> +<table border=0 width=100%> +<tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +<h1>ao_driver_info_list</h1> + +<p><i>declared in "ao/ao.h";</i></p> + +<p>Get a list of the <a href="ao_info.html">ao_info</a> structures +for all of the available drivers. ao_driver_info_list() passes back +the number of drivers through the <tt>driver_count</tt> pointer. + +<br><br> +<table border=0 color=black cellspacing=0 cellpadding=7> +<tr bgcolor=#cccccc> + <td> +<pre><b> +<a href="ao_info.html">ao_info</a>** ao_driver_info_list(int *driver_count); +</b></pre> + </td> +</tr> +</table> + +<h3>Parameters</h3> +<dl> +<dt><i>driver_count</i></dt> +<dd>Pointer to an integer that will contain the number of drivers.</dd> +</dl> + +<h3>Return Values</h3> +<blockquote> +<li>An array of driver info structures with <tt>*driver_count</tt> +elements.</li> +</blockquote> +<p> + +<br><br> +<hr noshade> +<table border=0 width=100%> +<tr valign=top> +<td><p class=tiny>copyright © 2001 Stan Seibert</p></td> +<td align=right><p class=tiny><a href="http://www.xiph.org/">xiph.org</a><br><a href="mailto:indigo@aztec.asu.edu">indigo@aztec.asu.edu</a></p></td> +</tr><tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +</body> + +</html> diff --git a/doc/ao_example.c b/doc/ao_example.c new file mode 100644 index 0000000..f539782 --- /dev/null +++ b/doc/ao_example.c @@ -0,0 +1,83 @@ +/* + * + * ao_example.c + * + * Written by Stan Seibert - July 2001 + * + * Legal Terms: + * + * This source file is released into the public domain. It is + * distributed without any warranty; without even the implied + * warranty * of merchantability or fitness for a particular + * purpose. + * + * Function: + * + * This program opens the default driver and plays a 440 Hz tone for + * one second. + * + * Compilation command line (for Linux systems): + * + * gcc -lao -ldl -lm -o ao_example ao_example.c + * + */ + +#include <stdio.h> +#include <ao/ao.h> +#include <math.h> + +#define BUF_SIZE 4096 + +int main(int argc, char **argv) +{ + ao_device *device; + ao_sample_format format; + int default_driver; + char *buffer; + int buf_size; + int sample; + float freq = 440.0; + int i; + + /* -- Initialize -- */ + + fprintf(stderr, "libao example program\n"); + + ao_initialize(); + + /* -- Setup for default driver -- */ + + default_driver = ao_default_driver_id(); + + format.bits = 16; + format.channels = 2; + format.rate = 44100; + format.byte_format = AO_FMT_LITTLE; + + /* -- Open driver -- */ + device = ao_open_live(default_driver, &format, NULL /* no options */); + if (device == NULL) { + fprintf(stderr, "Error opening device.\n"); + return 1; + } + + /* -- Play some stuff -- */ + buf_size = format.bits/8 * format.channels * format.rate; + buffer = calloc(buf_size, + sizeof(char)); + + for (i = 0; i < format.rate; i++) { + sample = 0.75 * 32768.0 * + sin(2 * M_PI * freq * ((float) i/format.rate)); + + /* Put the same stuff in left and right channel */ + buffer[4*i] = buffer[4*i+2] = sample & 0xff; + buffer[4*i+1] = buffer[4*i+3] = (sample >> 8) & 0xff; + } + ao_play(device, buffer, buf_size); + + /* -- Close and shutdown -- */ + ao_close(device); + + ao_shutdown(); +} diff --git a/doc/ao_free_options.html b/doc/ao_free_options.html new file mode 100644 index 0000000..d342f29 --- /dev/null +++ b/doc/ao_free_options.html @@ -0,0 +1,55 @@ +<html> + +<head> +<title>libao - function - ao_free_options</title> +<link rel=stylesheet href="style.css" type="text/css"> +</head> + +<body bgcolor=white text=black link="#5555ff" alink="#5555ff" vlink="#5555ff"> +<table border=0 width=100%> +<tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +<h1>ao_free_options</h1> + +<p><i>declared in "ao/ao.h";</i></p> + +<p>Free all of the memory allocated to an option list, including the key +and value strings. + +<br><br> +<table border=0 color=black cellspacing=0 cellpadding=7> +<tr bgcolor=#cccccc> + <td> +<pre><b> +void ao_free_options(<a href="ao_option.html">ao_option</a> *options); +</b></pre> + </td> +</tr> +</table> + +<h3>Parameters</h3> +<dl> +<dt><i>options</i></dt> +<dd>Pointer to the head of the option list. If NULL is passed, the +function does nothing.</dd> +</dl> + +<br><br> +<hr noshade> +<table border=0 width=100%> +<tr valign=top> +<td><p class=tiny>copyright © 2001 Stan Seibert</p></td> +<td align=right><p class=tiny><a href="http://www.xiph.org/">xiph.org</a><br><a href="mailto:indigo@aztec.asu.edu">indigo@aztec.asu.edu</a></p></td> +</tr><tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +</body> + +</html> diff --git a/doc/ao_info.html b/doc/ao_info.html new file mode 100644 index 0000000..2ea0311 --- /dev/null +++ b/doc/ao_info.html @@ -0,0 +1,93 @@ +<html> + +<head> +<title>libao - datatype - ao_info</title> +<link rel=stylesheet href="style.css" type="text/css"> +</head> + +<body bgcolor=white text=black link="#5555ff" alink="#5555ff" vlink="#5555ff"> +<table border=0 width=100%> +<tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +<h1>ao_info</h1> + +<p><i>declared in "ao/ao.h";</i></p> + +<p>This structure describes the attributes of an output driver. + +<br><br> +<table border=0 width=100% color=black cellspacing=0 cellpadding=7> +<tr bgcolor=#cccccc> + <td> +<pre><b>typedef struct { + int type; /* live output or file output? */ + char *name; /* full name of driver */ + char *short_name; /* short name of driver */ + char *comment; /* driver comment */ + int preferred_byte_format; + int priority; + char **options; + int option_count; +} ao_info;</b></pre> + </td> +</tr> +</table> + +<h3>Relevant Struct Members</h3> +<dl> +<dt><i>type</i></dt> +<dd>The output type of the driver: +<ul> +<li>AO_TYPE_LIVE - Live output.</li> +<li>AO_TYPE_FILE - File output.</li> +</ul> +</dd> +<dt><i>name</i></dt> +<dd>A longer name for the driver which may contain whitespace, but no +newlines. It is useful for telling users what output driver is in use.</dd> +<dt><i>short_name</i></dt> +<dd>A short identifier for the driver. The short name contains only +alphanumeric characters, and no whitespace. It is used to look up the driver +ID number using <a href="ao_driver_id.html">ao_driver_id()</a>.</dd> +<dt><i>preferred_byte_format</i></dt> +<dd>Specifies the preferred ordering of the sample bytes. Using the driver +with this byte format usually results in slightly less memory usage and +slightly less CPU usage because a swap buffer will not be needed. +See +<a href="ao_sample_format.html">ao_sample_format</a> for a list of +allowed values. +</dd> +<dt><i>priority</i></dt> +<dd>A positive integer ranking how likely it is for this driver to be +the default. The default driver will be a functioning driver with +highest priority. See the <a href="drivers.html">drivers document</a> +for more explanation.</dd> +<dt><i>comment</i></dt> +<dd>Pointer to a driver comment string (possibly <tt>NULL</tt>). It may +contain newlines.</dd> +<dt><i>options</i></dt> +<dd>An array of strings which list the option keys accepted by this +driver.</dd> +<dt><i>option_count</i></dt> +<dd>Number of strings in <tt>options</tt> array.</dd> +</dl> + +<br><br> +<hr noshade> +<table border=0 width=100%> +<tr valign=top> +<td><p class=tiny>copyright © 2001 Stan Seibert</p></td> +<td align=right><p class=tiny><a href="http://www.xiph.org/">xiph.org</a><br><a href="mailto:indigo@aztec.asu.edu">indigo@aztec.asu.edu</a></p></td> +</tr><tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +</body> + +</html> diff --git a/doc/ao_initialize.html b/doc/ao_initialize.html new file mode 100644 index 0000000..ef4b596 --- /dev/null +++ b/doc/ao_initialize.html @@ -0,0 +1,58 @@ +<html> + +<head> +<title>libao - function - ao_initialize</title> +<link rel=stylesheet href="style.css" type="text/css"> +</head> + +<body bgcolor=white text=black link="#5555ff" alink="#5555ff" vlink="#5555ff"> +<table border=0 width=100%> +<tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +<h1>ao_initialize</h1> + +<p><i>declared in "ao/ao.h";</i></p> + +<p>This function initializes the internal libao data structures and +loads all of the available plugins. The system and user <a +href="config.html">configuration files</a> are also read at this time +if available. The library must be initialized before any other libao +functions can be used. + +<br><br> +<table border=0 color=black cellspacing=0 cellpadding=7> +<tr bgcolor=#cccccc> + <td> +<pre><b> +void ao_initialize(); +</b></pre> + </td> +</tr> +</table> + +<h3>Notes</h3> + +<p>Do not invoke this function more than once before calling <a +href="ao_shutdown.html">ao_shutdown()</a>. If you want to reload the +configuration files without restarting your program, first call +ao_shutdown(), then call ao_initialize() again. + +<br><br> +<hr noshade> +<table border=0 width=100%> +<tr valign=top> +<td><p class=tiny>copyright © 2001 Stan Seibert</p></td> +<td align=right><p class=tiny><a href="http://www.xiph.org/">xiph.org</a><br><a href="mailto:indigo@aztec.asu.edu">indigo@aztec.asu.edu</a></p></td> +</tr><tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +</body> + +</html> diff --git a/doc/ao_open_file.html b/doc/ao_open_file.html new file mode 100644 index 0000000..c85fd08 --- /dev/null +++ b/doc/ao_open_file.html @@ -0,0 +1,99 @@ +<html> + +<head> +<title>libao - function - ao_open_file</title> +<link rel=stylesheet href="style.css" type="text/css"> +</head> + +<body bgcolor=white text=black link="#5555ff" alink="#5555ff" vlink="#5555ff"> +<table border=0 width=100%> +<tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +<h1>ao_open_file</h1> + +<p><i>declared in "ao/ao.h";</i></p> + +<p>Open a file for audio output. The file format is determined by the +audio driver used. + +<br><br> +<table border=0 color=black cellspacing=0 cellpadding=7> +<tr bgcolor=#cccccc> + <td> +<pre><b> +<a href="ao_device.html">ao_device</a>* ao_open_file(int driver_id, const char *filename, int overwrite, + <a href="ao_sample_format.html">ao_sample_format</a> *format, <a href="ao_option.html">ao_option</a> *options); +</b></pre> + </td> +</tr> +</table> + +<h3>Parameters</h3> +<dl> +<dt><i>driver_id</i></dt> +<dd>The ID number of the driver as returned by +<a href="ao_driver_id.html">ao_driver_id()</a>.</dd> +<dt><i>filename</i></dt> +<dd>Name of the file in which to store the audio. The special filename "-" corresponds to <tt>stdout</tt>.</dd> +<dt><i>overwrite</i></dt> +<dd>If non-zero, the file is automatically overwritten. If zero, then a +preexisting file will cause the function to report a failure.</dd> +<dt><i>format</i></dt> +<dd>Pointer to a struct describing the sample format. The caller retains ownership of this structure.</dd> +<dt><i>options</i></dt> +<dd>A linked list of options to be passed to the driver or NULL if no options +are needed. Unsupported options are ignored.</dd> +</dl> + +<h3>Return Values</h3> +<blockquote> +<li> +non-NULL pointer inicates success. This pointer must be passed in subsequent +calls to <a href="ao_play.html">ao_play()</a> and +<a href="ao_close.html">ao_close()</a>.</li> + +<li>NULL indicates failure. <tt>errno</tt> will contain the specific cause of the failure:</li> +<ul> +<li>AO_ENODRIVER - No driver corresponds to <tt>driver_id</tt>.</li> +<li>AO_ENOTFILE - This driver is not a file output driver.</li> +<li>AO_EBADOPTION - A valid option key has an invalid value.</li> +<li>AO_EOPENFILE - Cannot open the file.</li> +<li>AO_EFILEEXISTS - The file already exists. +(Only if <tt>overwrite == 0</tt>)</li> +<li>AO_EFAIL - Any other cause of failure.</li> +</ul> +</blockquote> +<p> + + +<h3>Notes</h3> + +<p>Live output drivers cannot be used with this function. Use <a +href="ao_open_live.html">ao_open_live()</a> instead. Some file +formats (notably .WAV) cannot be correctly written to non-seekable +files (like <tt>stdin</tt>). + +<p>When passed to <a href="ao_open_file.html">ao_open_file()</a>, the +<tt>byte_format</tt> member of an ao_sample_format struct does not +specify the byte format that will be used in the file <i>output</i>, +just the input sample format. + +<br><br> +<hr noshade> +<table border=0 width=100%> +<tr valign=top> +<td><p class=tiny>copyright © 2001 Stan Seibert</p></td> +<td align=right><p class=tiny><a href="http://www.xiph.org/">xiph.org</a><br><a href="mailto:indigo@aztec.asu.edu">indigo@aztec.asu.edu</a></p></td> +</tr><tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +</body> + +</html> diff --git a/doc/ao_open_live.html b/doc/ao_open_live.html new file mode 100644 index 0000000..bcfaac0 --- /dev/null +++ b/doc/ao_open_live.html @@ -0,0 +1,85 @@ +<html> + +<head> +<title>libao - function - ao_open_live</title> +<link rel=stylesheet href="style.css" type="text/css"> +</head> + +<body bgcolor=white text=black link="#5555ff" alink="#5555ff" vlink="#5555ff"> +<table border=0 width=100%> +<tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +<h1>ao_open_live</h1> + +<p><i>declared in "ao/ao.h";</i></p> + +<p>Open a live playback audio device for output. + +<br><br> +<table border=0 color=black cellspacing=0 cellpadding=7> +<tr bgcolor=#cccccc> + <td> +<pre><b> +<a href="ao_device.html">ao_device</a>* ao_open_live(int driver_id, <a href="ao_sample_format.html">ao_sample_format</a> *format, <a href="ao_option.html">ao_option</a> *options); +</b></pre> + </td> +</tr> +</table> + +<h3>Parameters</h3> +<dl> +<dt><i>driver_id</i></dt> +<dd>The ID number of the driver as returned by either +<a href="ao_driver_id.html">ao_driver_id()</a> or +<a href="ao_default_driver_id.html">ao_default_driver_id()</a>.</dd> +<dt><i>format</i></dt> +<dd>Pointer to a struct describing the sample format. The caller retains ownership of this structure.</dd> +<dt><i>options</i></dt> +<dd>A linked list of options to be passed to the driver or NULL if no options +are needed. Unsupported options are ignored.</dd> +</dl> + +<h3>Return Values</h3> +<blockquote> +<li> +non-NULL pointer inicates success. This pointer must be passed in subsequent +calls to <a href="ao_play.html">ao_play()</a> and +<a href="ao_close.html">ao_close()</a>.</li> + +<li>NULL indicates failure. <tt>errno</tt> will contain the specific cause of the failure:</li> +<ul> +<li>AO_ENODRIVER - No driver corresponds to <tt>driver_id</tt>.</li> +<li>AO_ENOTLIVE - This driver is not a live output device.</li> +<li>AO_EBADOPTION - A valid option key has an invalid value.</li> +<li>AO_EOPENDEVICE - Cannot open the device (for example, if /dev/dsp cannot be +opened for writing).</li> +<li>AO_EFAIL - Any other cause of failure.</li> +</ul> +</blockquote> +<p> + + +<h3>Notes</h3> + +<p>File output drivers cannot be used with this function. Use <a +href="ao_open_file.html">ao_open_file()</a> instead. + +<br><br> +<hr noshade> +<table border=0 width=100%> +<tr valign=top> +<td><p class=tiny>copyright © 2001 Stan Seibert</p></td> +<td align=right><p class=tiny><a href="http://www.xiph.org/">xiph.org</a><br><a href="mailto:indigo@aztec.asu.edu">indigo@aztec.asu.edu</a></p></td> +</tr><tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +</body> + +</html> diff --git a/doc/ao_option.html b/doc/ao_option.html new file mode 100644 index 0000000..3b92104 --- /dev/null +++ b/doc/ao_option.html @@ -0,0 +1,59 @@ +<html> + +<head> +<title>libao - datatype - ao_option</title> +<link rel=stylesheet href="style.css" type="text/css"> +</head> + +<body bgcolor=white text=black link="#5555ff" alink="#5555ff" vlink="#5555ff"> +<table border=0 width=100%> +<tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +<h1>ao_option</h1> + +<p><i>declared in "ao/ao.h";</i></p> + +<p>A linked list structure to hold option key/value pairs as standard +null-terminated C strings. It is used by <a +href="ao_open_live.html">ao_open_live()</a> and <a +href="ao_open_file.html">ao_open_file()</a>. + +<br><br> +<table border=0 width=100% color=black cellspacing=0 cellpadding=7> +<tr bgcolor=#cccccc> + <td> +<pre><b>typedef struct { + char *key; + char *value; + struct ao_option *next; /* number of audio channels */ +} ao_option;</b></pre> + </td> +</tr> +</table> + +<h3>Relevant Struct Members</h3> +<dl> +<dt><i>next</i></dt> +<dd>Pointer to the next option in the list. Set to <tt>NULL</tt> to mark the end of +the list.</dd> +</dl> + +<br><br> +<hr noshade> +<table border=0 width=100%> +<tr valign=top> +<td><p class=tiny>copyright © 2001 Stan Seibert</p></td> +<td align=right><p class=tiny><a href="http://www.xiph.org/">xiph.org</a><br><a href="mailto:indigo@aztec.asu.edu">indigo@aztec.asu.edu</a></p></td> +</tr><tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +</body> + +</html> diff --git a/doc/ao_play.html b/doc/ao_play.html new file mode 100644 index 0000000..0e55e70 --- /dev/null +++ b/doc/ao_play.html @@ -0,0 +1,67 @@ +<html> + +<head> +<title>libao - function - ao_play</title> +<link rel=stylesheet href="style.css" type="text/css"> +</head> + +<body bgcolor=white text=black link="#5555ff" alink="#5555ff" vlink="#5555ff"> +<table border=0 width=100%> +<tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +<h1>ao_play</h1> + +<p><i>declared in "ao/ao.h";</i></p> + +<p>Play a block of audio data to an open device. Samples are interleaved by +channels (Time 1, Channel 1; Time 1, Channel 2; Time 2, Channel 1; +etc.) in the memory buffer. + +<br><br> +<table border=0 color=black cellspacing=0 cellpadding=7> +<tr bgcolor=#cccccc> + <td> +<pre><b> +int ao_open(<a href="ao_device.html">ao_device</a> *device, void *output_samples, uint_32 num_bytes); +</b></pre> + </td> +</tr> +</table> + +<h3>Parameters</h3> +<dl> +<dt><i>device</i></dt> +<dd>Pointer to device structure as returned by <a href="ao_open_live.html">ao_open_live()</a> or <a href="ao_open_file.html">ao_open_file()</a></dd> +<dt><i>output_samples</i></dt> +<dd>Memory buffer containing audio data.</dd> +<dt><i>num_bytes</i></dt> +<dd>Number of bytes of audio data in the memory buffer.</dd> +</dl> + +<h3>Return Values</h3> +<blockquote> +<li>non-zero value indicates success.</li> + +<li>0 indicates failure. The device should be closed.</li> +</blockquote> +<p> + +<br><br> +<hr noshade> +<table border=0 width=100%> +<tr valign=top> +<td><p class=tiny>copyright © 2001 Stan Seibert</p></td> +<td align=right><p class=tiny><a href="http://www.xiph.org/">xiph.org</a><br><a href="mailto:indigo@aztec.asu.edu">indigo@aztec.asu.edu</a></p></td> +</tr><tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +</body> + +</html> diff --git a/doc/ao_plugin_close.html b/doc/ao_plugin_close.html new file mode 100644 index 0000000..4545b37 --- /dev/null +++ b/doc/ao_plugin_close.html @@ -0,0 +1,61 @@ +<html> + +<head> +<title>libao - function - ao_plugin_close</title> +<link rel=stylesheet href="style.css" type="text/css"> +</head> + +<body bgcolor=white text=black link="#5555ff" alink="#5555ff" vlink="#5555ff"> +<table border=0 width=100%> +<tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +<h1>ao_plugin_close</h1> + +<p><i>declared in "ao/plugin.h";</i></p> + +<p>Close the device. Private data structures are not deallocated yet. + +<br><br> +<table border=0 color=black cellspacing=0 cellpadding=7> +<tr bgcolor=#cccccc> + <td> +<pre><b> +int ao_plugin_close(<a href="ao_device.html">ao_device</a> *device); +</b></pre> + </td> +</tr> +</table> + +<h3>Parameters</h3> +<dl> +<dt><i>device</i></dt> +<dd>Pointer to pre-allocated device structure.</dd> +</dl> + +<h3>Return Values</h3> +<blockquote> +<li>1 indicates remaining data written correctly and device +closed.</li> +<li>0 indicates an error while the device was being closed. If this +device was writing to a file, the file may be corrupted.</li> +</blockquote> + +<br><br> +<hr noshade> +<table border=0 width=100%> +<tr valign=top> +<td><p class=tiny>copyright © 2001 Stan Seibert</p></td> +<td align=right><p class=tiny><a href="http://www.xiph.org/">xiph.org</a><br><a href="mailto:indigo@aztec.asu.edu">indigo@aztec.asu.edu</a></p></td> +</tr><tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +</body> + +</html> diff --git a/doc/ao_plugin_device_clear.html b/doc/ao_plugin_device_clear.html new file mode 100644 index 0000000..262948a --- /dev/null +++ b/doc/ao_plugin_device_clear.html @@ -0,0 +1,53 @@ +<html> + +<head> +<title>libao - function - ao_plugin_device_clear</title> +<link rel=stylesheet href="style.css" type="text/css"> +</head> + +<body bgcolor=white text=black link="#5555ff" alink="#5555ff" vlink="#5555ff"> +<table border=0 width=100%> +<tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +<h1>ao_plugin_device_clear</h1> + +<p><i>declared in "ao/plugin.h";</i></p> + +<p>Deallocate the private device data structures. + +<br><br> +<table border=0 color=black cellspacing=0 cellpadding=7> +<tr bgcolor=#cccccc> + <td> +<pre><b> +void ao_plugin_device_clear(<a href="ao_device.html">ao_device</a> *device); +</b></pre> + </td> +</tr> +</table> + +<h3>Parameters</h3> +<dl> +<dt><i>device</i></dt> +<dd>Pointer to pre-allocated device structure.</dd> +</dl> + +<br><br> +<hr noshade> +<table border=0 width=100%> +<tr valign=top> +<td><p class=tiny>copyright © 2001 Stan Seibert</p></td> +<td align=right><p class=tiny><a href="http://www.xiph.org/">xiph.org</a><br><a href="mailto:indigo@aztec.asu.edu">indigo@aztec.asu.edu</a></p></td> +</tr><tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +</body> + +</html> diff --git a/doc/ao_plugin_device_init.html b/doc/ao_plugin_device_init.html new file mode 100644 index 0000000..d251c60 --- /dev/null +++ b/doc/ao_plugin_device_init.html @@ -0,0 +1,67 @@ +<html> + +<head> +<title>libao - function - ao_plugin_device_init</title> +<link rel=stylesheet href="style.css" type="text/css"> +</head> + +<body bgcolor=white text=black link="#5555ff" alink="#5555ff" vlink="#5555ff"> +<table border=0 width=100%> +<tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +<h1>ao_plugin_device_init</h1> + +<p><i>declared in "ao/plugin.h";</i></p> + +<p>Initialize the private device data structures. Memory should be +allocated, and default values set if necessary, but devices should not +be opened until <a href="ao_plugin_open.html">ao_plugin_open()</a> is +called. + +<br><br> +<table border=0 color=black cellspacing=0 cellpadding=7> +<tr bgcolor=#cccccc> + <td> +<pre><b> +int ao_plugin_device_init(<a href="ao_device.html">ao_device</a> *device); +</b></pre> + </td> +</tr> +</table> + +<h3>Parameters</h3> +<dl> +<dt><i>device</i></dt> +<dd>Pointer to pre-allocated device structure. The driver should +store the address of its private memory in <tt>device->internal</tt>.</dd> +</dl> + +<h3>Return Values</h3> +<blockquote> +<li>1 indicates success.</li> + +<li>0 indicates failure, probably due to memory allocation problems. +<a href="ao_plugin_device_clear.html">ao_plugin_device_clear()</a> should be +called to ensure the deallocate of all private data structures.</li> +</blockquote> +<p> + +<br><br> +<hr noshade> +<table border=0 width=100%> +<tr valign=top> +<td><p class=tiny>copyright © 2001 Stan Seibert</p></td> +<td align=right><p class=tiny><a href="http://www.xiph.org/">xiph.org</a><br><a href="mailto:indigo@aztec.asu.edu">indigo@aztec.asu.edu</a></p></td> +</tr><tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +</body> + +</html> diff --git a/doc/ao_plugin_driver_info.html b/doc/ao_plugin_driver_info.html new file mode 100644 index 0000000..782b4e6 --- /dev/null +++ b/doc/ao_plugin_driver_info.html @@ -0,0 +1,54 @@ +<html> + +<head> +<title>libao - function - ao_plugin_driver_info</title> +<link rel=stylesheet href="style.css" type="text/css"> +</head> + +<body bgcolor=white text=black link="#5555ff" alink="#5555ff" vlink="#5555ff"> +<table border=0 width=100%> +<tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +<h1>ao_plugin_driver_info</h1> + +<p><i>declared in "ao/plugin.h";</i></p> + +<p>Get the driver information structure. + +<br><br> +<table border=0 color=black cellspacing=0 cellpadding=7> +<tr bgcolor=#cccccc> + <td> +<pre><b> +<a href="ao_info.html">ao_info*</a> ao_plugin_driver_info(); +</b></pre> + </td> +</tr> +</table> + +<h3>Return Values</h3> +<blockquote> +<li>Pointer to the driver information structure. This structure should +not be modified. </li> +</blockquote> +<p> + +<br><br> +<hr noshade> +<table border=0 width=100%> +<tr valign=top> +<td><p class=tiny>copyright © 2001 Stan Seibert</p></td> +<td align=right><p class=tiny><a href="http://www.xiph.org/">xiph.org</a><br><a href="mailto:indigo@aztec.asu.edu">indigo@aztec.asu.edu</a></p></td> +</tr><tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +</body> + +</html> diff --git a/doc/ao_plugin_open.html b/doc/ao_plugin_open.html new file mode 100644 index 0000000..3d58c2c --- /dev/null +++ b/doc/ao_plugin_open.html @@ -0,0 +1,71 @@ +<html> + +<head> +<title>libao - function - ao_plugin_open</title> +<link rel=stylesheet href="style.css" type="text/css"> +</head> + +<body bgcolor=white text=black link="#5555ff" alink="#5555ff" vlink="#5555ff"> +<table border=0 width=100%> +<tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +<h1>ao_plugin_open</h1> + +<p><i>declared in "ao/plugin.h";</i></p> + +<p>Open the device for playback. All of the device options will have +already been set by previous calls to <a +href="ao_plugin_set_option.html">ao_plugin_set_option()</a>. If this is a +file output driver, the file itself will have be already opened and a +pointer to a <tt>FILE</tt> structure stored in <tt>device->file</tt>. + +<br><br> +<table border=0 color=black cellspacing=0 cellpadding=7> +<tr bgcolor=#cccccc> + <td> +<pre><b> +int ao_plugin_open(<a href="ao_device.html">ao_device</a> *device, <a href="ao_sample_format.html">ao_sample_format</a> *format); +</b></pre> + </td> +</tr> +</table> + +<h3>Parameters</h3> +<dl> +<dt><i>device</i></dt> +<dd>Pointer to pre-allocated device structure. The plugin should +set its desired byte format in <tt>device->driver_byte_format</tt>.</dd> +<dt><i>format</i></dt> +<dd>Output device sample format. <tt>format->byte_format</tt> should be +ignored as it is relevant only to the library core.</dd> +</dl> + +<h3>Return Values</h3> +<blockquote> +<li>1 indicates success.</li> + +<li>0 indicates failure to open the device. +<a href="ao_plugin_device_clear.html">ao_plugin_device_clear()</a> should be +called to ensure the deallocate of all private data structures.</li> +</blockquote> +<p> + +<br><br> +<hr noshade> +<table border=0 width=100%> +<tr valign=top> +<td><p class=tiny>copyright © 2001 Stan Seibert</p></td> +<td align=right><p class=tiny><a href="http://www.xiph.org/">xiph.org</a><br><a href="mailto:indigo@aztec.asu.edu">indigo@aztec.asu.edu</a></p></td> +</tr><tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +</body> + +</html> diff --git a/doc/ao_plugin_play.html b/doc/ao_plugin_play.html new file mode 100644 index 0000000..7318449 --- /dev/null +++ b/doc/ao_plugin_play.html @@ -0,0 +1,70 @@ +<html> + +<head> +<title>libao - function - ao_plugin_play</title> +<link rel=stylesheet href="style.css" type="text/css"> +</head> + +<body bgcolor=white text=black link="#5555ff" alink="#5555ff" vlink="#5555ff"> +<table border=0 width=100%> +<tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +<h1>ao_plugin_play</h1> + +<p><i>declared in "ao/plugin.h";</i></p> + +<p>Write samples to the device. Channels are interleaved, and samples +have the byte order requested by the plugin +(<tt>device->driver_byte_format</tt>). + +<br><br> +<table border=0 color=black cellspacing=0 cellpadding=7> +<tr bgcolor=#cccccc> + <td> +<pre><b> +int ao_plugin_play(<a href="ao_device.html">ao_device</a> *device, void *output_samples, uint_32 num_bytes); +</b></pre> + </td> +</tr> +</table> + +<h3>Parameters</h3> +<dl> +<dt><i>device</i></dt> +<dd>Pointer to pre-allocated device structure. The plugin should +set its desired byte format in <tt>device->driver_byte_format</tt>.</dd> +<dt><i>output_samples</i></dt> +<dd>Pointer to audio sample buffer.</dd> +<dt><i>num_bytes</i></dt> +<dd>Number of bytes in buffer.</dd> +</dl> + +<h3>Return Values</h3> +<blockquote> +<li>1 indicates success.</li> + +<li>0 indicates failure to send the samples to the device. +<a href="ao_plugin_close.html">ao_plugin_close()</a> should be +called.</li> +</blockquote> +<p> + +<br><br> +<hr noshade> +<table border=0 width=100%> +<tr valign=top> +<td><p class=tiny>copyright © 2001 Stan Seibert</p></td> +<td align=right><p class=tiny><a href="http://www.xiph.org/">xiph.org</a><br><a href="mailto:indigo@aztec.asu.edu">indigo@aztec.asu.edu</a></p></td> +</tr><tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +</body> + +</html> diff --git a/doc/ao_plugin_set_option.html b/doc/ao_plugin_set_option.html new file mode 100644 index 0000000..cd7474c --- /dev/null +++ b/doc/ao_plugin_set_option.html @@ -0,0 +1,73 @@ +<html> + +<head> +<title>libao - function - ao_plugin_set_option</title> +<link rel=stylesheet href="style.css" type="text/css"> +</head> + +<body bgcolor=white text=black link="#5555ff" alink="#5555ff" vlink="#5555ff"> +<table border=0 width=100%> +<tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +<h1>ao_plugin_set_option</h1> + +<p><i>declared in "ao/plugin.h";</i></p> + +<p>Set a new option key-value pair for a device. This will only be +called after <a +href="ao_plugin_device_init.html">ao_plugin_device_init()</a> is called. +Unrecognized option keys are silently ignored, but invalid option +values will cause the function to return a failing error code. + +<br><br> +<table border=0 color=black cellspacing=0 cellpadding=7> +<tr bgcolor=#cccccc> + <td> +<pre><b> +int ao_plugin_set_option(<a href="ao_device.html">ao_device</a> *device, const char *key, const char *value); +</b></pre> + </td> +</tr> +</table> + +<h3>Parameters</h3> +<dl> +<dt><i>device</i></dt> +<dd>Pointer to the device structure.</dd> +<dt><i>key</i></dt> +<dd>A string holding the option key. The calling function retains ownership +of this memory.</dd> +<dt><i>value</i></dt> +<dd>A string holding the option value. The calling function retains ownership +of this memory.</dd> +</dl> + +<h3>Return Values</h3> +<blockquote> +<li>1 indicates success.</li> + +<li>0 indicates failure. <a +href="ao_plugin_device_clear.html">ao_plugin_device_clear()</a> should be +called to ensure the deallocate of all private data structures.</li> +</blockquote> +<p> + +<br><br> +<hr noshade> +<table border=0 width=100%> +<tr valign=top> +<td><p class=tiny>copyright © 2001 Stan Seibert</p></td> +<td align=right><p class=tiny><a href="http://www.xiph.org/">xiph.org</a><br><a href="mailto:indigo@aztec.asu.edu">indigo@aztec.asu.edu</a></p></td> +</tr><tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +</body> + +</html> diff --git a/doc/ao_plugin_test.html b/doc/ao_plugin_test.html new file mode 100644 index 0000000..af8b8b5 --- /dev/null +++ b/doc/ao_plugin_test.html @@ -0,0 +1,59 @@ +<html> + +<head> +<title>libao - function - ao_plugin_test</title> +<link rel=stylesheet href="style.css" type="text/css"> +</head> + +<body bgcolor=white text=black link="#5555ff" alink="#5555ff" vlink="#5555ff"> +<table border=0 width=100%> +<tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +<h1>ao_plugin_test</h1> + +<p><i>declared in "ao/plugin.h";</i></p> + +<p>Test if this driver could be used with only the default options. This +function is used by the library core to determine if a driver is a possible +candidate for the default driver. No devices are left open after this +function returns. + +<br><br> +<table border=0 color=black cellspacing=0 cellpadding=7> +<tr bgcolor=#cccccc> + <td> +<pre><b> +int ao_plugin_test(); +</b></pre> + </td> +</tr> +</table> + +<h3>Return Values</h3> +<blockquote> +<li>1 indicates that the driver can be successfully opened with no +options.</li> + +<li>0 indicates that the driver cannot be opened with no options.</li> +</blockquote> +<p> + +<br><br> +<hr noshade> +<table border=0 width=100%> +<tr valign=top> +<td><p class=tiny>copyright © 2001 Stan Seibert</p></td> +<td align=right><p class=tiny><a href="http://www.xiph.org/">xiph.org</a><br><a href="mailto:indigo@aztec.asu.edu">indigo@aztec.asu.edu</a></p></td> +</tr><tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +</body> + +</html> diff --git a/doc/ao_sample_format.html b/doc/ao_sample_format.html new file mode 100644 index 0000000..1152fa0 --- /dev/null +++ b/doc/ao_sample_format.html @@ -0,0 +1,62 @@ +<html> + +<head> +<title>libao - datatype - ao_sample_format</title> +<link rel=stylesheet href="style.css" type="text/css"> +</head> + +<body bgcolor=white text=black link="#5555ff" alink="#5555ff" vlink="#5555ff"> +<table border=0 width=100%> +<tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +<h1>ao_sample_format</h1> + +<p><i>declared in "ao/ao.h";</i></p> + +<p>This structure describes the format of audio samples. + +<br><br> +<table border=0 width=100% color=black cellspacing=0 cellpadding=7> +<tr bgcolor=#cccccc> + <td> +<pre><b>typedef struct { + 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;</b></pre> + </td> +</tr> +</table> + +<h3>Relevant Struct Members</h3> +<dl> +<dt><i>byte_format</i></dt> +<dd>Specifies the ordering of the sample bytes. The value of this member is ignored when samples have only 8 bits. Use the following constants: +<ul> +<li>AO_FMT_LITTLE - Samples are in little-endian order.</li> +<li>AO_FMT_BIG - Samples are in big-endian order.</li> +<li>AO_FMT_NATIVE - Samples are in the native ordering of the computer.</li> +</ul> +</dd> +</dl> + +<br><br> +<hr noshade> +<table border=0 width=100%> +<tr valign=top> +<td><p class=tiny>copyright © 2001 Stan Seibert</p></td> +<td align=right><p class=tiny><a href="http://www.xiph.org/">xiph.org</a><br><a href="mailto:indigo@aztec.asu.edu">indigo@aztec.asu.edu</a></p></td> +</tr><tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +</body> + +</html> diff --git a/doc/ao_shutdown.html b/doc/ao_shutdown.html new file mode 100644 index 0000000..d544b76 --- /dev/null +++ b/doc/ao_shutdown.html @@ -0,0 +1,55 @@ +<html> + +<head> +<title>libao - function - ao_shutdown</title> +<link rel=stylesheet href="style.css" type="text/css"> +</head> + +<body bgcolor=white text=black link="#5555ff" alink="#5555ff" vlink="#5555ff"> +<table border=0 width=100%> +<tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +<h1>ao_shutdown</h1> + +<p><i>declared in "ao/ao.h";</i></p> + +<p>This function unloads all of the plugins and deallocates any +internal data structures the library has created. It should be called +prior to program exit. + +<br><br> +<table border=0 color=black cellspacing=0 cellpadding=7> +<tr bgcolor=#cccccc> + <td> +<pre><b> +void ao_shutdown(); +</b></pre> + </td> +</tr> +</table> + +<h3>Notes</h3> + +<p>Do not invoke this function before closing all of the open devices. +You may call <a href="ao_shutdown.html">ao_initialize()</a> after +calling ao_shutdown(). + +<br><br> +<hr noshade> +<table border=0 width=100%> +<tr valign=top> +<td><p class=tiny>copyright © 2001 Stan Seibert</p></td> +<td align=right><p class=tiny><a href="http://www.xiph.org/">xiph.org</a><br><a href="mailto:indigo@aztec.asu.edu">indigo@aztec.asu.edu</a></p></td> +</tr><tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +</body> + +</html> diff --git a/doc/config.html b/doc/config.html new file mode 100644 index 0000000..72fe37d --- /dev/null +++ b/doc/config.html @@ -0,0 +1,56 @@ +<html> + +<head> +<title>libao - Documentation</title> +<link rel=stylesheet href="style.css" type="text/css"> +</head> + +<body bgcolor=white text=black link="#5555ff" alink="#5555ff" vlink="#5555ff"> +<table border=0 width=100%> +<tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +<h1>libao Configuration Files</h1> +<p> + +When libao is <a href="ao_initialize.html">initialized</a>, it reads +two configuration files: the system-wide configuration in +"/etc/libao.conf" and the user configuration in +"~/.libao". Neither file needs to be present on the system for +libao to load. If both are present, the system configuration file is +read first, followed by the user configuration file. Options set in +the user configuration will take precedence. +<p> + +Options are specified in these files in the form: +<pre> +option=value +</pre> +There can be no extra spaces anywhere on the line. Comment lines begin with a <tt>#</tt> symbol. + +<h2>Options</h2> + +<dl> +<dt><i>default_driver</i></dt> +<dd>Set this equal to the short name of the driver you want the system to use by default. If this is not specified in any of the configuration files, the library will try to guess an appropriate driver to use. +</dd> +</dl> + +<br><br> +<hr noshade> +<table border=0 width=100%> +<tr valign=top> +<td><p class=tiny>copyright © 2001 Stan Seibert</p></td> +<td align=right><p class=tiny><a href="http://www.xiph.org/">xiph.org</a><br><a href="mailto:indigo@aztec.asu.edu">indigo@aztec.asu.edu</a></p></td> +</tr><tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +</body> + +</html> diff --git a/doc/drivers.html b/doc/drivers.html new file mode 100644 index 0000000..f889300 --- /dev/null +++ b/doc/drivers.html @@ -0,0 +1,209 @@ +<html> + +<head> +<title>libao - Documentation</title> +<link rel=stylesheet href="style.css" type="text/css"> +</head> + +<body bgcolor=white text=black link="#5555ff" alink="#5555ff" vlink="#5555ff"> +<table border=0 width=100%> +<tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +<h1>libao Drivers</h1> + +<p> +Libao supports both <i>live</i> output drivers and <i>file</i> output +drivers. Live output drivers send audio data to sound cards and sound +daemons. File output drivers write audio to disk using a particular +file format (such as WAV, AU, etc.). You must invoke the +ao_open_????() function that corresponds to the type of driver you are +using, but otherwise live and file drivers are treated identically in +libao. + +<h2>Live Output Drivers</h2> + +<h3>null</h3> + +Null driver. This is just a test device which does not write the +audio data anywhere. +<p> + +<b>Option keys:</b> None. +<p> + +<hr width="50%"> + +<h3>alsa</h3> + +Advanced Linux Sound Architecture. This driver borrows some code from +Jaroslav Kysela's <perex@suse.cz> GPLed aplay that is included with +the alsa-util distribution. It defaults to device 0 on card 0. +Because of the way ALSA reads data, this driver packs sound from +successive calls into a fixed size buffer (defaults to 32kB) and sends +it to the card. Note that this driver only works with ALSA 0.5.x. It +will be updated to the newer API once it stabilizes and is better +documented. +<p> + +<b>Option keys:</b> +<ul> +<li>"card" - Sound card number. +<li>"dev" - Device number on sound card. +<li>"buf_size" - Override the internal buffer size (in bytes). +Experiment with this if the sound skips. Default is 32768. +</ul> +<p> + +<hr width="50%"> + +<h3>esd</h3> + +ESounD audio driver. This sound daemon is used on some Linux systems. +It permits multiple programs to play sound simultaneously and sound to +be sent to networked computers. +<p> + +<b>Option keys:</b> +<ul> +<li>"host" - The hostname where esd is running. By default sound is +played on the local host. A port number can be specified after a +colon, as in "whizbang.com:555". +</ul> +<p> + +<hr width="50%"> + +<h3>irix</h3> + +IRIX audio driver. This was inherited from the original +libao, but has not been tested. Use at your own risk. (Better yet, +fix it! I don't have access to an IRIX system.) +<p> + +<b>Option keys:</b> None. +<p> + +<hr width="50%"> + +<h3>oss</h3> + +Open Sound System driver. This is the audio system for +Linux and FreeBSD as well as some other UNIX-like systems. +<p> + +<b>Option keys:</b> +<ul> +<li>"dev" - The dsp device. By default, the driver tries +"/dev/sound/dsp", followed by "/dev/dsp". +</ul> +<p> + +<hr width="50%"> + +<h3>sun</h3> + +Sun audio driver. This is the audio system for NetBSD, OpenBSD, and +Solaris. +<p> + +<b>Option keys:</b> +<ul> +<li>"dev" - The audio device for the sound card. By default, the +driver tries "/dev/audio". +</ul> +<p> + +<hr> + +<h2>File Output Drivers</h2> + +<h3>au</h3> + +Sun audio file driver. Writes a .au file from audio output. This +driver can write usable data to unseekable files (like standard out), +which the wav driver cannot do. +<p> + +<b>Option keys:</b> None. +<p> + +<hr width="50%"> + +<h3>raw</h3> + +Raw sample driver. Writes the sound to disk in uncompressed, +headerless form using the byte order specified. +<p> + +<b>Option keys:</b> +<ul> +<li>"byteorder" - Byte order used in the output. Use "native" for +native machine byte order, "big" for big-endian order, and "little" +for little-endian order. By default this is "native". +</ul> +<p> + +<hr width="50%"> + +<h3>wav</h3> + +Windows sound file output. Because of the way WAV files are +structured, this driver cannot correct files unless the target file is +seekable. Writing WAVs to stdout will result in broken files. Use +either the raw or the au driver instead. +<p> + +<b>Option keys:</b> None. +<p> + +<hr> + +<a name="default_driver"> +<h2>Default Driver Detection</h2> + +In the absence of <a href="config.html">configuration files</a> to +explicit identify a default driver, the library will try to detect a +suitable default driver. It does this by testing every available live +output driver (using <a +href="ao_plugin_test.html">ao_plugin_test()</a>) and finding the +driver with the highest priority (see the <a +href="ao_info.html">ao_info</a> struct) that works. Drivers with +priority 0, such as the null and file output drivers, are never +selected as the default. +<p> + +The ranking system currently used is: +<center> +<table border="1"> + <tr><th>Priority</th><th>Drivers</th> </tr> + <tr><td>30</td> <td>alsa</td> </tr> + <tr><td>20</td> <td>oss, irix, sun</td> </tr> + <tr><td>10</td> <td>esd,arts</td> </tr> + <tr bgcolor="#888888"><td> 0</td> <td>null, all file output</td></tr> +</table> +</center> +<p> + +Clearly, any ranking scheme will fail to make everybody happy. For +such cases, the <a href="config.html">configuration files</a> can be +easily used to define an appropriate default output device + +<br><br> +<hr noshade> +<table border=0 width=100%> +<tr valign=top> +<td><p class=tiny>copyright © 2001 Stan Seibert</p></td> +<td align=right><p class=tiny><a href="http://www.xiph.org/">xiph.org</a><br><a href="mailto:indigo@aztec.asu.edu">indigo@aztec.asu.edu</a></p></td> +</tr><tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +</body> + +</html> diff --git a/doc/index.html b/doc/index.html new file mode 100644 index 0000000..44c51b5 --- /dev/null +++ b/doc/index.html @@ -0,0 +1,52 @@ +<html> + +<head> +<title>libao - Documentation</title> +<link rel=stylesheet href="style.css" type="text/css"> +</head> + +<body bgcolor=white text=black link="#5555ff" alink="#5555ff" vlink="#5555ff"> +<table border=0 width=100%> +<tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +<h1>libao Documentation</h1> + +<p> +Libao is a cross-platform library that allows programs to output +PCM audio data to the native audio devices on a wide variety of +platforms. It currently supports: +<ul> + <li>OSS (Open Sound System) + <li>ESD (ESounD) + <li>ALSA (Advanced Linux Sound Architecture) + <li>Sun audio system (used in Solaris, OpenBSD, and NetBSD) + <li>aRts (Analog Realtime Synthesizer) +</ul> +<p> +<a href="overview.html">libao api overview</a><br> +<a href="drivers.html">drivers</a><br> +<a href="ao_example.c">example code</a><br> +<a href="config.html">configuration files</a><br> +<a href="libao-api.html">libao api reference</a><br> +<a href="plugin-overview.html">plugin overview</a><br> +<a href="plugin-api.html">plugin api reference</a><br> + +<br><br> +<hr noshade> +<table border=0 width=100%> +<tr valign=top> +<td><p class=tiny>copyright © 2001 Stan Seibert</p></td> +<td align=right><p class=tiny><a href="http://www.xiph.org/">xiph.org</a><br><a href="mailto:indigo@aztec.asu.edu">indigo@aztec.asu.edu</a></p></td> +</tr><tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +</body> + +</html> diff --git a/doc/libao-api.html b/doc/libao-api.html new file mode 100644 index 0000000..e52c8e8 --- /dev/null +++ b/doc/libao-api.html @@ -0,0 +1,60 @@ +<html> + +<head> +<title>libao - Documentation</title> +<link rel=stylesheet href="style.css" type="text/css"> +</head> + +<body bgcolor=white text=black link="#5555ff" alink="#5555ff" vlink="#5555ff"> +<table border=0 width=100%> +<tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +<h1>libao API Reference</h1> + +<p> +<b>Data Structures</b><br> +<a href="ao_device.html">ao_device</a><br> +<a href="ao_info.html">ao_info</a><br> +<a href="ao_option.html">ao_option</a><br> +<a href="ao_sample_format.html">ao_sample_format</a><br> +<br> +<b>Library Setup/Teardown</b><br> +<a href="ao_initialize.html">ao_initialize()</a><br> +<a href="ao_shutdown.html">ao_shutdown()</a><br> +<br> +<b>Device Setup/Playback/Teardown</b><br> +<a href="ao_append_option.html">ao_append_option()</a><br> +<a href="ao_free_options.html">ao_free_options()</a><br> +<a href="ao_open_live.html">ao_open_live()</a><br> +<a href="ao_open_file.html">ao_open_file()</a><br> +<a href="ao_play.html">ao_play()</a><br> +<a href="ao_close.html">ao_close()</a><br> +<br> +<b>Driver Information</b><br> +<a href="ao_driver_id.html">ao_driver_id()</a><br> +<a href="ao_default_driver_id.html">ao_default_driver_id()</a><br> +<a href="ao_driver_info.html">ao_driver_info()</a><br> +<a href="ao_driver_info_list.html">ao_driver_info_list()</a><br> +<br> +<b>Miscellaneous</b><br> +<a href="ao_is_big_endian.html">ao_is_big_endian()</a><br> + +<br><br> +<hr noshade> +<table border=0 width=100%> +<tr valign=top> +<td><p class=tiny>copyright © 2001 Stan Seibert</p></td> +<td align=right><p class=tiny><a href="http://www.xiph.org/">xiph.org</a><br><a href="mailto:indigo@aztec.asu.edu">indigo@aztec.asu.edu</a></p></td> +</tr><tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +</body> + +</html> diff --git a/doc/overview.html b/doc/overview.html new file mode 100644 index 0000000..3898ddc --- /dev/null +++ b/doc/overview.html @@ -0,0 +1,109 @@ +<html> + +<head> +<title>libao - Documentation</title> +<link rel=stylesheet href="style.css" type="text/css"> +</head> + +<body bgcolor=white text=black link="#5555ff" alink="#5555ff" vlink="#5555ff"> +<table border=0 width=100%> +<tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +<h1>libao Overview</h1> + +<p> +Libao is designed to make it easy to do simple audio output using +various audio devices and libraries. For this reason, complex audio +control features are missing and will probably never be added. +However, if you just want to be able to open whatever audio device is +available and play sound, libao should be just fine. + +<p> +The libao API makes a distinction between drivers and devices. A +driver is a set of functions that allow audio to be played on a +particular platform (i.e. Solaris, ESD, etc.). A device is a +particular output target that uses a driver. In addition, libao +distinguishes between <i>live</i> output drivers, which write audio to +playback devices (sound cards, etc.), and <i>file</i> output drivers, +which write audio to disk in a particular format. + +<p> +To use libao in your program, you need to follow these steps: +<ul> +<li>Include the <ao/ao.h> header into your program. +<p> + +<li>Call <a href="ao_initialize.html">ao_initialize()</a> to +initialize the library. This loads the plugins from disk, reads the +libao <a href="config.html">configuration files</a>, and identifies an +appropriate default output driver if none is specified in the +configuration files. +<p> + +<li>Call <a +href="ao_default_driver_id.html">ao_default_driver_id()</a> to get the +ID number of the default output driver. This may not be successful if +no audio hardware is available, it is in use, or is not in the "standard" +configuration. If you want to specify a particular output driver, you +may call <a href="ao_driver_id.html">ao_driver_id()</a> with a string +corresponding to the short name of the device (i.e. "oss", "wav", +etc.) instead. +<p> + +<li>If you are using the default device, no extra options are needed. +However, if you wish to to pass special options to the driver, you +will need to: +<p> + +<ul> +<li>Create an option list pointer of type <tt>(<a +href="ao_option.html">ao_option</a> *)</tt> and initialize it to +<tt>NULL</tt>. +<p> + +<li>Through successive calls to <a +href="ao_append_option.html">ao_append_option()</a>, add any +driver-specific options you need. Note that the options take the form +of key/value pairs where supported keys are listed in the <a +href="drivers.html">driver documentation</a>. +</ul> +<p> + +<li>Call <a href="ao_open_live.html">ao_open_live()</a> and save the +returned device pointer. If you are using a file output driver, you +will need to call <a href="ao_open_file.html">ao_open_file()</a> +instead. +<p> + +<li>Call <a href="ao_play.html">ao_play()</a> to output each +block of audio. +<p> + +<li>Call <a href="ao_close.html">ao_close()</a> to close the device. +Note that this will automatically free the memory that was allocated +for the device. Do not attempt to free the device pointer yourself! +<p> + +<li>Call <a href="ao_shutdown.html">ao_shutdown()</a> to close the +library. +</ul> + +<br><br> +<hr noshade> +<table border=0 width=100%> +<tr valign=top> +<td><p class=tiny>copyright © 2001 Stan Seibert</p></td> +<td align=right><p class=tiny><a href="http://www.xiph.org/">xiph.org</a><br><a href="mailto:indigo@aztec.asu.edu">indigo@aztec.asu.edu</a></p></td> +</tr><tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +</body> + +</html> diff --git a/doc/plugin-api.html b/doc/plugin-api.html new file mode 100644 index 0000000..5e2c7bc --- /dev/null +++ b/doc/plugin-api.html @@ -0,0 +1,42 @@ +<html> + +<head> +<title>libao - Documentation</title> +<link rel=stylesheet href="style.css" type="text/css"> +</head> + +<body bgcolor=white text=black link="#5555ff" alink="#5555ff" vlink="#5555ff"> +<table border=0 width=100%> +<tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +<h1>Plugin API</h1> + +<p> +<a href="ao_plugin_test.html">ao_plugin_test()</a><br> +<a href="ao_plugin_driver_info.html">ao_plugin_driver_info()</a><br> +<a href="ao_plugin_device_init.html">ao_plugin_device_init()</a><br> +<a href="ao_plugin_set_option.html">ao_plugin_set_option()</a><br> +<a href="ao_plugin_open.html">ao_plugin_open()</a><br> +<a href="ao_plugin_play.html">ao_plugin_play()</a><br> +<a href="ao_plugin_close.html">ao_plugin_close()</a><br> +<a href="ao_plugin_device_clear.html">ao_plugin_device_clear()</a><br> + +<br><br> +<hr noshade> +<table border=0 width=100%> +<tr valign=top> +<td><p class=tiny>copyright © 2001 Stan Seibert</p></td> +<td align=right><p class=tiny><a href="http://www.xiph.org/">xiph.org</a><br><a href="mailto:indigo@aztec.asu.edu">indigo@aztec.asu.edu</a></p></td> +</tr><tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +</body> + +</html> diff --git a/doc/plugin-overview.html b/doc/plugin-overview.html new file mode 100644 index 0000000..9f6ca55 --- /dev/null +++ b/doc/plugin-overview.html @@ -0,0 +1,45 @@ +<html> + +<head> +<title>libao - Documentation</title> +<link rel=stylesheet href="style.css" type="text/css"> +</head> + +<body bgcolor=white text=black link="#5555ff" alink="#5555ff" vlink="#5555ff"> +<table border=0 width=100%> +<tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +<h1>libao Plugin Overview</h1> + +<p> +Plugins are drivers that are loaded dynamically when libao is first +initialized by the client application. Drivers that are operating +system dependent, like the <tt>oss</tt> and <tt>sun</tt> drivers, or that +depend on external libraries, like the <tt>esd</tt> driver, must be +implemented as plugins in order to keep binary packagers happy. + +<p> +In order to make a new plugin, follow these steps: +<ul> +<li>To be filled in. +</ul> + +<br><br> +<hr noshade> +<table border=0 width=100%> +<tr valign=top> +<td><p class=tiny>copyright © 2001 Stan Seibert</p></td> +<td align=right><p class=tiny><a href="http://www.xiph.org/">xiph.org</a><br><a href="mailto:indigo@aztec.asu.edu">indigo@aztec.asu.edu</a></p></td> +</tr><tr> +<td><p class=tiny>libao documentation</p></td> +<td align=right><p class=tiny>libao version 0.90 - 20010528</p></td> +</tr> +</table> + +</body> + +</html> diff --git a/doc/style.css b/doc/style.css new file mode 100644 index 0000000..332f809 --- /dev/null +++ b/doc/style.css @@ -0,0 +1,7 @@ +BODY { font-family: helvetica, sans-serif } +TD { font-family: helvetica, sans-serif } +P { font-family: helvetica, sans-serif } +H1 { font-family: helvetica, sans-serif } +H2 { font-family: helvetica, sans-serif } +H4 { font-family: helvetica, sans-serif } +P.tiny { font-size: 8pt } diff --git a/include/ao/Makefile.am b/include/ao/Makefile.am index 6ac8ad4..73e1624 100644 --- a/include/ao/Makefile.am +++ b/include/ao/Makefile.am @@ -4,4 +4,5 @@ AUTOMAKE_OPTIONS = foreign includedir = $(prefix)/include/ao -include_HEADERS = ao.h os_types.h +include_HEADERS = ao.h os_types.h plugin.h + diff --git a/include/ao/ao.h b/include/ao/ao.h index 456634e..35e608f 100644 --- a/include/ao/ao.h +++ b/include/ao/ao.h @@ -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 --- */ - -typedef struct ao_option_s { - char *key; - char *value; - struct ao_option_s *next; -} ao_option_t; +/* --- Constants ---*/ -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@ess.engr.uvic.ca>") */ - const char *author; - /* any additional comments (Ex: "Needs work.") */ - const char *comment; -} ao_info_t; +#define AO_TYPE_LIVE 1 +#define AO_TYPE_FILE 2 -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; +#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 -typedef struct ao_device_s { - ao_functions_t *funcs; - ao_internal_t *state; -} ao_device_t; +#define AO_EFAIL 100 +#define AO_FMT_LITTLE 1 +#define AO_FMT_BIG 2 +#define AO_FMT_NATIVE 4 -/* --- Standard driver_id numbers --- */ +/* --- Structures --- */ -#define AO_NULL 0 -#define AO_WAV 1 -#define AO_RAW 2 -#define AO_AU 3 +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); +}; + +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); -/* driver options */ -int ao_append_option(ao_option_t **options, const char *key, const char *value); -void ao_free_options(ao_option_t *options); +int ao_play(ao_device *device, char *output_samples, uint_32 num_bytes); +int ao_close(ao_device *device); -/* 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 } diff --git a/include/ao/os_types.h.in b/include/ao/os_types.h.in index 3907c7c..2621251 100644 --- a/include/ao/os_types.h.in +++ b/include/ao/os_types.h.in @@ -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__ */ diff --git a/include/ao/plugin.h b/include/ao/plugin.h new file mode 100644 index 0000000..c22f560 --- /dev/null +++ b/include/ao/plugin.h @@ -0,0 +1,50 @@ +/* + * + * plugin.h - function declarations for libao plugins + * + * Copyright (C) Stan Seibert - June 2001C + * + * This file is part of libao, a cross-platform audio outputlibrary. See + * README for a history of this source code. + * + * libao is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * libao is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#ifndef __PLUGIN_H__ +#define __PLUGIN_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#include <stdlib.h> +#include "os_types.h" + +int ao_plugin_test(); +ao_info *ao_plugin_driver_info(); +int ao_plugin_device_init(ao_device *device); +int ao_plugin_set_option(ao_device *device, const char *key, const char *value); +int ao_plugin_open(ao_device *device, ao_sample_format *format); +int ao_plugin_play(ao_device *device, const char *output_samples, + uint_32 num_bytes); +int ao_plugin_close(ao_device *device); +void ao_plugin_device_clear(ao_device *device); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __PLUGIN_H__ */ diff --git a/libao.conf.5 b/libao.conf.5 new file mode 100644 index 0000000..449ba80 --- /dev/null +++ b/libao.conf.5 @@ -0,0 +1,68 @@ +.\" Process this file with +.\" groff -man -Tascii libao.conf.5 +.\" +.TH libao.conf 5 "July 8, 2001" "" "libao configuration" + +.SH NAME +libao.conf \- configuration for libao. + +.SH SYNOPSIS + +.B /etc/libao.conf + +.B ~/.libao + +.SH DESCRIPTION +.B libao.conf +and +.B .libao +are configuration files for libao, the audio output library. They +specify various options to libao, as described below. +.B libao.conf +sets system-wide options, whereas +.B ~/.libao +sets user-specific options. When an option is set in +both places, the option in +.B ~/.libao +takes precedence. + +.SH FILE FORMAT +The file consists of comments and key-value pairs. Comments are on separate lines that start with a +.B # +symbol. The key-value pairs are of the form: +.RS +.BR +.B key=value +.RE +where +.B key +contains no whitespace and no equal signs. +.B value +will be all of the text after the equal sign until (but not including) +the ending newline. Beware of extra spaces at the end of the line! +They will probably be interpreted as part of the option value. + +Valid option keys are: +.RS +.IP default_driver +The short name of the driver libao should use by default. +.RE + +.SH EXAMPLE + +Here is an example +.B libao.conf +that forces the OSS driver to be used by default: + + # This is a comment. + default_driver=oss + +.SH BUGS + +.B libao.conf +is missing a number of potentially useful options. + +.SH AUTHORS + +.br +Stan Seibert <indigo@aztec.asu.edu> diff --git a/src/Makefile.am b/src/Makefile.am index eea91da..68b829c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,7 +7,7 @@ INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/include 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@ diff --git a/src/ao_au.c b/src/ao_au.c index 1eb419c..83d38cc 100644 --- a/src/ao_au.c +++ b/src/ao_au.c @@ -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 @@ typedef struct { 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@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 @@ static void ao_au_close(ao_internal_t *state) * 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 }; - diff --git a/src/ao_null.c b/src/ao_null.c index 62d6d2c..942b611 100644 --- a/src/ao_null.c +++ b/src/ao_null.c @@ -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@ess.engr.uvic.ca>", - "This plugin does nothing" + "Stan Seibert <volsung@asu.edu>", + "This driver does nothing.", + AO_FMT_NATIVE, + 0, + NULL, /* No options */ + 0 }; -static ao_internal_t *ao_null_open(uint_32 bits, uint_32 rate, uint_32 channels, ao_option_t *options) + +typedef struct ao_null_internal { + unsigned long byte_counter; +} ao_null_internal; + + +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 }; diff --git a/src/ao_private.h b/src/ao_private.h new file mode 100644 index 0000000..1bada63 --- /dev/null +++ b/src/ao_private.h @@ -0,0 +1,69 @@ +/* + * + * ao_private.c + * + * Copyright (C) Stan Seibert - July 2001 + * + * This file is part of libao, a cross-platform audio output library. See + * README for a history of this source code. + * + * libao is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * libao is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __AO_PRIVATE_H__ +#define __AO_PRIVATE_H__ + +/* --- Operating System Compatibility --- */ + +/* + OpenBSD systems with a.out binaries require dlsym()ed symbols to be + prepended with an underscore, so we need the following nasty #ifdef + hack. +*/ +#if defined(__OpenBSD__) && !defined(__ELF__) +#define dlsym(h,s) dlsym(h, "_" s) +#endif + +/* RTLD_NOW is the preferred symbol resolution behavior, but + some platforms do not support it. */ +#if defined(__OpenBSD__) +#define DLOPEN_FLAG RTLD_LAZY +#else +#define DLOPEN_FLAG RTLD_NOW +#endif + +/* --- Constants --- */ + +#ifndef AO_SYSTEM_CONFIG +#define AO_SYSTEM_CONFIG "/etc/libao.conf" +#endif +#ifndef AO_USER_CONFIG +#define AO_USER_CONFIG "/.libao" +#endif + +/* --- Structures --- */ + +typedef struct ao_config { + char *default_driver; + int default_driver_id; +} ao_config; + +/* --- Functions --- */ + +void read_config_files (ao_config *config); +int read_config_file(ao_config *config, const char *config_file); + +#endif /* __AO_PRIVATE_H__ */ diff --git a/src/ao_raw.c b/src/ao_raw.c index ab12115..a015bf1 100644 --- a/src/ao_raw.c +++ b/src/ao_raw.c @@ -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@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; + int byte_order; +} ao_raw_internal; -static void ao_raw_parse_options(ao_raw_internal_t *state, ao_option_t *options) +static int ao_raw_test() { - 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; - } + return 1; /* Always works */ +} + - if (state->output_file == NULL) - state->output_file = strdup("output.raw"); - if (state->byteorder == 0) - state->byteorder = BYTEORDER_NATIVE; +static ao_info *ao_raw_driver_info(void) +{ + return &ao_raw_info; } -static ao_internal_t *ao_raw_open(uint_32 bits, uint_32 rate, uint_32 channels, ao_option_t *options) + +static int ao_raw_device_init(ao_device *device) { - ao_raw_internal_t *state; + ao_raw_internal *internal; - 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); - - /* 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; - /* 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); + return 1; /* Memory alloc successful */ +} - if(state->fd < 0) { - fprintf(stderr,"%s: Opening audio output %s\n", strerror(errno), state->output_file); - goto ERR; +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 state; + return 1; +} -ERR: - if(state->fd >= 0) { close(state->fd); } - return NULL; + +static int ao_raw_open(ao_device *device, ao_sample_format *format) +{ + ao_raw_internal *internal = (ao_raw_internal *)device->internal; + + device->driver_byte_format = internal->byte_order; + + 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 }; diff --git a/src/ao_wav.c b/src/ao_wav.c index daca10c..d63e5b7 100644 --- a/src/ao_wav.c +++ b/src/ao_wav.c @@ -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 @@ struct wave_header }; -static ao_info_t ao_wav_info = +static ao_info ao_wav_info = { + AO_TYPE_FILE, "WAV file output", "wav", "Aaron Holtzman <aholtzma@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 void (*old_sig)(int); -static void signal_handler(int sig); - - -static void ao_wav_parse_options(ao_wav_internal_t *state, ao_option_t *options) +static int ao_wav_test() { - state->output_file = NULL; + return 1; /* File driver always works */ +} - 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"); +static ao_info *ao_wav_driver_info(void) +{ + return &ao_wav_info; } -static ao_internal_t *ao_wav_open(uint_32 bits, uint_32 rate, uint_32 channels, ao_option_t *options) + +static int ao_wav_device_init(ao_device *device) { - ao_wav_internal_t *state; - unsigned char buf[WAV_HEADER_LEN]; + ao_wav_internal *internal; - memset(buf, 0, WAV_HEADER_LEN); + internal = (ao_wav_internal *) malloc(sizeof(ao_wav_internal)); - state = malloc(sizeof(ao_wav_internal_t)); - if (state == NULL) { - fprintf(stderr, "ao_wav: Could not allocate state memory.\n"); - goto ERR; - } + if (internal == NULL) + return 0; /* Could not initialize device memory */ + + memset(&(internal->wave), 0, sizeof(internal->wave)); + + device->internal = internal; - /* 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); + return 1; /* Memory alloc successful */ +} - 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_set_option(ao_device *device, const char *key, + const char *value) +{ + return 1; /* No options! */ +} - /* 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; - } +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]; - if (last == NULL) { - /* Empty list, install our signal handler only once */ - old_sig = signal(SIGINT,signal_handler); + /* Store information */ + internal->wave.common.wChannels = format->channels; + internal->wave.common.wBitsPerSample = format->bits; + internal->wave.common.dwSamplesPerSec = format->rate; - 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; - } - -ERR: - close(s->fd); - free(s->output_file); - if (s->byte_swap) - free(s->swap_buffer); - free(s); + strncpy(internal->wave.riff.id, "RIFF",4); + internal->wave.riff.len = size - 8; + strncpy(internal->wave.riff.wave_id, "WAVE",4); + + strncpy(internal->wave.format.id, "fmt ",4); + internal->wave.format.len = 16; + + internal->wave.common.wFormatTag = WAVE_FORMAT_PCM; + internal->wave.common.dwAvgBytesPerSec = + internal->wave.common.wChannels * + internal->wave.common.dwSamplesPerSec * + (internal->wave.common.wBitsPerSample >> 3); + + internal->wave.common.wBlockAlign = + internal->wave.common.wChannels * + (internal->wave.common.wBitsPerSample >> 3); + + strncpy(internal->wave.data.id, "data",4); + + 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); + + if (fwrite(buf, sizeof(char), WAV_HEADER_LEN, device->file) + < WAV_HEADER_LEN) + return 0; + + return 1; } -static int ao_wav_get_latency(ao_internal_t *state) +static void ao_wav_device_clear(ao_device *device) { - return 0; -} + ao_wav_internal *internal = (ao_wav_internal *) device->internal; -static ao_info_t *ao_wav_get_driver_info(void) -{ - return &ao_wav_info; + free(internal); } -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); - } - - states = NULL; - - signal(sig, old_sig); - raise(sig); -} - -ao_functions_t ao_wav = -{ - ao_wav_get_driver_info, - ao_wav_open, - ao_wav_play, - ao_wav_close, - ao_wav_get_latency +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 }; + diff --git a/src/audio_out.c b/src/audio_out.c index 6b9b163..0ce028e 100644 --- a/src/audio_out.c +++ b/src/audio_out.c @@ -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 @@ driver_tree_t *_get_plugin(char *plugin_file) return dt; } -void ao_initialize(void) -{ - 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; - struct dirent *plugin_dirent; - char *ext; - struct stat statbuf; - void *plughand; - char fullpath[FILENAME_MAX]; - 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; +/* 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; - 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; - } - } - } + 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 */ } - - closedir(plugindir); + + driver = driver->next; + id++; } } + + return def_id; } -void ao_shutdown(void) + +/* Convert the static drivers table into a linked list of drivers. */ +driver_list* _load_static_drivers(driver_list **end) { - driver_tree_t *driver = driver_head; - driver_tree_t *next_driver; + 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 (!driver_head) return; + if (end != NULL) + *end = driver; - /* 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; - } + return head; +} - /* free the standard drivers */ - if (driver_head) { - if(driver_head->next) - free(driver_head->next); - free(driver_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; + char fullpath[FILENAME_MAX]; + DIR *plugindir; + driver_list *plugin; + driver_list *driver = end; + + /* 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); } - - /* NULL out driver_head or ao_initialize won't work */ - driver_head = NULL; } -int ao_get_driver_id(const char *short_name) + +/* 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; - driver_tree_t *driver = driver_head; + ao_info **table; - 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 */ + /* Count drivers */ + list = head; + i = 0; + while (list != NULL) { + i++; + list = list->next; } + + + /* 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; } -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 @@ driver_tree_t *_get_driver(int driver_id) { 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; @@ -238,62 +326,226 @@ int _check_driver_id(int driver_id) return 0; } -ao_info_t *ao_get_driver_info(int driver_id) + +/* 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) { - driver_tree_t *driver; + if (byte_format == AO_FMT_NATIVE) { + if (ao_is_big_endian()) + return AO_FMT_BIG; + else + return AO_FMT_LITTLE; + } else + return byte_format; +} - if (driver = _get_driver(driver_id)) - return driver->functions->get_driver_info(); - else - return NULL; + +/* 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) +{ + 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; + } + + 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; +} + -void ao_play(ao_device_t *device, void* output_samples, uint_32 num_bytes) +/* ---------- Public Functions ---------- */ + +/* -- 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; + } -/* --- Option Functions --- */ + _clear_config(); + /* NULL out driver_head or ao_initialize() won't work */ + driver_head = NULL; +} -int ao_append_option(ao_option_t **options, const char *key, const char *value) + +/* -- Device Setup/Playback/Teardown -- */ + +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 @@ int ao_append_option(ao_option_t **options, const char *key, const char *value) } -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; @@ -326,7 +578,133 @@ void ao_free_options(ao_option_t *options) } } -/* Helper function lifted from Vorbis' lib/vorbisfile.c */ + +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; +} + + +/* -- 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 @@ int ao_is_big_endian(void) if (bytewise[0] == 0xba) return 1; return 0; } - -int ao_get_latency(ao_device_t *device) -{ - return device->funcs->get_latency(device->state); -} - diff --git a/src/config.c b/src/config.c new file mode 100644 index 0000000..9d0d96a --- /dev/null +++ b/src/config.c @@ -0,0 +1,76 @@ +/* + * + * config.c + * + * Copyright (C) Stan Seibert - July 2000 + * + * This file is part of libao, a cross-platform audio output library. See + * README for a history of this source code. + * + * libao is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * libao is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "ao_private.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> + +void read_config_files (ao_config *config) +{ + char userfile[FILENAME_MAX+1]; + char *homedir = getenv("HOME"); + + /* Read the system-wide config file */ + read_config_file(config, AO_SYSTEM_CONFIG); + + /* Read the user config file */ + if ( homedir!=NULL && + strlen(homedir) <= FILENAME_MAX - strlen(AO_USER_CONFIG) ) + { + strncpy(userfile, homedir, FILENAME_MAX); + strcat(userfile, AO_USER_CONFIG); + read_config_file(config, userfile); + } +} + +#define LINE_LEN 100 + +int read_config_file(ao_config *config, const char *config_file) +{ + FILE *fp; + char line[LINE_LEN]; + int end; + + + if ( !(fp = fopen(config_file, "r")) ) + return 0; /* Can't open file */ + + while (fgets(line, LINE_LEN, fp)) { + /* All options are key=value */ + + if (strncmp(line, "default_driver=", 15) == 0) { + free(config->default_driver); + end = strlen(line); + if (line[end-1] == '\n') + line[end-1] = 0; /* Remove trailing newline */ + + config->default_driver = strdup(line+15); + } + } + + return 1; +} diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am index e3f18bb..3b9cd9e 100644 --- a/src/plugins/Makefile.am +++ b/src/plugins/Makefile.am @@ -1,4 +1,4 @@ ## Process this file with automake to produce Makefile.in AUTOMAKE_OPTIONS = foreign -SUBDIRS = oss sun esd alsa arts # irix +SUBDIRS = oss esd arts alsa sun irix # macosx diff --git a/src/plugins/alsa/ao_alsa.c b/src/plugins/alsa/ao_alsa.c index 747fcdc..585d11b 100644 --- a/src/plugins/alsa/ao_alsa.c +++ b/src/plugins/alsa/ao_alsa.c @@ -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@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 @@ typedef struct ao_alsa_internal_s 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@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 */ + } +} -static int _is_big_endian(void) + +ao_info *ao_plugin_driver_info(void) { - uint_16 pattern = 0xbabe; - unsigned char *bytewise = (unsigned char *)&pattern; + return &ao_alsa_info; +} + + +int ao_plugin_device_init(ao_device *device) +{ + ao_alsa_internal *internal; + + internal = (ao_alsa_internal *) malloc(sizeof(ao_alsa_internal)); + + if (internal == NULL) + return 0; /* Could not initialize device memory */ + + internal->buf_size = AO_ALSA_BUF_SIZE; + internal->card = 0; + internal->dev = 0; + + device->internal = internal; - if (bytewise[0] == 0xba) return 1; - return 0; + 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; - - 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; - } + 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); + + 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 @@ ao_internal_t *plugin_open(uint_32 bits, uint_32 rate, uint_32 channels, ao_opti 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)); - - if (state == NULL) - return NULL; - - ao_alsa_parse_options(state, options); + return 0; // 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 @@ void ao_alsa_write_buffer(ao_alsa_internal_t *s) 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 @@ void ao_alsa_write_buffer(ao_alsa_internal_t *s) 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); } diff --git a/src/plugins/arts/ao_arts.c b/src/plugins/arts/ao_arts.c index a96a4f4..d97e881 100644 --- a/src/plugins/arts/ao_arts.c +++ b/src/plugins/arts/ao_arts.c @@ -2,7 +2,7 @@ * * ao_arts.c * - * Copyright (C) Rik Hemsley (rikkus) <rik@kde.org 2000 + * Copyright (C) Rik Hemsley (rikkus) <rik@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 -{ - arts_stream_t stream; - uint_32 bits; - uint_32 rate; - uint_32 channels; -} ao_arts_internal_t; -ao_info_t ao_arts_info = +static ao_info ao_arts_info = { - "aRts output", - "arts", - "Rik Hemsley (rikkus) <rik@kde.org>", - "Outputs to the aRts soundserver." + AO_TYPE_LIVE, + "aRts output", + "arts", + "Rik Hemsley (rikkus) <rik@kde.org>", + "Outputs to the aRts soundserver.", + AO_FMT_NATIVE, + 10, + NULL, + 0 }; - ao_internal_t * -plugin_open -( - uint_32 bits, - uint_32 rate, - uint_32 channels, - ao_option_t * options -) + +typedef struct ao_arts_internal +{ + arts_stream_t stream; +} ao_arts_internal; + + +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); +} diff --git a/src/plugins/esd/ao_esd.c b/src/plugins/esd/ao_esd.c index 07c52dc..2a777a9 100644 --- a/src/plugins/esd/ao_esd.c +++ b/src/plugins/esd/ao_esd.c @@ -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 -{ - int sock; - char *host; -} ao_esd_internal_t; - -ao_info_t ao_esd_info = +static char *ao_esd_options[] = {"host"}; +static ao_info ao_esd_info = { + AO_TYPE_LIVE, "ESounD output", "esd", "Stan Seibert <volsung@asu.edu>", - "Outputs to the Enlightened Sound Daemon." + "Outputs to the Enlightened Sound Daemon.", + AO_FMT_NATIVE, + 10, + ao_esd_options, + 1 }; -void ao_esd_parse_options(ao_esd_internal_t *state, ao_option_t *options) + +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; +} + + +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); } diff --git a/src/plugins/irix/.cvsignore b/src/plugins/irix/.cvsignore new file mode 100644 index 0000000..282522d --- /dev/null +++ b/src/plugins/irix/.cvsignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/src/plugins/irix/Makefile.am b/src/plugins/irix/Makefile.am new file mode 100644 index 0000000..cd06f15 --- /dev/null +++ b/src/plugins/irix/Makefile.am @@ -0,0 +1,27 @@ +## Process this file with automake to produce Makefile.in + +AUTOMAKE_OPTIONS = foreign + +if HAVE_IRIX + +irixltlibs = libirix.la +irixldflags = -export-dynamic -avoid-version +irixsources = ao_irix.c + +else + +irixltlibs = +irixldflags = +irixsources = + +endif + +INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/include + +libdir = $(plugindir) +lib_LTLIBRARIES = $(irixltlibs) + +libirix_la_LDFLAGS = $(irixldflags) +libirix_la_SOURCES = $(irixsources) + +EXTRA_DIST = ao_irix.c diff --git a/src/plugins/irix/ao_irix.c b/src/plugins/irix/ao_irix.c index fd7dbd9..7c2a1dd 100644 --- a/src/plugins/irix/ao_irix.c +++ b/src/plugins/irix/ao_irix.c @@ -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; } - if (alSetWidth(state->alconfig, wsize) < 0) { + + internal->alport = alOpenPort("libao", "w", 0); + + if (!internal->alport) { + fprintf(stderr, "alOpenPort failed: %s\n", + alGetErrorString(oserror())); + return 0; + } + + + if (alSetWidth(internal->alconfig, wsize) < 0) { fprintf(stderr, "alSetWidth failed: %s\n", alGetErrorString(oserror())); + alClosePort(internal->alport); return 0; } @@ -138,38 +183,42 @@ ao_internal_t *plugin_open(uint_32 bits, uint_32 rate, uint_32 channels, ao_opti 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; } - return state; + device->driver_byte_format = AO_FMT_NATIVE; + + 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); } diff --git a/src/plugins/oss/ao_oss.c b/src/plugins/oss/ao_oss.c index ba2d48d..7822939 100644 --- a/src/plugins/oss/ao_oss.c +++ b/src/plugins/oss/ao_oss.c @@ -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@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); } - ao_oss_parse_options(state, options); + return 1; +} + + +/* + * 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); } diff --git a/src/plugins/sun/ao_sun.c b/src/plugins/sun/ao_sun.c index b655764..e595a85 100644 --- a/src/plugins/sun/ao_sun.c +++ b/src/plugins/sun/ao_sun.c @@ -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@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 */ +} + +int ao_plugin_set_option(ao_device *device, const char *key, const char *value) +{ + ao_sun_internal *internal = (ao_sun_internal *) device->internal; - ao_sun_parse_options(state, options); - - 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); } -- GitLab