Dynamic loading for NAS audio driver. SDL-ryan-multiple-audio-device
authorRyan C. Gordon <icculus@icculus.org>
Sat, 07 Oct 2006 07:25:30 +0000
branchSDL-ryan-multiple-audio-device
changeset 382576c5a414b996
parent 3824 25052dd25810
child 3826 5b483ce86357
Dynamic loading for NAS audio driver.
configure.in
include/SDL_config.h.in
src/audio/nas/SDL_nasaudio.c
     1.1 --- a/configure.in	Sat Oct 07 07:23:52 2006 +0000
     1.2 +++ b/configure.in	Sat Oct 07 07:25:30 2006 +0000
     1.3 @@ -511,10 +511,11 @@
     1.4  AC_HELP_STRING([--enable-nas], [support the NAS audio API [[default=yes]]]),
     1.5                    , enable_nas=yes)
     1.6      if test x$enable_audio = xyes -a x$enable_nas = xyes; then
     1.7 +        AC_CHECK_HEADER(audio/audiolib.h, have_nas_hdr=yes)
     1.8 +        AC_CHECK_LIB(audio, AuOpenServer, have_nas_lib=yes)
     1.9 +
    1.10          AC_MSG_CHECKING(for NAS audio support)
    1.11          have_nas=no
    1.12 -        AC_CHECK_HEADER(audio/audiolib.h, have_nas_hdr=yes)
    1.13 -        AC_CHECK_LIB(audio, AuOpenServer, have_nas_lib=yes)
    1.14  
    1.15          if test x$have_nas_hdr = xyes -a x$have_nas_lib = xyes; then
    1.16              have_nas=yes
    1.17 @@ -532,12 +533,40 @@
    1.18              have_nas=yes
    1.19              NAS_LIBS="-lnas -lXt"
    1.20          fi
    1.21 +
    1.22          AC_MSG_RESULT($have_nas)
    1.23 +
    1.24          if test x$have_nas = xyes; then
    1.25 +            AC_ARG_ENABLE(nas-shared,
    1.26 +AC_HELP_STRING([--enable-nas-shared], [dynamically load NAS audio support [[default=yes]]]),
    1.27 +                          , enable_nas_shared=yes)
    1.28 +            if test "x`echo $NAS_LIBS | grep -- -L`" = "x"; then
    1.29 +                if test "x`ls /lib/libaudio.so.* 2> /dev/null`" != "x"; then
    1.30 +                    NAS_LIBS="-L/lib $NAS_LIBS"
    1.31 +                elif test "x`ls /usr/lib/libaudio.so.* 2> /dev/null`" != "x"; then
    1.32 +                    NAS_LIBS="-L/usr/lib $NAS_LIBS"
    1.33 +                elif test "x`ls /usr/local/lib/libaudio.so.* 2> /dev/null`" != "x"; then
    1.34 +                    NAS_LIBS="-L/usr/local/lib $NAS_LIBS"
    1.35 +                fi
    1.36 +            fi
    1.37 +            nas_lib_spec=`echo $NAS_LIBS | sed 's/.*-L\([[^ ]]*\).*/\1\/libaudio.so.*/'`
    1.38 +            nas_lib=`ls -- $nas_lib_spec | sed 's/.*\/\(.*\)/\1/; q'`
    1.39 +            echo "-- $nas_lib_spec -> $nas_lib"
    1.40 +
    1.41 +            if test x$have_loadso != xyes && \
    1.42 +               test x$enable_nas_shared = xyes; then
    1.43 +                AC_MSG_WARN([You must have SDL_LoadObject() support for dynamic NAS loading])
    1.44 +            fi
    1.45 +            if test x$have_loadso = xyes && \
    1.46 +               test x$enable_nas_shared = xyes && test x$alsa_lib != x; then
    1.47 +                AC_DEFINE_UNQUOTED(SDL_AUDIO_DRIVER_NAS_DYNAMIC, "$nas_lib")
    1.48 +            else
    1.49 +                EXTRA_LDFLAGS="$EXTRA_LDFLAGS $NAS_LIBS"
    1.50 +            fi
    1.51 +
    1.52              AC_DEFINE(SDL_AUDIO_DRIVER_NAS)
    1.53              SOURCES="$SOURCES $srcdir/src/audio/nas/*.c"
    1.54              EXTRA_CFLAGS="$EXTRA_CFLAGS $NAS_CFLAGS"
    1.55 -            EXTRA_LDFLAGS="$EXTRA_LDFLAGS $NAS_LIBS"
    1.56              have_audio=yes
    1.57          fi
    1.58      fi
     2.1 --- a/include/SDL_config.h.in	Sat Oct 07 07:23:52 2006 +0000
     2.2 +++ b/include/SDL_config.h.in	Sat Oct 07 07:25:30 2006 +0000
     2.3 @@ -168,6 +168,7 @@
     2.4  #undef SDL_AUDIO_DRIVER_MINT
     2.5  #undef SDL_AUDIO_DRIVER_MMEAUDIO
     2.6  #undef SDL_AUDIO_DRIVER_NAS
     2.7 +#undef SDL_AUDIO_DRIVER_NAS_DYNAMIC
     2.8  #undef SDL_AUDIO_DRIVER_OSS
     2.9  #undef SDL_AUDIO_DRIVER_OSS_SOUNDCARD_H
    2.10  #undef SDL_AUDIO_DRIVER_PAUD
     3.1 --- a/src/audio/nas/SDL_nasaudio.c	Sat Oct 07 07:23:52 2006 +0000
     3.2 +++ b/src/audio/nas/SDL_nasaudio.c	Sat Oct 07 07:25:30 2006 +0000
     3.3 @@ -32,6 +32,7 @@
     3.4  
     3.5  #include "SDL_timer.h"
     3.6  #include "SDL_audio.h"
     3.7 +#include "SDL_loadso.h"
     3.8  #include "../SDL_audiomem.h"
     3.9  #include "../SDL_audio_c.h"
    3.10  #include "SDL_nasaudio.h"
    3.11 @@ -41,17 +42,128 @@
    3.12  
    3.13  static struct SDL_PrivateAudioData *this2 = NULL;
    3.14  
    3.15 -/* !!! FIXME: dynamic loading? */
    3.16 +
    3.17 +static void (*NAS_AuCloseServer)(AuServer *);
    3.18 +static void (*NAS_AuNextEvent)(AuServer *, AuBool, AuEvent *);
    3.19 +static AuBool (*NAS_AuDispatchEvent)(AuServer *, AuEvent *);
    3.20 +static AuFlowID (*NAS_AuCreateFlow)(AuServer *, AuStatus *);
    3.21 +static void (*NAS_AuStartFlow)(AuServer *, AuFlowID, AuStatus *);
    3.22 +static void (*NAS_AuSetElements)
    3.23 +    (AuServer *, AuFlowID, AuBool, int, AuElement *, AuStatus *);
    3.24 +static void (*NAS_AuWriteElement)
    3.25 +    (AuServer *, AuFlowID, int, AuUint32, AuPointer, AuBool, AuStatus *);
    3.26 +static AuServer *(*NAS_AuOpenServer)
    3.27 +    (_AuConst char *, int, _AuConst char *, int, _AuConst char *, char **);
    3.28 +static AuEventHandlerRec *(*NAS_AuRegisterEventHandler)
    3.29 +    (AuServer *, AuMask, int, AuID, AuEventHandlerCallback, AuPointer);
    3.30 +
    3.31 +
    3.32 +#ifdef SDL_AUDIO_DRIVER_NAS_DYNAMIC
    3.33 +
    3.34 +static const char *nas_library = SDL_AUDIO_DRIVER_NAS_DYNAMIC;
    3.35 +static void *nas_handle = NULL;
    3.36 +
    3.37 +static int
    3.38 +load_nas_sym(const char *fn, void **addr)
    3.39 +{
    3.40 +    *addr = SDL_LoadFunction(nas_handle, fn);
    3.41 +    if (*addr == NULL) {
    3.42 +        return 0;
    3.43 +    }
    3.44 +    return 1;
    3.45 +}
    3.46 +
    3.47 +/* cast funcs to char* first, to please GCC's strict aliasing rules. */
    3.48 +#define SDL_NAS_SYM(x) \
    3.49 +    if (!load_nas_sym(#x, (void **) (char *) &NAS_##x)) return -1
    3.50 +#else
    3.51 +#define SDL_NAS_SYM(x) NAS_##x = x
    3.52 +#endif
    3.53 +
    3.54 +static int load_nas_syms(void)
    3.55 +{
    3.56 +    SDL_NAS_SYM(AuCloseServer);
    3.57 +    SDL_NAS_SYM(AuNextEvent);
    3.58 +    SDL_NAS_SYM(AuDispatchEvent);
    3.59 +    SDL_NAS_SYM(AuCreateFlow);
    3.60 +    SDL_NAS_SYM(AuStartFlow);
    3.61 +    SDL_NAS_SYM(AuSetElements);
    3.62 +    SDL_NAS_SYM(AuWriteElement);
    3.63 +    SDL_NAS_SYM(AuOpenServer);
    3.64 +    SDL_NAS_SYM(AuRegisterEventHandler);
    3.65 +    return 0;
    3.66 +}
    3.67 +#undef SDL_NAS_SYM
    3.68 +
    3.69 +#ifdef SDL_AUDIO_DRIVER_NAS_DYNAMIC
    3.70 +
    3.71 +static int library_load_count = 0;
    3.72 +
    3.73 +static void
    3.74 +UnloadNASLibrary(void)
    3.75 +{
    3.76 +    if ((nas_handle != NULL) && (--library_load_count == 0)) {
    3.77 +        SDL_UnloadObject(nas_handle);
    3.78 +        nas_handle = NULL;
    3.79 +    }
    3.80 +}
    3.81 +
    3.82 +static int
    3.83 +LoadNASLibrary(void)
    3.84 +{
    3.85 +    int retval = 0;
    3.86 +    if (library_load_count++ == 0) {
    3.87 +        nas_handle = SDL_LoadObject(nas_library);
    3.88 +        if (nas_handle == NULL) {
    3.89 +            /* Copy error string so we can use it in a new SDL_SetError(). */
    3.90 +            char *origerr = SDL_GetError();
    3.91 +            size_t len = SDL_strlen(origerr) + 1;
    3.92 +            char *err = (char *) alloca(len);
    3.93 +            SDL_strlcpy(err, origerr, len);
    3.94 +
    3.95 +            library_load_count--;
    3.96 +            retval = -1;
    3.97 +            SDL_SetError("NAS: SDL_LoadObject('%s') failed: %s\n",
    3.98 +                          nas_library, err);
    3.99 +        } else {
   3.100 +            retval = load_nas_syms();
   3.101 +            if (retval < 0) {
   3.102 +                UnloadNASLibrary();
   3.103 +            }
   3.104 +        }
   3.105 +    }
   3.106 +    return retval;
   3.107 +}
   3.108 +
   3.109 +#else
   3.110 +
   3.111 +static void
   3.112 +UnloadNASLibrary(void)
   3.113 +{
   3.114 +}
   3.115 +
   3.116 +static int
   3.117 +LoadNASLibrary(void)
   3.118 +{
   3.119 +    load_nas_syms();
   3.120 +    return 0;
   3.121 +}
   3.122 +
   3.123 +#endif /* SDL_AUDIO_DRIVER_NAS_DYNAMIC */
   3.124  
   3.125  static int
   3.126  NAS_Available(void)
   3.127  {
   3.128 -    AuServer *aud = AuOpenServer("", 0, NULL, 0, NULL, NULL);
   3.129 -    if (!aud)
   3.130 -        return 0;
   3.131 -
   3.132 -    AuCloseServer(aud);
   3.133 -    return 1;
   3.134 +    int available = 0;
   3.135 +    if (LoadNASLibrary() >= 0) {
   3.136 +        AuServer *aud = NAS_AuOpenServer("", 0, NULL, 0, NULL, NULL);
   3.137 +        if (aud != NULL) {
   3.138 +            available = 1;
   3.139 +            NAS_AuCloseServer(aud);
   3.140 +        }
   3.141 +        UnloadNASLibrary();
   3.142 +    }
   3.143 +    return available;
   3.144  }
   3.145  
   3.146  /* This function waits until it is possible to write a full sound buffer */
   3.147 @@ -60,8 +172,8 @@
   3.148  {
   3.149      while (this->hidden->buf_free < this->hidden->mixlen) {
   3.150          AuEvent ev;
   3.151 -        AuNextEvent(this->hidden->aud, AuTrue, &ev);
   3.152 -        AuDispatchEvent(this->hidden->aud, &ev);
   3.153 +        NAS_AuNextEvent(this->hidden->aud, AuTrue, &ev);
   3.154 +        NAS_AuDispatchEvent(this->hidden->aud, &ev);
   3.155      }
   3.156  }
   3.157  
   3.158 @@ -75,13 +187,13 @@
   3.159           *  of the buffer is free now than what we think.
   3.160           */
   3.161          AuEvent ev;
   3.162 -        AuNextEvent(this->hidden->aud, AuTrue, &ev);
   3.163 -        AuDispatchEvent(this->hidden->aud, &ev);
   3.164 +        NAS_AuNextEvent(this->hidden->aud, AuTrue, &ev);
   3.165 +        NAS_AuDispatchEvent(this->hidden->aud, &ev);
   3.166      }
   3.167      this->hidden->buf_free -= this->hidden->mixlen;
   3.168  
   3.169      /* Write the audio data */
   3.170 -    AuWriteElement(this->hidden->aud, this->hidden->flow, 0,
   3.171 +    NAS_AuWriteElement(this->hidden->aud, this->hidden->flow, 0,
   3.172                     this->hidden->mixlen, this->hidden->mixbuf, AuFalse, NULL);
   3.173  
   3.174      this->hidden->written += this->hidden->mixlen;
   3.175 @@ -106,11 +218,12 @@
   3.176              this->hidden->mixbuf = NULL;
   3.177          }
   3.178          if (this->hidden->aud) {
   3.179 -            AuCloseServer(this->hidden->aud);
   3.180 +            NAS_AuCloseServer(this->hidden->aud);
   3.181              this->hidden->aud = 0;
   3.182          }
   3.183          SDL_free(this->hidden);
   3.184          this2 = this->hidden = NULL;
   3.185 +        UnloadNASLibrary();
   3.186      }
   3.187  }
   3.188  
   3.189 @@ -175,6 +288,7 @@
   3.190  static AuDeviceID
   3.191  find_device(_THIS, int nch)
   3.192  {
   3.193 +    /* These "Au" things are all macros, not functions... */
   3.194      int i;
   3.195      for (i = 0; i < AuServerNumDevices(this->hidden->aud); i++) {
   3.196          if ((AuDeviceKind(AuServerDevice(this->hidden->aud, i)) ==
   3.197 @@ -202,6 +316,11 @@
   3.198      }
   3.199      SDL_memset(this->hidden, 0, (sizeof *this->hidden));
   3.200  
   3.201 +    if (LoadNASLibrary() < 0) {
   3.202 +        NAS_CloseDevice(this);
   3.203 +        return 0;
   3.204 +    }
   3.205 +
   3.206      /* Try for a closest match on audio format */
   3.207      format = 0;
   3.208      for (test_format = SDL_FirstAudioFormat(this->spec.format);
   3.209 @@ -218,7 +337,7 @@
   3.210      }
   3.211      this->spec.format = test_format;
   3.212  
   3.213 -    this->hidden->aud = AuOpenServer("", 0, NULL, 0, NULL, NULL);
   3.214 +    this->hidden->aud = NAS_AuOpenServer("", 0, NULL, 0, NULL, NULL);
   3.215      if (this->hidden->aud == 0) {
   3.216          NAS_CloseDevice(this);
   3.217          SDL_SetError("NAS: Couldn't open connection to NAS server");
   3.218 @@ -227,7 +346,7 @@
   3.219  
   3.220      this->hidden->dev = find_device(this, this->spec.channels);
   3.221      if ((this->hidden->dev == AuNone)
   3.222 -        || (!(this->hidden->flow = AuCreateFlow(this->hidden->aud, NULL)))) {
   3.223 +        || (!(this->hidden->flow = NAS_AuCreateFlow(this->hidden->aud, 0)))) {
   3.224          NAS_CloseDevice(this);
   3.225          SDL_SetError("NAS: Couldn't find a fitting device on NAS server");
   3.226          return 0;
   3.227 @@ -249,12 +368,13 @@
   3.228                                AuTrue, buffer_size, buffer_size / 4, 0, NULL);
   3.229      AuMakeElementExportDevice(elms + 1, 0, this->hidden->dev, this->spec.freq,
   3.230                                AuUnlimitedSamples, 0, NULL);
   3.231 -    AuSetElements(this->hidden->aud, this->hidden->flow, AuTrue, 2, elms, NULL);
   3.232 -    AuRegisterEventHandler(this->hidden->aud, AuEventHandlerIDMask, 0,
   3.233 -                           this->hidden->flow, event_handler,
   3.234 -                           (AuPointer) NULL);
   3.235 +    NAS_AuSetElements(this->hidden->aud, this->hidden->flow,
   3.236 +                      AuTrue, 2, elms, NULL);
   3.237 +    NAS_AuRegisterEventHandler(this->hidden->aud, AuEventHandlerIDMask, 0,
   3.238 +                               this->hidden->flow, event_handler,
   3.239 +                               (AuPointer) NULL);
   3.240  
   3.241 -    AuStartFlow(this->hidden->aud, this->hidden->flow, NULL);
   3.242 +    NAS_AuStartFlow(this->hidden->aud, this->hidden->flow, NULL);
   3.243  
   3.244      /* Allocate mixing buffer */
   3.245      this->hidden->mixlen = this->spec.size;
   3.246 @@ -262,7 +382,7 @@
   3.247      if (this->hidden->mixbuf == NULL) {
   3.248          NAS_CloseDevice(this);
   3.249          SDL_OutOfMemory();
   3.250 -        return (-1);
   3.251 +        return 0;
   3.252      }
   3.253      SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
   3.254