1.1 --- a/src/audio/nas/SDL_nasaudio.c Sat Sep 12 19:41:54 2009 +0000
1.2 +++ b/src/audio/nas/SDL_nasaudio.c Sun Sep 13 22:19:56 2009 +0000
1.3 @@ -37,11 +37,122 @@
1.4 #include "../SDL_audiodev_c.h"
1.5 #include "SDL_nasaudio.h"
1.6
1.7 +#ifdef SDL_AUDIO_DRIVER_NAS_DYNAMIC
1.8 +#include "SDL_loadso.h"
1.9 +#endif
1.10 +
1.11 /* The tag name used by artsc audio */
1.12 #define NAS_DRIVER_NAME "nas"
1.13
1.14 static struct SDL_PrivateAudioData *this2 = NULL;
1.15
1.16 +static void (*NAS_AuCloseServer) (AuServer *);
1.17 +static void (*NAS_AuNextEvent) (AuServer *, AuBool, AuEvent *);
1.18 +static AuBool(*NAS_AuDispatchEvent) (AuServer *, AuEvent *);
1.19 +static AuFlowID(*NAS_AuCreateFlow) (AuServer *, AuStatus *);
1.20 +static void (*NAS_AuStartFlow) (AuServer *, AuFlowID, AuStatus *);
1.21 +static void (*NAS_AuSetElements)
1.22 + (AuServer *, AuFlowID, AuBool, int, AuElement *, AuStatus *);
1.23 +static void (*NAS_AuWriteElement)
1.24 + (AuServer *, AuFlowID, int, AuUint32, AuPointer, AuBool, AuStatus *);
1.25 +static AuServer *(*NAS_AuOpenServer)
1.26 + (_AuConst char *, int, _AuConst char *, int, _AuConst char *, char **);
1.27 +static AuEventHandlerRec *(*NAS_AuRegisterEventHandler)
1.28 + (AuServer *, AuMask, int, AuID, AuEventHandlerCallback, AuPointer);
1.29 +
1.30 +
1.31 +#ifdef SDL_AUDIO_DRIVER_NAS_DYNAMIC
1.32 +
1.33 +static const char *nas_library = SDL_AUDIO_DRIVER_NAS_DYNAMIC;
1.34 +static void *nas_handle = NULL;
1.35 +
1.36 +static int
1.37 +load_nas_sym(const char *fn, void **addr)
1.38 +{
1.39 + *addr = SDL_LoadFunction(nas_handle, fn);
1.40 + if (*addr == NULL) {
1.41 + return 0;
1.42 + }
1.43 + return 1;
1.44 +}
1.45 +
1.46 +/* cast funcs to char* first, to please GCC's strict aliasing rules. */
1.47 +#define SDL_NAS_SYM(x) \
1.48 + if (!load_nas_sym(#x, (void **) (char *) &NAS_##x)) return -1
1.49 +#else
1.50 +#define SDL_NAS_SYM(x) NAS_##x = x
1.51 +#endif
1.52 +
1.53 +static int
1.54 +load_nas_syms(void)
1.55 +{
1.56 + SDL_NAS_SYM(AuCloseServer);
1.57 + SDL_NAS_SYM(AuNextEvent);
1.58 + SDL_NAS_SYM(AuDispatchEvent);
1.59 + SDL_NAS_SYM(AuCreateFlow);
1.60 + SDL_NAS_SYM(AuStartFlow);
1.61 + SDL_NAS_SYM(AuSetElements);
1.62 + SDL_NAS_SYM(AuWriteElement);
1.63 + SDL_NAS_SYM(AuOpenServer);
1.64 + SDL_NAS_SYM(AuRegisterEventHandler);
1.65 + return 0;
1.66 +}
1.67 +
1.68 +#undef SDL_NAS_SYM
1.69 +
1.70 +#ifdef SDL_AUDIO_DRIVER_NAS_DYNAMIC
1.71 +
1.72 +static void
1.73 +UnloadNASLibrary(void)
1.74 +{
1.75 + if (nas_handle != NULL) {
1.76 + SDL_UnloadObject(nas_handle);
1.77 + nas_handle = NULL;
1.78 + }
1.79 +}
1.80 +
1.81 +static int
1.82 +LoadNASLibrary(void)
1.83 +{
1.84 + int retval = 0;
1.85 + if (nas_handle == NULL) {
1.86 + nas_handle = SDL_LoadObject(nas_library);
1.87 + if (nas_handle == NULL) {
1.88 + /* Copy error string so we can use it in a new SDL_SetError(). */
1.89 + char *origerr = SDL_GetError();
1.90 + size_t len = SDL_strlen(origerr) + 1;
1.91 + char *err = (char *) alloca(len);
1.92 + SDL_strlcpy(err, origerr, len);
1.93 + retval = -1;
1.94 + SDL_SetError("NAS: SDL_LoadObject('%s') failed: %s\n",
1.95 + nas_library, err);
1.96 + } else {
1.97 + retval = load_nas_syms();
1.98 + if (retval < 0) {
1.99 + UnloadNASLibrary();
1.100 + }
1.101 + }
1.102 + }
1.103 + return retval;
1.104 +}
1.105 +
1.106 +#else
1.107 +
1.108 +static void
1.109 +UnloadNASLibrary(void)
1.110 +{
1.111 +}
1.112 +
1.113 +static int
1.114 +LoadNASLibrary(void)
1.115 +{
1.116 + load_nas_syms();
1.117 + return 0;
1.118 +}
1.119 +
1.120 +#endif /* SDL_AUDIO_DRIVER_NAS_DYNAMIC */
1.121 +
1.122 +
1.123 /* Audio driver functions */
1.124 static int NAS_OpenAudio(_THIS, SDL_AudioSpec *spec);
1.125 static void NAS_WaitAudio(_THIS);
1.126 @@ -53,15 +164,22 @@
1.127
1.128 static int Audio_Available(void)
1.129 {
1.130 - AuServer *aud = AuOpenServer("", 0, NULL, 0, NULL, NULL);
1.131 - if (!aud) return 0;
1.132 -
1.133 - AuCloseServer(aud);
1.134 - return 1;
1.135 + if (LoadNASLibrary() == 0) {
1.136 + AuServer *aud = NAS_AuOpenServer("", 0, NULL, 0, NULL, NULL);
1.137 + if (!aud) {
1.138 + UnloadNASLibrary();
1.139 + return 0;
1.140 + }
1.141 + NAS_AuCloseServer(aud);
1.142 + UnloadNASLibrary();
1.143 + return 1;
1.144 + }
1.145 + return 0;
1.146 }
1.147
1.148 static void Audio_DeleteDevice(SDL_AudioDevice *device)
1.149 {
1.150 + UnloadNASLibrary();
1.151 SDL_free(device->hidden);
1.152 SDL_free(device);
1.153 }
1.154 @@ -70,6 +188,10 @@
1.155 {
1.156 SDL_AudioDevice *this;
1.157
1.158 + if (LoadNASLibrary() < 0) {
1.159 + return NULL;
1.160 + }
1.161 +
1.162 /* Initialize all variables that we clean on shutdown */
1.163 this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
1.164 if ( this ) {
1.165 @@ -82,7 +204,7 @@
1.166 if ( this ) {
1.167 SDL_free(this);
1.168 }
1.169 - return(0);
1.170 + return NULL;
1.171 }
1.172 SDL_memset(this->hidden, 0, (sizeof *this->hidden));
1.173
1.174 @@ -108,8 +230,8 @@
1.175 {
1.176 while ( this->hidden->buf_free < this->hidden->mixlen ) {
1.177 AuEvent ev;
1.178 - AuNextEvent(this->hidden->aud, AuTrue, &ev);
1.179 - AuDispatchEvent(this->hidden->aud, &ev);
1.180 + NAS_AuNextEvent(this->hidden->aud, AuTrue, &ev);
1.181 + NAS_AuDispatchEvent(this->hidden->aud, &ev);
1.182 }
1.183 }
1.184
1.185 @@ -119,13 +241,13 @@
1.186 in the hope that some of them is LowWater events telling us more
1.187 of the buffer is free now than what we think. */
1.188 AuEvent ev;
1.189 - AuNextEvent(this->hidden->aud, AuTrue, &ev);
1.190 - AuDispatchEvent(this->hidden->aud, &ev);
1.191 + NAS_AuNextEvent(this->hidden->aud, AuTrue, &ev);
1.192 + NAS_AuDispatchEvent(this->hidden->aud, &ev);
1.193 }
1.194 this->hidden->buf_free -= this->hidden->mixlen;
1.195
1.196 /* Write the audio data */
1.197 - AuWriteElement(this->hidden->aud, this->hidden->flow, 0, this->hidden->mixlen, this->hidden->mixbuf, AuFalse, NULL);
1.198 + NAS_AuWriteElement(this->hidden->aud, this->hidden->flow, 0, this->hidden->mixlen, this->hidden->mixbuf, AuFalse, NULL);
1.199
1.200 this->hidden->written += this->hidden->mixlen;
1.201
1.202 @@ -146,7 +268,7 @@
1.203 this->hidden->mixbuf = NULL;
1.204 }
1.205 if ( this->hidden->aud ) {
1.206 - AuCloseServer(this->hidden->aud);
1.207 + NAS_AuCloseServer(this->hidden->aud);
1.208 this->hidden->aud = 0;
1.209 }
1.210 }
1.211 @@ -211,6 +333,7 @@
1.212 static AuDeviceID
1.213 find_device(_THIS, int nch)
1.214 {
1.215 + /* These "Au" things are all macros, not functions... */
1.216 int i;
1.217 for (i = 0; i < AuServerNumDevices(this->hidden->aud); i++) {
1.218 if ((AuDeviceKind(AuServerDevice(this->hidden->aud, i)) ==
1.219 @@ -246,7 +369,7 @@
1.220 }
1.221 spec->format = test_format;
1.222
1.223 - this->hidden->aud = AuOpenServer("", 0, NULL, 0, NULL, NULL);
1.224 + this->hidden->aud = NAS_AuOpenServer("", 0, NULL, 0, NULL, NULL);
1.225 if (this->hidden->aud == 0)
1.226 {
1.227 SDL_SetError("Couldn't open connection to NAS server");
1.228 @@ -254,8 +377,8 @@
1.229 }
1.230
1.231 this->hidden->dev = find_device(this, spec->channels);
1.232 - if ((this->hidden->dev == AuNone) || (!(this->hidden->flow = AuCreateFlow(this->hidden->aud, NULL)))) {
1.233 - AuCloseServer(this->hidden->aud);
1.234 + if ((this->hidden->dev == AuNone) || (!(this->hidden->flow = NAS_AuCreateFlow(this->hidden->aud, NULL)))) {
1.235 + NAS_AuCloseServer(this->hidden->aud);
1.236 this->hidden->aud = 0;
1.237 SDL_SetError("Couldn't find a fitting playback device on NAS server");
1.238 return (-1);
1.239 @@ -273,15 +396,16 @@
1.240
1.241 this2 = this->hidden;
1.242
1.243 + /* These "Au" things without a NAS_ prefix are macros, not functions... */
1.244 AuMakeElementImportClient(elms, spec->freq, format, spec->channels, AuTrue,
1.245 buffer_size, buffer_size / 4, 0, NULL);
1.246 AuMakeElementExportDevice(elms+1, 0, this->hidden->dev, spec->freq,
1.247 AuUnlimitedSamples, 0, NULL);
1.248 - AuSetElements(this->hidden->aud, this->hidden->flow, AuTrue, 2, elms, NULL);
1.249 - AuRegisterEventHandler(this->hidden->aud, AuEventHandlerIDMask, 0, this->hidden->flow,
1.250 + NAS_AuSetElements(this->hidden->aud, this->hidden->flow, AuTrue, 2, elms, NULL);
1.251 + NAS_AuRegisterEventHandler(this->hidden->aud, AuEventHandlerIDMask, 0, this->hidden->flow,
1.252 event_handler, (AuPointer) NULL);
1.253
1.254 - AuStartFlow(this->hidden->aud, this->hidden->flow, NULL);
1.255 + NAS_AuStartFlow(this->hidden->aud, this->hidden->flow, NULL);
1.256
1.257 /* Allocate mixing buffer */
1.258 this->hidden->mixlen = spec->size;