Skip to content
This repository has been archived by the owner. It is now read-only.
Permalink
Browse files

Dynamic loading for NAS audio driver.

  • Loading branch information
icculus committed Oct 7, 2006
1 parent 3f95f92 commit 10115dfbde2c666eb114eea4e3c2e2f64c71e911
Showing with 173 additions and 23 deletions.
  1. +32 −3 configure.in
  2. +1 −0 include/SDL_config.h.in
  3. +140 −20 src/audio/nas/SDL_nasaudio.c
@@ -511,11 +511,12 @@ CheckNAS()
AC_HELP_STRING([--enable-nas], [support the NAS audio API [[default=yes]]]),
, enable_nas=yes)
if test x$enable_audio = xyes -a x$enable_nas = xyes; then
AC_MSG_CHECKING(for NAS audio support)
have_nas=no
AC_CHECK_HEADER(audio/audiolib.h, have_nas_hdr=yes)
AC_CHECK_LIB(audio, AuOpenServer, have_nas_lib=yes)

AC_MSG_CHECKING(for NAS audio support)
have_nas=no

if test x$have_nas_hdr = xyes -a x$have_nas_lib = xyes; then
have_nas=yes
NAS_LIBS="-laudio"
@@ -532,12 +533,40 @@ AC_HELP_STRING([--enable-nas], [support the NAS audio API [[default=yes]]]),
have_nas=yes
NAS_LIBS="-lnas -lXt"
fi

AC_MSG_RESULT($have_nas)

if test x$have_nas = xyes; then
AC_ARG_ENABLE(nas-shared,
AC_HELP_STRING([--enable-nas-shared], [dynamically load NAS audio support [[default=yes]]]),
, enable_nas_shared=yes)
if test "x`echo $NAS_LIBS | grep -- -L`" = "x"; then
if test "x`ls /lib/libaudio.so.* 2> /dev/null`" != "x"; then
NAS_LIBS="-L/lib $NAS_LIBS"
elif test "x`ls /usr/lib/libaudio.so.* 2> /dev/null`" != "x"; then
NAS_LIBS="-L/usr/lib $NAS_LIBS"
elif test "x`ls /usr/local/lib/libaudio.so.* 2> /dev/null`" != "x"; then
NAS_LIBS="-L/usr/local/lib $NAS_LIBS"
fi
fi
nas_lib_spec=`echo $NAS_LIBS | sed 's/.*-L\([[^ ]]*\).*/\1\/libaudio.so.*/'`
nas_lib=`ls -- $nas_lib_spec | sed 's/.*\/\(.*\)/\1/; q'`
echo "-- $nas_lib_spec -> $nas_lib"

if test x$have_loadso != xyes && \
test x$enable_nas_shared = xyes; then
AC_MSG_WARN([You must have SDL_LoadObject() support for dynamic NAS loading])
fi
if test x$have_loadso = xyes && \
test x$enable_nas_shared = xyes && test x$alsa_lib != x; then
AC_DEFINE_UNQUOTED(SDL_AUDIO_DRIVER_NAS_DYNAMIC, "$nas_lib")
else
EXTRA_LDFLAGS="$EXTRA_LDFLAGS $NAS_LIBS"
fi

AC_DEFINE(SDL_AUDIO_DRIVER_NAS)
SOURCES="$SOURCES $srcdir/src/audio/nas/*.c"
EXTRA_CFLAGS="$EXTRA_CFLAGS $NAS_CFLAGS"
EXTRA_LDFLAGS="$EXTRA_LDFLAGS $NAS_LIBS"
have_audio=yes
fi
fi
@@ -168,6 +168,7 @@
#undef SDL_AUDIO_DRIVER_MINT
#undef SDL_AUDIO_DRIVER_MMEAUDIO
#undef SDL_AUDIO_DRIVER_NAS
#undef SDL_AUDIO_DRIVER_NAS_DYNAMIC
#undef SDL_AUDIO_DRIVER_OSS
#undef SDL_AUDIO_DRIVER_OSS_SOUNDCARD_H
#undef SDL_AUDIO_DRIVER_PAUD
@@ -32,6 +32,7 @@

#include "SDL_timer.h"
#include "SDL_audio.h"
#include "SDL_loadso.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "SDL_nasaudio.h"
@@ -41,27 +42,138 @@

static struct SDL_PrivateAudioData *this2 = NULL;

/* !!! FIXME: dynamic loading? */

static void (*NAS_AuCloseServer)(AuServer *);
static void (*NAS_AuNextEvent)(AuServer *, AuBool, AuEvent *);
static AuBool (*NAS_AuDispatchEvent)(AuServer *, AuEvent *);
static AuFlowID (*NAS_AuCreateFlow)(AuServer *, AuStatus *);
static void (*NAS_AuStartFlow)(AuServer *, AuFlowID, AuStatus *);
static void (*NAS_AuSetElements)
(AuServer *, AuFlowID, AuBool, int, AuElement *, AuStatus *);
static void (*NAS_AuWriteElement)
(AuServer *, AuFlowID, int, AuUint32, AuPointer, AuBool, AuStatus *);
static AuServer *(*NAS_AuOpenServer)
(_AuConst char *, int, _AuConst char *, int, _AuConst char *, char **);
static AuEventHandlerRec *(*NAS_AuRegisterEventHandler)
(AuServer *, AuMask, int, AuID, AuEventHandlerCallback, AuPointer);


#ifdef SDL_AUDIO_DRIVER_NAS_DYNAMIC

static const char *nas_library = SDL_AUDIO_DRIVER_NAS_DYNAMIC;
static void *nas_handle = NULL;

static int
NAS_Available(void)
load_nas_sym(const char *fn, void **addr)
{
AuServer *aud = AuOpenServer("", 0, NULL, 0, NULL, NULL);
if (!aud)
*addr = SDL_LoadFunction(nas_handle, fn);
if (*addr == NULL) {
return 0;

AuCloseServer(aud);
}
return 1;
}

/* cast funcs to char* first, to please GCC's strict aliasing rules. */
#define SDL_NAS_SYM(x) \
if (!load_nas_sym(#x, (void **) (char *) &NAS_##x)) return -1
#else
#define SDL_NAS_SYM(x) NAS_##x = x
#endif

static int load_nas_syms(void)
{
SDL_NAS_SYM(AuCloseServer);
SDL_NAS_SYM(AuNextEvent);
SDL_NAS_SYM(AuDispatchEvent);
SDL_NAS_SYM(AuCreateFlow);
SDL_NAS_SYM(AuStartFlow);
SDL_NAS_SYM(AuSetElements);
SDL_NAS_SYM(AuWriteElement);
SDL_NAS_SYM(AuOpenServer);
SDL_NAS_SYM(AuRegisterEventHandler);
return 0;
}
#undef SDL_NAS_SYM

#ifdef SDL_AUDIO_DRIVER_NAS_DYNAMIC

static int library_load_count = 0;

static void
UnloadNASLibrary(void)
{
if ((nas_handle != NULL) && (--library_load_count == 0)) {
SDL_UnloadObject(nas_handle);
nas_handle = NULL;
}
}

static int
LoadNASLibrary(void)
{
int retval = 0;
if (library_load_count++ == 0) {
nas_handle = SDL_LoadObject(nas_library);
if (nas_handle == NULL) {
/* Copy error string so we can use it in a new SDL_SetError(). */
char *origerr = SDL_GetError();
size_t len = SDL_strlen(origerr) + 1;
char *err = (char *) alloca(len);
SDL_strlcpy(err, origerr, len);

library_load_count--;
retval = -1;
SDL_SetError("NAS: SDL_LoadObject('%s') failed: %s\n",
nas_library, err);
} else {
retval = load_nas_syms();
if (retval < 0) {
UnloadNASLibrary();
}
}
}
return retval;
}

#else

static void
UnloadNASLibrary(void)
{
}

static int
LoadNASLibrary(void)
{
load_nas_syms();
return 0;
}

#endif /* SDL_AUDIO_DRIVER_NAS_DYNAMIC */

static int
NAS_Available(void)
{
int available = 0;
if (LoadNASLibrary() >= 0) {
AuServer *aud = NAS_AuOpenServer("", 0, NULL, 0, NULL, NULL);
if (aud != NULL) {
available = 1;
NAS_AuCloseServer(aud);
}
UnloadNASLibrary();
}
return available;
}

/* This function waits until it is possible to write a full sound buffer */
static void
NAS_WaitDevice(_THIS)
{
while (this->hidden->buf_free < this->hidden->mixlen) {
AuEvent ev;
AuNextEvent(this->hidden->aud, AuTrue, &ev);
AuDispatchEvent(this->hidden->aud, &ev);
NAS_AuNextEvent(this->hidden->aud, AuTrue, &ev);
NAS_AuDispatchEvent(this->hidden->aud, &ev);
}
}

@@ -75,13 +187,13 @@ NAS_PlayDevice(_THIS)
* of the buffer is free now than what we think.
*/
AuEvent ev;
AuNextEvent(this->hidden->aud, AuTrue, &ev);
AuDispatchEvent(this->hidden->aud, &ev);
NAS_AuNextEvent(this->hidden->aud, AuTrue, &ev);
NAS_AuDispatchEvent(this->hidden->aud, &ev);
}
this->hidden->buf_free -= this->hidden->mixlen;

/* Write the audio data */
AuWriteElement(this->hidden->aud, this->hidden->flow, 0,
NAS_AuWriteElement(this->hidden->aud, this->hidden->flow, 0,
this->hidden->mixlen, this->hidden->mixbuf, AuFalse, NULL);

this->hidden->written += this->hidden->mixlen;
@@ -106,11 +218,12 @@ NAS_CloseDevice(_THIS)
this->hidden->mixbuf = NULL;
}
if (this->hidden->aud) {
AuCloseServer(this->hidden->aud);
NAS_AuCloseServer(this->hidden->aud);
this->hidden->aud = 0;
}
SDL_free(this->hidden);
this2 = this->hidden = NULL;
UnloadNASLibrary();
}
}

@@ -175,6 +288,7 @@ event_handler(AuServer * aud, AuEvent * ev, AuEventHandlerRec * hnd)
static AuDeviceID
find_device(_THIS, int nch)
{
/* These "Au" things are all macros, not functions... */
int i;
for (i = 0; i < AuServerNumDevices(this->hidden->aud); i++) {
if ((AuDeviceKind(AuServerDevice(this->hidden->aud, i)) ==
@@ -202,6 +316,11 @@ NAS_OpenDevice(_THIS, const char *devname, int iscapture)
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));

if (LoadNASLibrary() < 0) {
NAS_CloseDevice(this);
return 0;
}

/* Try for a closest match on audio format */
format = 0;
for (test_format = SDL_FirstAudioFormat(this->spec.format);
@@ -218,7 +337,7 @@ NAS_OpenDevice(_THIS, const char *devname, int iscapture)
}
this->spec.format = test_format;

this->hidden->aud = AuOpenServer("", 0, NULL, 0, NULL, NULL);
this->hidden->aud = NAS_AuOpenServer("", 0, NULL, 0, NULL, NULL);
if (this->hidden->aud == 0) {
NAS_CloseDevice(this);
SDL_SetError("NAS: Couldn't open connection to NAS server");
@@ -227,7 +346,7 @@ NAS_OpenDevice(_THIS, const char *devname, int iscapture)

this->hidden->dev = find_device(this, this->spec.channels);
if ((this->hidden->dev == AuNone)
|| (!(this->hidden->flow = AuCreateFlow(this->hidden->aud, NULL)))) {
|| (!(this->hidden->flow = NAS_AuCreateFlow(this->hidden->aud, 0)))) {
NAS_CloseDevice(this);
SDL_SetError("NAS: Couldn't find a fitting device on NAS server");
return 0;
@@ -249,20 +368,21 @@ NAS_OpenDevice(_THIS, const char *devname, int iscapture)
AuTrue, buffer_size, buffer_size / 4, 0, NULL);
AuMakeElementExportDevice(elms + 1, 0, this->hidden->dev, this->spec.freq,
AuUnlimitedSamples, 0, NULL);
AuSetElements(this->hidden->aud, this->hidden->flow, AuTrue, 2, elms, NULL);
AuRegisterEventHandler(this->hidden->aud, AuEventHandlerIDMask, 0,
this->hidden->flow, event_handler,
(AuPointer) NULL);
NAS_AuSetElements(this->hidden->aud, this->hidden->flow,
AuTrue, 2, elms, NULL);
NAS_AuRegisterEventHandler(this->hidden->aud, AuEventHandlerIDMask, 0,
this->hidden->flow, event_handler,
(AuPointer) NULL);

AuStartFlow(this->hidden->aud, this->hidden->flow, NULL);
NAS_AuStartFlow(this->hidden->aud, this->hidden->flow, NULL);

/* Allocate mixing buffer */
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
NAS_CloseDevice(this);
SDL_OutOfMemory();
return (-1);
return 0;
}
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);

0 comments on commit 10115df

Please sign in to comment.