head 1.24; access; symbols volsung_20010721:1.15.0.2 xiphophorus:1.1.1; locks; strict; comment @ * @; 1.24 date 2003.07.14.01.55.46; author volsung; state Exp; branches; next 1.23; 1.23 date 2003.01.08.03.48.54; author volsung; state Exp; branches; next 1.22; 1.22 date 2002.06.09.17.06.31; author volsung; state Exp; branches; next 1.21; 1.21 date 2002.06.09.15.44.43; author volsung; state Exp; branches; next 1.20; 1.20 date 2001.09.05.19.34.29; author cwolf; state Exp; branches; next 1.19; 1.19 date 2001.08.31.23.17.55; author volsung; state Exp; branches; next 1.18; 1.18 date 2001.08.22.01.56.25; author volsung; state Exp; branches; next 1.17; 1.17 date 2001.08.13.05.24.04; author volsung; state Exp; branches; next 1.16; 1.16 date 2001.08.04.02.56.14; author volsung; state Exp; branches; next 1.15; 1.15 date 2001.05.13.03.30.40; author jack; state Exp; branches 1.15.2.1; next 1.14; 1.14 date 2001.05.06.00.13.59; author jack; state Exp; branches; next 1.13; 1.13 date 2001.02.28.07.50.11; author msmith; state Exp; branches; next 1.12; 1.12 date 2001.02.24.01.31.46; author jack; state Exp; branches; next 1.11; 1.11 date 2001.02.24.01.21.04; author jack; state Exp; branches; next 1.10; 1.10 date 2001.02.24.01.18.50; author jack; state Exp; branches; next 1.9; 1.9 date 2000.12.17.20.28.35; author giles; state Exp; branches; next 1.8; 1.8 date 2000.12.17.13.24.10; author kcarnold; state Exp; branches; next 1.7; 1.7 date 2000.11.18.06.36.58; author jack; state Exp; branches; next 1.6; 1.6 date 2000.11.04.05.29.29; author jack; state Exp; branches; next 1.5; 1.5 date 2000.10.30.04.38.48; author jack; state Exp; branches; next 1.4; 1.4 date 2000.10.30.00.46.41; author jack; state Exp; branches; next 1.3; 1.3 date 2000.09.30.01.16.15; author kcarnold; state Exp; branches; next 1.2; 1.2 date 2000.09.27.06.11.55; author jack; state Exp; branches; next 1.1; 1.1 date 2000.09.03.09.56.05; author jack; state Exp; branches 1.1.1.1; next ; 1.1.1.1 date 2000.09.03.09.56.05; author jack; state Exp; branches; next ; 1.15.2.1 date 2001.07.22.03.35.48; author volsung; state Exp; branches; next 1.15.2.2; 1.15.2.2 date 2001.07.23.23.13.29; author volsung; state Exp; branches; next 1.15.2.3; 1.15.2.3 date 2001.07.24.00.08.02; author volsung; state Exp; branches; next 1.15.2.4; 1.15.2.4 date 2001.07.24.17.51.11; author volsung; state Exp; branches; next 1.15.2.5; 1.15.2.5 date 2001.07.25.19.55.29; author volsung; state Exp; branches; next 1.15.2.6; 1.15.2.6 date 2001.07.25.20.54.43; author volsung; state Exp; branches; next ; desc @@ 1.24 log @Patch from David Walser to do plugin detection in a better way. Sort the plugin priorities and do them in descending order. Also makes use of arts/esd functions to test if they are holding the device or not. If present, we check the those plugins first and only use them if they are currently holding the device. @ text @/* * * audio_out.c * * Original Copyright (C) Aaron Holtzman - May 1999 * Modifications 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 #include #include #include #include #include #ifndef _MSC_VER # include #endif #include #include "ao/ao.h" #include "ao_private.h" /* These should have been set by the Makefile */ #ifndef AO_PLUGIN_PATH #define AO_PLUGIN_PATH "/usr/local/lib/ao" #endif #ifndef SHARED_LIB_EXT #define SHARED_LIB_EXT ".so" #endif /* --- Other constants --- */ #define DEF_SWAP_BUF_SIZE 1024 /* --- Driver Table --- */ typedef struct driver_list { ao_functions *functions; void *handle; 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; #ifdef HAVE_SYS_AUDIO_H extern ao_functions ao_aixs; #endif static ao_functions *static_drivers[] = { &ao_null, /* Must have at least one static driver! */ &ao_wav, &ao_raw, &ao_au, #ifdef HAVE_SYS_AUDIO_H &ao_aixs, #endif NULL /* End of list */ }; static driver_list *driver_head = NULL; static ao_config config = { NULL /* default_driver */ }; static ao_info **info_table = NULL; static int driver_count = 0; /* ---------- Helper functions ---------- */ /* Clear out all of the library configuration options and set them to defaults. The defaults should match the initializer above. */ static void _clear_config() { free(config.default_driver); config.default_driver = NULL; } /* Load a plugin from disk and put the function table into a driver_list struct. */ static driver_list *_get_plugin(char *plugin_file) { driver_list *dt; void *handle; handle = dlopen(plugin_file, DLOPEN_FLAG /* See ao_private.h */); if (handle) { dt = (driver_list *)malloc(sizeof(driver_list)); if (!dt) return NULL; dt->handle = handle; dt->functions = (ao_functions *)malloc(sizeof(ao_functions)); if (!(dt->functions)) { free(dt); return NULL; } dt->functions->test = dlsym(dt->handle, "ao_plugin_test"); if (dlerror()) { free(dt->functions); free(dt); return NULL; } 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, "ao_plugin_play"); if (dlerror()) { free(dt->functions); free(dt); return NULL; } dt->functions->close = dlsym(dt->handle, "ao_plugin_close"); if (dlerror()) { free(dt->functions); free(dt); return NULL; } dt->functions->device_clear = dlsym(dt->handle, "ao_plugin_device_clear"); if (dlerror()) { free(dt->functions); free(dt); return NULL; } } else { return NULL; } return dt; } /* If *name is a valid driver name, return its driver number. Otherwise, test all of available live drivers until one works. */ static int _find_default_driver_id (const char *name) { int def_id; int id; ao_info *info; driver_list *driver = driver_head; if ( name == NULL || (def_id = ao_driver_id(name)) < 0 ) { /* No default specified. Find one among available drivers. */ def_id = -1; id = 0; while (driver != NULL) { info = driver->functions->driver_info(); if ( info->type == AO_TYPE_LIVE && info->priority > 0 && /* Skip static drivers */ driver->functions->test() ) { def_id = id; /* Found a usable driver */ break; } driver = driver->next; id++; } } return def_id; } /* Convert the static drivers table into a linked list of drivers. */ static driver_list* _load_static_drivers(driver_list **end) { driver_list *head; driver_list *driver; int i; /* insert first driver */ head = driver = malloc(sizeof(driver_list)); if (driver != NULL) { driver->functions = static_drivers[0]; driver->handle = NULL; driver->next = NULL; i = 1; while (static_drivers[i] != NULL) { driver->next = malloc(sizeof(driver_list)); if (driver->next == NULL) break; driver->next->functions = static_drivers[i]; driver->next->handle = NULL; driver->next->next = NULL; driver = driver->next; i++; } } if (end != NULL) *end = driver; return head; } /* Load the dynamic drivers from disk and append them to end of the driver list. end points the driver_list node to append to. */ static 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); } } /* Compare two drivers based on priority Used as compar function for qsort() in _make_info_table() */ static int _compar_driver_priority (const driver_list **a, const driver_list **b) { return memcmp(&((*b)->functions->driver_info()->priority), &((*a)->functions->driver_info()->priority), sizeof(int)); } /* Make a table of driver info structures for ao_driver_info_list(). */ static ao_info ** _make_info_table (driver_list **head, int *driver_count) { driver_list *list; int i; ao_info **table; driver_list **drivers_table; *driver_count = 0; /* Count drivers */ list = *head; i = 0; while (list != NULL) { i++; list = list->next; } /* Sort driver_list */ drivers_table = (driver_list **) calloc(i, sizeof(driver_list *)); if (drivers_table == NULL) return (ao_info **) NULL; list = *head; *driver_count = i; for (i = 0; i < *driver_count; i++, list = list->next) drivers_table[i] = list; qsort(drivers_table, i, sizeof(driver_list *), _compar_driver_priority); *head = drivers_table[0]; for (i = 1; i < *driver_count; i++) drivers_table[i-1]->next = drivers_table[i]; drivers_table[i-1]->next = NULL; /* Alloc table */ table = (ao_info **) calloc(i, sizeof(ao_info *)); if (table != NULL) { for (i = 0; i < *driver_count; i++) table[i] = drivers_table[i]->functions->driver_info(); } free(drivers_table); return table; } /* Return the driver struct corresponding to particular driver id number. */ static driver_list *_get_driver(int driver_id) { int i = 0; driver_list *driver = driver_head; if (driver_id < 0) return NULL; while (driver && (i < driver_id)) { i++; driver = driver->next; } if (i == driver_id) return driver; return NULL; } /* Check if driver_id is a valid id number */ static int _check_driver_id(int driver_id) { int i = 0; driver_list *driver = driver_head; if (driver_id < 0) return 0; while (driver && (i <= driver_id)) { driver = driver->next; i++; } if (i == (driver_id + 1)) return 1; return 0; } /* helper function to convert a byte_format of AO_FMT_NATIVE to the actual byte format of the machine, otherwise just return byte_format */ static int _real_byte_format(int byte_format) { if (byte_format == AO_FMT_NATIVE) { if (ao_is_big_endian()) return AO_FMT_BIG; else return AO_FMT_LITTLE; } else return byte_format; } /* Create a new ao_device structure and populate it with data */ static 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. */ static 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 */ } /* Swap and copy the byte order of samples from the source buffer to the target buffer. */ static void _swap_samples(char *target_buffer, char* source_buffer, uint_32 num_bytes) { uint_32 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. */ static 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); /* Only create swap buffer for 16 bit samples if needed */ if (format->bits == 16 && device->client_byte_format != device->driver_byte_format) { result = _realloc_swap_buffer(device, DEF_SWAP_BUF_SIZE); if (!result) { device->funcs->close(device); device->funcs->device_clear(device); free(device); errno = AO_EFAIL; return NULL; /* Couldn't alloc swap buffer */ } } /* If we made it this far, everything is OK. */ return device; } /* ---------- Public Functions ---------- */ /* -- Library Setup/Teardown -- */ void ao_initialize(void) { driver_list *end; /* Read config files */ read_config_files(&config); if (driver_head == NULL) { driver_head = _load_static_drivers(&end); _append_dynamic_drivers(end); } /* Create the table of driver info structs */ info_table = _make_info_table(&driver_head, &driver_count); } void ao_shutdown(void) { driver_list *driver = driver_head; driver_list *next_driver; if (!driver_head) return; /* unload and free all the drivers */ while (driver) { if (driver->handle) { dlclose(driver->handle); free(driver->functions); /* DON'T FREE STATIC FUNC TABLES */ } next_driver = driver->next; free(driver); driver = next_driver; } _clear_config(); /* NULL out driver_head or ao_initialize() won't work */ driver_head = NULL; } /* -- Device Setup/Playback/Teardown -- */ int ao_append_option(ao_option **options, const char *key, const char *value) { ao_option *op, *list; op = malloc(sizeof(ao_option)); if (op == NULL) return 0; op->key = strdup(key); op->value = strdup(value); op->next = NULL; if ((list = *options) != NULL) { list = *options; while (list->next != NULL) list = list->next; list->next = op; } else { *options = op; } return 1; } void ao_free_options(ao_option *options) { ao_option *rest; while (options != NULL) { rest = options->next; free(options->key); free(options->value); free(options); options = rest; } } ao_device *ao_open_live (int driver_id, ao_sample_format *format, ao_option *options) { return _open_device(driver_id, format, options, NULL); } ao_device *ao_open_file (int driver_id, const char *filename, int overwrite, ao_sample_format *format, ao_option *options) { FILE *file; ao_device *device; if (strcmp("-", filename) == 0) file = stdout; else { if (!overwrite) { /* Test for file existence */ file = fopen(filename, "r"); if (file != NULL) { fclose(file); errno = AO_EFILEEXISTS; return NULL; } } file = fopen(filename, "w"); } if (file == NULL) { errno = AO_EOPENFILE; return NULL; } device = _open_device(driver_id, format, options, file); if (device == NULL) { fclose(file); /* errno already set by _open_device() */ return NULL; } return device; } int ao_play(ao_device *device, char* output_samples, uint_32 num_bytes) { char *playback_buffer; if (device->swap_buffer != NULL) { if (_realloc_swap_buffer(device, num_bytes)) { _swap_samples(device->swap_buffer, output_samples, num_bytes); playback_buffer = device->swap_buffer; } else return 0; /* Could not expand swap buffer */ } else playback_buffer = output_samples; return device->funcs->play(device, playback_buffer, num_bytes); } int ao_close(ao_device *device) { int result; result = device->funcs->close(device); device->funcs->device_clear(device); free(device); return result; } /* -- 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 () { /* Find the default driver in the list of loaded drivers */ return _find_default_driver_id(config.default_driver); } 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; unsigned char *bytewise = (unsigned char *)&pattern; if (bytewise[0] == 0xba) return 1; return 0; } @ 1.23 log @Patch from Stefan Tibus to add support for the AIX audio devices. The conditional compilation is a little messy, but I still need to decide a good way to do that in general. @ text @a163 1 int priority; a171 1 priority = 0; /* This forces the null driver to be skipped */ d177 1 a177 1 info->priority > priority && a178 1 priority = info->priority; d180 1 d265 11 d277 1 a277 1 static ao_info ** _make_info_table (driver_list *head, int *driver_count) d282 3 d287 1 a287 1 list = head; d295 15 d313 5 a317 6 *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; d544 1 a544 1 info_table = _make_info_table(driver_head, &driver_count); @ 1.22 log @Removed unnecessary trailing comma to make Jack happy. :-P @ text @d65 3 d74 3 @ 1.21 log @Made use of "static" to prevent unwanted symbols from being exported. @ text @d76 1 a76 1 NULL, /* default_driver */ @ 1.20 log @Don't include unistd.h with MSVC, fix a warning @ text @d66 1 a66 1 ao_functions *static_drivers[] = { d74 2 a75 2 driver_list *driver_head = NULL; ao_config config = { d79 2 a80 2 ao_info **info_table = NULL; int driver_count = 0; d86 1 a86 1 void _clear_config() d96 1 a96 1 driver_list *_get_plugin(char *plugin_file) d154 1 a154 1 int _find_default_driver_id (const char *name) d189 1 a189 1 driver_list* _load_static_drivers(driver_list **end) d226 1 a226 1 void _append_dynamic_drivers(driver_list *end) d262 1 a262 1 ao_info ** _make_info_table (driver_list *head, int *driver_count) d293 1 a293 1 driver_list *_get_driver(int driver_id) { d312 1 a312 1 int _check_driver_id(int driver_id) d334 1 a334 1 int _real_byte_format(int byte_format) d347 2 a348 2 ao_device* _create_device(int driver_id, driver_list *driver, ao_sample_format *format, FILE *file) d374 1 a374 1 int _realloc_swap_buffer(ao_device *device, int min_size) d393 2 a394 1 void _swap_samples(char *target_buffer, char* source_buffer, uint_32 num_bytes) d406 2 a407 2 ao_device* _open_device(int driver_id, ao_sample_format *format, ao_option *options, FILE *file) @ 1.19 log @API update allowing library users to get the suggested file extension associated with a particular file output driver. The additional plugin function is optional, so drivers that don't need to implement it don't have to. That's why we don't need to bump the plugin API version number. @ text @d33 3 a35 1 #include d37 1 d43 1 a43 1 #define AO_PLUGIN_PATH "/usr/local/lib/ao/plugins" a142 5 /* Optional function */ dt->functions->file_extension = dlsym(dt->handle, "ao_plugin_file_extension"); if (dlerror()) { dt->functions->file_extension = NULL; } d395 1 a395 1 int i; a701 12 char *ao_file_extension(int driver_id) { driver_list *driver; if ( (driver = _get_driver(driver_id)) && driver->functions->file_extension != NULL) return driver->functions->file_extension(); else return NULL; } @ 1.18 log @Changed plugin dir to be less messy. All plugin versions will be in separate subdirectories of $libdir/ao. @ text @d140 5 d704 12 @ 1.17 log @Default driver is now identified when ao_default_driver_id() is called rather than ao_initialize(). This has the benefit of avoiding autodetection unless is it necessary. @ text @d40 1 a40 1 #define AO_PLUGIN_PATH "/usr/local/lib/ao" @ 1.16 log @Merger of new API branch (volsung_20010721) with head. @ text @a73 1 -1, /* default_driver_id */ a86 1 config.default_driver_id = -1; a506 4 /* Find the default driver in the list of loaded drivers */ config.default_driver_id = _find_default_driver_id(config.default_driver); d677 3 a679 1 return config.default_driver_id; @ 1.15 log @.au output device provided by William T. Mahan @ text @d35 2 a36 1 #include a38 3 #ifndef AO_DEFAULT #define AO_DEFAULT AO_NULL #endif d46 3 d51 2 a52 2 typedef struct driver_tree_s { ao_functions_t *functions; d54 25 a78 2 struct driver_tree_s *next; } driver_tree_t; d80 1 a80 4 extern ao_functions_t ao_null; extern ao_functions_t ao_wav; extern ao_functions_t ao_raw; extern ao_functions_t ao_au; d82 12 a93 1 driver_tree_t *driver_head = NULL; d95 1 a95 1 driver_tree_t *_get_plugin(char *plugin_file) d97 1 a97 1 driver_tree_t *dt; d99 3 a101 2 handle = dlopen(plugin_file, RTLD_NOW); d103 1 a103 1 dt = (driver_tree_t *)malloc(sizeof(driver_tree_t)); d108 1 a108 1 dt->functions = (ao_functions_t *)malloc(sizeof(ao_functions_t)); d114 1 a114 1 dt->functions->get_driver_info = dlsym(dt->handle, "plugin_get_driver_info"); d116 14 a129 1 dt->functions->open = dlsym(dt->handle, "plugin_open"); d131 2 a132 1 dt->functions->play = dlsym(dt->handle, "plugin_play"); d134 2 a135 1 dt->functions->close = dlsym(dt->handle, "plugin_close"); d137 3 a139 1 dt->functions->get_latency = dlsym(dt->handle, "plugin_get_latency"); d141 2 d150 76 a225 1 void ao_initialize(void) a226 7 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; a229 1 void *plughand; d231 3 d235 15 a249 36 if (driver_head == NULL) { /* insert the null, wav, raw, and au drivers into the tree */ dnull = (driver_tree_t *)malloc(sizeof(driver_tree_t)); dnull->functions = &ao_null; dnull->handle = NULL; dwav = (driver_tree_t *)malloc(sizeof(driver_tree_t)); dwav->functions = &ao_wav; dwav->handle = NULL; draw = (driver_tree_t *)malloc(sizeof(driver_tree_t)); draw->functions = &ao_raw; draw->handle = NULL; dau = (driver_tree_t *)malloc(sizeof(driver_tree_t)); dau->functions = &ao_au; dau->handle = NULL; dnull->next = dwav; dwav->next = draw; draw->next = dau; dau->next = NULL; driver_head = dnull; driver = dau; /* now insert any plugins we find */ plugindir = opendir(AO_PLUGIN_PATH); if (plugindir != NULL) { while ((plugin_dirent = readdir(plugindir)) != NULL) { snprintf(fullpath, FILENAME_MAX, "%s/%s", AO_PLUGIN_PATH, plugin_dirent->d_name); if (!stat(fullpath, &statbuf) && S_ISREG(statbuf.st_mode) && (ext = strrchr(plugin_dirent->d_name, '.')) != NULL) { if (strcmp(ext, SHARED_LIB_EXT) == 0) { plugin = _get_plugin(fullpath); if (plugin) { driver->next = plugin; plugin->next = NULL; driver = driver->next; } a252 2 closedir(plugindir); d254 2 d259 3 a261 1 void ao_shutdown(void) d263 3 a265 2 driver_tree_t *driver = driver_head; driver_tree_t *next_driver; d267 6 a272 10 if (!driver_head) return; /* 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; a274 6 /* free the standard drivers */ if (driver_head) { if(driver_head->next) free(driver_head->next); free(driver_head); } d276 11 a286 2 /* NULL out driver_head or ao_initialize won't work */ driver_head = NULL; a288 19 int ao_get_driver_id(const char *short_name) { int i; driver_tree_t *driver = driver_head; if (short_name == NULL) { return AO_NULL; } else { i = 0; while (driver) { if (strcmp(short_name, driver->functions->get_driver_info()->short_name) == 0) return i; driver = driver->next; i++; } return -1; /* No driver by that name */ } } d290 3 a292 1 driver_tree_t *_get_driver(int driver_id) { d294 1 a294 1 driver_tree_t *driver = driver_head; d309 2 d314 1 a314 1 driver_tree_t *driver = driver_head; d329 19 a347 1 ao_info_t *ao_get_driver_info(int driver_id) d349 17 a365 1 driver_tree_t *driver; d367 1 a367 4 if (driver = _get_driver(driver_id)) return driver->functions->get_driver_info(); else return NULL; d371 17 a388 1 /* -- Audio Functions --- */ d390 3 a392 1 ao_device_t* ao_open(int driver_id, uint_32 bits, uint_32 rate, uint_32 channels, ao_option_t *options) d394 91 a484 13 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; d488 8 a495 2 return NULL; } d497 1 a497 1 void ao_play(ao_device_t *device, void* output_samples, uint_32 num_bytes) d499 16 a514 1 device->funcs->play(device->state, output_samples, num_bytes); d518 1 a518 1 void ao_close(ao_device_t *device) d520 19 a538 2 device->funcs->close(device->state); free(device); d542 1 d544 1 a544 3 /* --- Option Functions --- */ int ao_append_option(ao_option_t **options, const char *key, const char *value) d546 1 a546 1 ao_option_t *op, *list; d548 1 a548 1 op = malloc(sizeof(ao_option_t)); d568 1 a568 1 void ao_free_options(ao_option_t *options) d570 1 a570 1 ao_option_t *rest; d581 127 a707 1 /* Helper function lifted from Vorbis' lib/vorbisfile.c */ a715 6 int ao_get_latency(ao_device_t *device) { return device->funcs->get_latency(device->state); } @ 1.15.2.1 log @Initial branch of libao to new API. Great fear and trembling shall sweep the land... @ text @d35 1 a35 2 #include "ao/ao.h" #include "ao_private.h" d38 3 a47 3 /* --- Other constants --- */ #define DEF_SWAP_BUF_SIZE 1024 d50 2 a51 2 typedef struct driver_list { ao_functions *functions; d53 2 a54 25 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; d56 4 a59 1 /* ---------- Helper functions ---------- */ d61 1 a61 8 /* 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; } d63 1 a63 4 /* Load a plugin from disk and put the function table into a driver_list struct. */ driver_list *_get_plugin(char *plugin_file) d65 1 a65 1 driver_list *dt; d70 1 a70 1 dt = (driver_list *)malloc(sizeof(driver_list)); d75 1 a75 1 dt->functions = (ao_functions *)malloc(sizeof(ao_functions)); d81 1 a81 9 dt->functions->test = dlsym(dt->handle, "plugin_test"); if (dlerror()) { free(dt->functions); free(dt); return NULL; } dt->functions->driver_info = dlsym(dt->handle, "plugin_driver_info"); if (dlerror()) { free(dt->functions); free(dt); return NULL; } dt->functions->device_init = dlsym(dt->handle, "plugin_device_init"); a82 5 dt->functions->set_option = dlsym(dt->handle, "plugin_set_option"); if (dlerror()) { free(dt->functions); free(dt); return NULL; } a84 1 a86 1 d89 1 a89 3 dt->functions->device_clear = dlsym(dt->handle, "plugin_device_clear"); a90 2 d98 1 a98 76 /* 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; 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; /* Skip null driver */ id = 1; driver = driver->next; while (driver != NULL && def_id == -1) { if ( (driver->functions->driver_info()->type == AO_TYPE_LIVE) && driver->functions->test() ) { def_id = id; /* Found a usable driver */ } driver = driver->next; id++; } /* Did we actually find anything? */ if (def_id == -1) def_id = 0; /* If not, use null driver */ } return def_id; } /* Convert the static drivers table into a linked list of drivers. */ driver_list* _load_static_drivers(driver_list **end) { 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->next = NULL; driver = driver->next; i++; } } if (end != NULL) *end = driver; return head; } /* Load the dynamic drivers from disk and append them to end of the driver list. end points the driver_list node to append to. */ void _append_dynamic_drivers(driver_list *end) d100 7 d110 1 a111 3 DIR *plugindir; driver_list *plugin; driver_list *driver = end; d113 36 a148 15 /* 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; d152 2 a154 2 closedir(plugindir); d158 4 d163 1 a163 6 /* Make a table of driver info structures for ao_driver_info_list(). */ ao_info ** _make_info_table (driver_list *head, int *driver_count) { driver_list *list; int i; ao_info **table; d165 8 a172 6 /* Count drivers */ list = head; i = 0; while (list != NULL) { i++; list = list->next; d175 6 d182 2 a183 11 /* 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; d186 19 d206 1 a206 3 /* Return the driver struct corresponding to particular driver id number. */ driver_list *_get_driver(int driver_id) { d208 1 a208 1 driver_list *driver = driver_head; a222 2 /* Check if driver_id is a valid id number */ d226 1 a226 1 driver_list *driver = driver_head; d241 1 a241 19 /* helper function to convert a byte_format of AO_FMT_NATIVE to the actual byte format of the machine, otherwise just return byte_format */ int _real_byte_format(int byte_format) { if (byte_format == AO_FMT_NATIVE) { if (ao_is_big_endian()) return AO_FMT_BIG; else return AO_FMT_LITTLE; } else return byte_format; } /* 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) d243 1 a243 17 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; } d245 4 a248 1 return device; a251 17 /* 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 */ } d253 1 d255 1 a255 3 /* 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) d257 13 a269 60 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; a270 2 options = options->next; a271 13 /* 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); d273 2 a274 22 /* Only create swap buffer for 16 bit samples if needed */ if (format->bits == 16 && device->client_byte_format != device->driver_byte_format) { result = _realloc_swap_buffer(device, DEF_SWAP_BUF_SIZE); if (!result) { device->funcs->close(device); device->funcs->device_clear(device); free(device); errno = AO_EFAIL; return NULL; /* Couldn't alloc swap buffer */ } } /* If we made it this far, everything is OK. */ return device; } /* ---------- Public Functions ---------- */ d276 1 a276 3 /* -- Library Setup/Teardown -- */ void ao_initialize(void) d278 1 a278 16 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); d282 1 a282 1 void ao_shutdown(void) d284 3 a286 15 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; } a287 4 _clear_config(); /* NULL out driver_head or ao_initialize() won't work */ driver_head = NULL; } d290 1 a290 1 /* -- Device Setup/Playback/Teardown -- */ d292 1 a292 1 int ao_append_option(ao_option **options, const char *key, const char *value) d294 1 a294 1 ao_option *op, *list; d296 1 a296 1 op = malloc(sizeof(ao_option)); d316 1 a316 1 void ao_free_options(ao_option *options) d318 1 a318 1 ao_option *rest; d329 1 a329 127 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 */ d338 6 @ 1.15.2.2 log @Forgot to zero an element of a struct. Fixes segfault some users were experiencing during ao_shutdown(). @ text @a206 1 driver->next->handle = NULL; @ 1.15.2.3 log @Changed the plugin_*() functions to ao_plugin_*() functions for consistency. @ text @d112 1 a112 1 dt->functions->test = dlsym(dt->handle, "ao_plugin_test"); d116 1 a116 1 dlsym(dt->handle, "ao_plugin_driver_info"); d120 1 a120 1 dlsym(dt->handle, "ao_plugin_device_init"); d124 1 a124 1 dlsym(dt->handle, "ao_plugin_set_option"); d127 1 a127 1 dt->functions->open = dlsym(dt->handle, "ao_plugin_open"); d130 1 a130 1 dt->functions->play = dlsym(dt->handle, "ao_plugin_play"); d133 1 a133 1 dt->functions->close = dlsym(dt->handle, "ao_plugin_close"); d137 1 a137 1 dlsym(dt->handle, "ao_plugin_device_clear"); @ 1.15.2.4 log @We now use a ranking system to select a defaut driver from the range of possible drivers. Note that the null device is no longer a possible default device to prevent user confusion that we have had in the past. @ text @a154 2 int priority; ao_info *info; d161 3 a163 3 id = 0; priority = 0; /* This forces the null driver to be skipped */ while (driver != NULL) { d165 1 a165 1 info = driver->functions->driver_info(); d167 2 a168 2 if ( info->type == AO_TYPE_LIVE && info->priority > priority && d170 1 a170 1 priority = info->priority; a172 1 d176 4 @ 1.15.2.5 log @OpenBSD compatability patches from Christian Weisgerber . Yes, I know #ifdef's are evil, but making C work on multiple UNIX's is the work of the devil to begin with. @ text @d93 1 a93 8 struct. 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 d98 1 a98 6 /* RTLD_NOW is the preferred symbol resolution behavior, but some platforms do not support it. */ #if defined(__OpenBSD__) handle = dlopen(plugin_file, RTLD_LAZY); #else a99 2 #endif @ 1.15.2.6 log @Moved #ifdefs to header file as per Jack's suggestion. @ text @d93 1 a93 1 struct. */ d95 6 d106 7 a112 1 handle = dlopen(plugin_file, DLOPEN_FLAG /* See ao_private.h */); @ 1.14 log @Stan Seibert's ao_raw device. @ text @d59 1 d103 1 d114 1 a114 1 /* insert the null and wav drivers into the tree */ d124 3 d130 2 a131 1 draw->next = NULL; d134 1 a134 1 driver = draw; d166 1 a166 1 driver = driver->next->next->next; /* Skip null, wav, and raw driver */ @ 1.13 log @ Fix the really obvious errors found in various places trying to track down the arts bug. - wrong function prototypes in ao_null and ao_wav - freeing stuff based on wrong tests in audio_out.c - fix a memory leak in ao_arts.c @ text @d58 1 d101 1 d119 3 d124 2 a125 1 dwav->next = NULL; d128 1 a128 1 driver = dwav; d160 1 a160 1 driver = driver->next->next; @ 1.12 log @rik@@kde.org's ao_get_latency patch + fixes to make it compile incremented teh library version @ text @d164 5 a168 2 if (driver_head->next) free(driver_head->next); if (driver_head->next) free(driver_head); @ 1.11 log @let's back that change out since I'm an idiot. you can do this without that api change @ text @d87 2 d323 6 @ 1.10 log @added new function suggested by rik@@kde.org updated library version for release @ text @a320 14 int ao_get_driver_count(void) { int i = 0; driver_tree_t *driver = driver_head; while (driver) { i++; driver = driver->next; } return i; } @ 1.9 log @ API change. Rather than passing the driver options as single "key:value" string, we have a slot for each in ao_append_option() corresponding documentation changes, harmonized ao_append_option() definition in the header and docs, plus some other doc fixups. @ text @d321 14 @ 1.8 log @Fix for case where ao_initialize is called after ao_shutdown. @ text @d275 1 a275 1 ao_option_t* _parse_option(const char* op_str) d277 1 a277 24 char *copy; char *value_ptr; char *colon; ao_option_t *op = NULL; copy = strdup(op_str); colon = strchr(copy, ':'); if (colon != NULL) { value_ptr = colon + 1; *colon = 0x00; // Null terminate the key part /* Allocate the option structure */ op = malloc(sizeof(ao_option_t)); if (op != NULL) { op->key = strdup(copy); op->value = strdup(value_ptr); op->next = NULL; } } free(copy); return op; } d279 2 d282 3 a284 5 int ao_append_option(ao_option_t **options, const char *op_str) { ao_option_t *temp; temp = _parse_option(op_str); d286 4 a289 7 if (temp == NULL) return 0; //Bad option format if (*options != NULL) { while ((*options)->next != NULL) *options = (*options)->next; (*options)->next = temp; d291 1 a291 1 *options = temp; d293 1 @ 1.7 log @using correct constant now @ text @d164 3 @ 1.6 log @few fixes courtesy of ingo saitz @ text @d105 1 a105 1 char fullpath[NAME_MAX]; d126 1 a126 1 snprintf(fullpath, NAME_MAX, "%s/%s", AO_PLUGIN_PATH, plugin_dirent->d_name); @ 1.5 log @now this actually works :) @ text @d133 1 @ 1.4 log @the long awaited ao fixes. this hasn't been well tested. @ text @d79 1 a79 1 dt->functions->get_driver_info = dlsym(dt->handle, "get_driver_info"); d81 1 a81 1 dt->functions->open = dlsym(dt->handle, "open"); d83 1 a83 1 dt->functions->play = dlsym(dt->handle, "play"); d85 1 a85 1 dt->functions->close = dlsym(dt->handle, "close"); @ 1.3 log @Trying to get libao to compile properly. This is at least an improvement. See post on mailing list for more info. @ text @d8 1 a8 1 * This file is part of libao, a cross-platform library. See d30 5 a34 1 #include d37 3 a39 12 /* --- Function Tables --- */ extern ao_functions_t ao_null; /* Okay, so this is messy. I'm open to ideas of how to clean this up. - Stan */ #ifdef AO_COMPILE_OSS extern ao_functions_t ao_oss; #define AO_FUNC_OSS &ao_oss #else #define AO_FUNC_OSS NULL d41 2 a42 6 #ifdef AO_COMPILE_IRIX extern ao_functions_t ao_irix; #define AO_FUNC_IRIX &ao_irix #else #define AO_FUNC_IRIX NULL d44 2 a45 6 #ifdef AO_COMPILE_SOLARIS extern ao_functions_t ao_solaris; #define AO_FUNC_SOLARIS &ao_solaris #else #define AO_FUNC_SOLARIS NULL d48 1 a48 6 #ifdef AO_COMPILE_WIN32 extern ao_functions_t ao_win32; #define AO_FUNC_WIN32 &ao_win32 #else #define AO_FUNC_WIN32 NULL #endif d50 5 a54 6 #ifdef AO_COMPILE_BEOS extern ao_functions_t ao_beos; #define AO_FUNC_BEOS &ao_beos #else #define AO_FUNC_BEOS NULL #endif d56 2 a57 6 #ifdef AO_COMPILE_ESD extern ao_functions_t ao_esd; #define AO_FUNC_ESD &ao_esd #else #define AO_FUNC_ESD NULL #endif d59 1 a59 6 #ifdef AO_COMPILE_ALSA extern ao_functions_t ao_alsa; #define AO_FUNC_ALSA &ao_alsa #else #define AO_FUNC_ALSA NULL #endif d61 9 a69 1 extern ao_functions_t ao_wav; d71 7 d79 11 d91 2 a92 1 /* --- Driver Table --- */ d94 1 a94 1 ao_functions_t* ao_drivers[AO_DRIVERS] = d96 46 a141 13 &ao_null, /* 0: Null Device */ AO_FUNC_OSS, /* 1: Linux, *BSD */ AO_FUNC_IRIX, /* 2: IRIX */ AO_FUNC_SOLARIS, /* 3: Solaris */ AO_FUNC_WIN32, /* 4: Win32 */ AO_FUNC_BEOS, /* 5: BeOS */ AO_FUNC_ESD, /* 6: EsounD */ AO_FUNC_ALSA, /* 7: ALSA */ NULL, /* 8: Unassigned */ NULL, /* 9: Unassigned */ &ao_wav, /* 10: .WAV output */ NULL, /* 11: RAW output */ }; d143 4 d148 1 d150 9 a158 1 /* --- Driver Functions --- */ d160 4 a163 4 /* This should have been set by the Makefile */ #ifndef AO_DEFAULT #define AO_DEFAULT AO_NULL #endif d165 1 a165 1 int ao_get_driver_id (const char *short_name) d168 1 d170 3 a172 4 if (short_name == NULL) return AO_DEFAULT; else { d174 2 a175 6 while (i < AO_DRIVERS) { /* Skip empty driver slots */ if (ao_drivers[i] != NULL && !strcmp(short_name, ao_drivers[i]->get_driver_info()->short_name)) d177 1 a177 1 d185 10 d196 7 a202 1 int ao_check_driver_id (int driver_id) d204 14 a217 2 return driver_id >= 0 && driver_id < AO_DRIVERS && ao_drivers[driver_id] != NULL; d220 1 a220 1 ao_info_t *ao_get_driver_info (int driver_id) d222 4 a225 2 if (ao_check_driver_id(driver_id)) return ao_drivers[driver_id]->get_driver_info(); d234 1 a234 2 ao_device_t* ao_open (int driver_id, uint_32 bits, uint_32 rate, uint_32 channels, ao_option_t *options) d239 1 d241 2 a242 3 if (ao_check_driver_id(driver_id)) { funcs = ao_drivers[driver_id]; d244 1 a244 2 if (state != NULL) { d255 1 a255 1 void ao_play (ao_device_t *device, void* output_samples, uint_32 num_bytes) d257 1 a257 2 device->funcs->play(device->state, output_samples, num_bytes); d261 1 a261 1 void ao_close (ao_device_t *device) d271 1 a271 1 ao_option_t* ao_parse_option (const char* op_str) d281 1 a281 2 if (colon != NULL) { d285 1 a285 1 // Allocate the option structure d287 1 a287 2 if (op != NULL) { d299 1 a299 1 int ao_append_option (ao_option_t **options, const char *op_str) d303 1 a303 1 temp = ao_parse_option(op_str); d308 1 a308 2 if (*options != NULL) { a309 1 { a310 1 } d312 1 a312 3 } else { d320 1 a320 1 void ao_free_options (ao_option_t* options) d324 1 a324 2 while (options != NULL) { d333 3 a335 2 /* Helper function lifted from lib/vorbisfile.c */ int ao_is_big_endian() { d338 1 a339 2 assert(bytewise[0] == 0xbe); @ 1.2 log @brought up to date with postbeta2 @ text @d31 1 a31 1 #include "audio_out.h" @ 1.1 log @Initial revision @ text @d30 2 a31 1 #include d271 10 @ 1.1.1.1 log @The first sample... @ text @@