1.1 --- a/src/audio/nas/SDL_nasaudio.c Sun Oct 01 16:10:41 2006 +0000
1.2 +++ b/src/audio/nas/SDL_nasaudio.c Tue Oct 17 09:15:21 2006 +0000
1.3 @@ -32,106 +32,149 @@
1.4
1.5 #include "SDL_timer.h"
1.6 #include "SDL_audio.h"
1.7 +#include "SDL_loadso.h"
1.8 #include "../SDL_audiomem.h"
1.9 #include "../SDL_audio_c.h"
1.10 -#include "../SDL_audiodev_c.h"
1.11 #include "SDL_nasaudio.h"
1.12
1.13 -/* The tag name used by artsc audio */
1.14 +/* The tag name used by nas audio */
1.15 #define NAS_DRIVER_NAME "nas"
1.16
1.17 static struct SDL_PrivateAudioData *this2 = NULL;
1.18
1.19 -/* Audio driver functions */
1.20 -static int NAS_OpenAudio(_THIS, SDL_AudioSpec * spec);
1.21 -static void NAS_WaitAudio(_THIS);
1.22 -static void NAS_PlayAudio(_THIS);
1.23 -static Uint8 *NAS_GetAudioBuf(_THIS);
1.24 -static void NAS_CloseAudio(_THIS);
1.25
1.26 -/* Audio driver bootstrap functions */
1.27 +static void (*NAS_AuCloseServer)(AuServer *);
1.28 +static void (*NAS_AuNextEvent)(AuServer *, AuBool, AuEvent *);
1.29 +static AuBool (*NAS_AuDispatchEvent)(AuServer *, AuEvent *);
1.30 +static AuFlowID (*NAS_AuCreateFlow)(AuServer *, AuStatus *);
1.31 +static void (*NAS_AuStartFlow)(AuServer *, AuFlowID, AuStatus *);
1.32 +static void (*NAS_AuSetElements)
1.33 + (AuServer *, AuFlowID, AuBool, int, AuElement *, AuStatus *);
1.34 +static void (*NAS_AuWriteElement)
1.35 + (AuServer *, AuFlowID, int, AuUint32, AuPointer, AuBool, AuStatus *);
1.36 +static AuServer *(*NAS_AuOpenServer)
1.37 + (_AuConst char *, int, _AuConst char *, int, _AuConst char *, char **);
1.38 +static AuEventHandlerRec *(*NAS_AuRegisterEventHandler)
1.39 + (AuServer *, AuMask, int, AuID, AuEventHandlerCallback, AuPointer);
1.40 +
1.41 +
1.42 +#ifdef SDL_AUDIO_DRIVER_NAS_DYNAMIC
1.43 +
1.44 +static const char *nas_library = SDL_AUDIO_DRIVER_NAS_DYNAMIC;
1.45 +static void *nas_handle = NULL;
1.46
1.47 static int
1.48 -Audio_Available(void)
1.49 +load_nas_sym(const char *fn, void **addr)
1.50 {
1.51 - AuServer *aud = AuOpenServer("", 0, NULL, 0, NULL, NULL);
1.52 - if (!aud)
1.53 + *addr = SDL_LoadFunction(nas_handle, fn);
1.54 + if (*addr == NULL) {
1.55 return 0;
1.56 -
1.57 - AuCloseServer(aud);
1.58 + }
1.59 return 1;
1.60 }
1.61
1.62 -static void
1.63 -Audio_DeleteDevice(SDL_AudioDevice * device)
1.64 +/* cast funcs to char* first, to please GCC's strict aliasing rules. */
1.65 +#define SDL_NAS_SYM(x) \
1.66 + if (!load_nas_sym(#x, (void **) (char *) &NAS_##x)) return -1
1.67 +#else
1.68 +#define SDL_NAS_SYM(x) NAS_##x = x
1.69 +#endif
1.70 +
1.71 +static int load_nas_syms(void)
1.72 {
1.73 - SDL_free(device->hidden);
1.74 - SDL_free(device);
1.75 + SDL_NAS_SYM(AuCloseServer);
1.76 + SDL_NAS_SYM(AuNextEvent);
1.77 + SDL_NAS_SYM(AuDispatchEvent);
1.78 + SDL_NAS_SYM(AuCreateFlow);
1.79 + SDL_NAS_SYM(AuStartFlow);
1.80 + SDL_NAS_SYM(AuSetElements);
1.81 + SDL_NAS_SYM(AuWriteElement);
1.82 + SDL_NAS_SYM(AuOpenServer);
1.83 + SDL_NAS_SYM(AuRegisterEventHandler);
1.84 + return 0;
1.85 +}
1.86 +#undef SDL_NAS_SYM
1.87 +
1.88 +#ifdef SDL_AUDIO_DRIVER_NAS_DYNAMIC
1.89 +
1.90 +static void
1.91 +UnloadNASLibrary(void)
1.92 +{
1.93 + if (nas_handle != NULL) {
1.94 + SDL_UnloadObject(nas_handle);
1.95 + nas_handle = NULL;
1.96 + }
1.97 }
1.98
1.99 -static SDL_AudioDevice *
1.100 -Audio_CreateDevice(int devindex)
1.101 +static int
1.102 +LoadNASLibrary(void)
1.103 {
1.104 - SDL_AudioDevice *this;
1.105 -
1.106 - /* Initialize all variables that we clean on shutdown */
1.107 - this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
1.108 - if (this) {
1.109 - SDL_memset(this, 0, (sizeof *this));
1.110 - this->hidden = (struct SDL_PrivateAudioData *)
1.111 - SDL_malloc((sizeof *this->hidden));
1.112 + int retval = 0;
1.113 + if (nas_handle == NULL) {
1.114 + nas_handle = SDL_LoadObject(nas_library);
1.115 + if (nas_handle == NULL) {
1.116 + /* Copy error string so we can use it in a new SDL_SetError(). */
1.117 + char *origerr = SDL_GetError();
1.118 + size_t len = SDL_strlen(origerr) + 1;
1.119 + char *err = (char *) alloca(len);
1.120 + SDL_strlcpy(err, origerr, len);
1.121 + retval = -1;
1.122 + SDL_SetError("NAS: SDL_LoadObject('%s') failed: %s\n",
1.123 + nas_library, err);
1.124 + } else {
1.125 + retval = load_nas_syms();
1.126 + if (retval < 0) {
1.127 + UnloadNASLibrary();
1.128 + }
1.129 + }
1.130 }
1.131 - if ((this == NULL) || (this->hidden == NULL)) {
1.132 - SDL_OutOfMemory();
1.133 - if (this) {
1.134 - SDL_free(this);
1.135 - }
1.136 - return (0);
1.137 - }
1.138 - SDL_memset(this->hidden, 0, (sizeof *this->hidden));
1.139 -
1.140 - /* Set the function pointers */
1.141 - this->OpenAudio = NAS_OpenAudio;
1.142 - this->WaitAudio = NAS_WaitAudio;
1.143 - this->PlayAudio = NAS_PlayAudio;
1.144 - this->GetAudioBuf = NAS_GetAudioBuf;
1.145 - this->CloseAudio = NAS_CloseAudio;
1.146 -
1.147 - this->free = Audio_DeleteDevice;
1.148 -
1.149 - return this;
1.150 + return retval;
1.151 }
1.152
1.153 -AudioBootStrap NAS_bootstrap = {
1.154 - NAS_DRIVER_NAME, "Network Audio System",
1.155 - Audio_Available, Audio_CreateDevice
1.156 -};
1.157 +#else
1.158 +
1.159 +static void
1.160 +UnloadNASLibrary(void)
1.161 +{
1.162 +}
1.163 +
1.164 +static int
1.165 +LoadNASLibrary(void)
1.166 +{
1.167 + load_nas_syms();
1.168 + return 0;
1.169 +}
1.170 +
1.171 +#endif /* SDL_AUDIO_DRIVER_NAS_DYNAMIC */
1.172
1.173 /* This function waits until it is possible to write a full sound buffer */
1.174 static void
1.175 -NAS_WaitAudio(_THIS)
1.176 +NAS_WaitDevice(_THIS)
1.177 {
1.178 while (this->hidden->buf_free < this->hidden->mixlen) {
1.179 AuEvent ev;
1.180 - AuNextEvent(this->hidden->aud, AuTrue, &ev);
1.181 - AuDispatchEvent(this->hidden->aud, &ev);
1.182 + NAS_AuNextEvent(this->hidden->aud, AuTrue, &ev);
1.183 + NAS_AuDispatchEvent(this->hidden->aud, &ev);
1.184 }
1.185 }
1.186
1.187 static void
1.188 -NAS_PlayAudio(_THIS)
1.189 +NAS_PlayDevice(_THIS)
1.190 {
1.191 - while (this->hidden->mixlen > this->hidden->buf_free) { /* We think the buffer is full? Yikes! Ask the server for events,
1.192 - in the hope that some of them is LowWater events telling us more
1.193 - of the buffer is free now than what we think. */
1.194 + while (this->hidden->mixlen > this->hidden->buf_free) {
1.195 + /*
1.196 + * We think the buffer is full? Yikes! Ask the server for events,
1.197 + * in the hope that some of them is LowWater events telling us more
1.198 + * of the buffer is free now than what we think.
1.199 + */
1.200 AuEvent ev;
1.201 - AuNextEvent(this->hidden->aud, AuTrue, &ev);
1.202 - AuDispatchEvent(this->hidden->aud, &ev);
1.203 + NAS_AuNextEvent(this->hidden->aud, AuTrue, &ev);
1.204 + NAS_AuDispatchEvent(this->hidden->aud, &ev);
1.205 }
1.206 this->hidden->buf_free -= this->hidden->mixlen;
1.207
1.208 /* Write the audio data */
1.209 - AuWriteElement(this->hidden->aud, this->hidden->flow, 0,
1.210 + NAS_AuWriteElement(this->hidden->aud, this->hidden->flow, 0,
1.211 this->hidden->mixlen, this->hidden->mixbuf, AuFalse, NULL);
1.212
1.213 this->hidden->written += this->hidden->mixlen;
1.214 @@ -142,21 +185,25 @@
1.215 }
1.216
1.217 static Uint8 *
1.218 -NAS_GetAudioBuf(_THIS)
1.219 +NAS_GetDeviceBuf(_THIS)
1.220 {
1.221 return (this->hidden->mixbuf);
1.222 }
1.223
1.224 static void
1.225 -NAS_CloseAudio(_THIS)
1.226 +NAS_CloseDevice(_THIS)
1.227 {
1.228 - if (this->hidden->mixbuf != NULL) {
1.229 - SDL_FreeAudioMem(this->hidden->mixbuf);
1.230 - this->hidden->mixbuf = NULL;
1.231 - }
1.232 - if (this->hidden->aud) {
1.233 - AuCloseServer(this->hidden->aud);
1.234 - this->hidden->aud = 0;
1.235 + if (this->hidden != NULL) {
1.236 + if (this->hidden->mixbuf != NULL) {
1.237 + SDL_FreeAudioMem(this->hidden->mixbuf);
1.238 + this->hidden->mixbuf = NULL;
1.239 + }
1.240 + if (this->hidden->aud) {
1.241 + NAS_AuCloseServer(this->hidden->aud);
1.242 + this->hidden->aud = 0;
1.243 + }
1.244 + SDL_free(this->hidden);
1.245 + this2 = this->hidden = NULL;
1.246 }
1.247 }
1.248
1.249 @@ -221,6 +268,7 @@
1.250 static AuDeviceID
1.251 find_device(_THIS, int nch)
1.252 {
1.253 + /* These "Au" things are all macros, not functions... */
1.254 int i;
1.255 for (i = 0; i < AuServerNumDevices(this->hidden->aud); i++) {
1.256 if ((AuDeviceKind(AuServerDevice(this->hidden->aud, i)) ==
1.257 @@ -233,46 +281,53 @@
1.258 }
1.259
1.260 static int
1.261 -NAS_OpenAudio(_THIS, SDL_AudioSpec * spec)
1.262 +NAS_OpenDevice(_THIS, const char *devname, int iscapture)
1.263 {
1.264 AuElement elms[3];
1.265 int buffer_size;
1.266 SDL_AudioFormat test_format, format;
1.267
1.268 - this->hidden->mixbuf = NULL;
1.269 + /* Initialize all variables that we clean on shutdown */
1.270 + this->hidden = (struct SDL_PrivateAudioData *)
1.271 + SDL_malloc((sizeof *this->hidden));
1.272 + if (this->hidden == NULL) {
1.273 + SDL_OutOfMemory();
1.274 + return 0;
1.275 + }
1.276 + SDL_memset(this->hidden, 0, (sizeof *this->hidden));
1.277
1.278 /* Try for a closest match on audio format */
1.279 format = 0;
1.280 - for (test_format = SDL_FirstAudioFormat(spec->format);
1.281 + for (test_format = SDL_FirstAudioFormat(this->spec.format);
1.282 !format && test_format;) {
1.283 format = sdlformat_to_auformat(test_format);
1.284 -
1.285 if (format == AuNone) {
1.286 test_format = SDL_NextAudioFormat();
1.287 }
1.288 }
1.289 if (format == 0) {
1.290 - SDL_SetError("Couldn't find any hardware audio formats");
1.291 - return (-1);
1.292 + NAS_CloseDevice(this);
1.293 + SDL_SetError("NAS: Couldn't find any hardware audio formats");
1.294 + return 0;
1.295 }
1.296 - spec->format = test_format;
1.297 + this->spec.format = test_format;
1.298
1.299 - this->hidden->aud = AuOpenServer("", 0, NULL, 0, NULL, NULL);
1.300 + this->hidden->aud = NAS_AuOpenServer("", 0, NULL, 0, NULL, NULL);
1.301 if (this->hidden->aud == 0) {
1.302 - SDL_SetError("Couldn't open connection to NAS server");
1.303 - return (-1);
1.304 + NAS_CloseDevice(this);
1.305 + SDL_SetError("NAS: Couldn't open connection to NAS server");
1.306 + return 0;
1.307 }
1.308
1.309 - this->hidden->dev = find_device(this, spec->channels);
1.310 + this->hidden->dev = find_device(this, this->spec.channels);
1.311 if ((this->hidden->dev == AuNone)
1.312 - || (!(this->hidden->flow = AuCreateFlow(this->hidden->aud, NULL)))) {
1.313 - AuCloseServer(this->hidden->aud);
1.314 - this->hidden->aud = 0;
1.315 - SDL_SetError("Couldn't find a fitting playback device on NAS server");
1.316 - return (-1);
1.317 + || (!(this->hidden->flow = NAS_AuCreateFlow(this->hidden->aud, 0)))) {
1.318 + NAS_CloseDevice(this);
1.319 + SDL_SetError("NAS: Couldn't find a fitting device on NAS server");
1.320 + return 0;
1.321 }
1.322
1.323 - buffer_size = spec->freq;
1.324 + buffer_size = this->spec.freq;
1.325 if (buffer_size < 4096)
1.326 buffer_size = 4096;
1.327
1.328 @@ -280,35 +335,70 @@
1.329 buffer_size = 32768; /* So that the buffer won't get unmanageably big. */
1.330
1.331 /* Calculate the final parameters for this audio specification */
1.332 - SDL_CalculateAudioSpec(spec);
1.333 + SDL_CalculateAudioSpec(&this->spec);
1.334
1.335 this2 = this->hidden;
1.336
1.337 - AuMakeElementImportClient(elms, spec->freq, format, spec->channels,
1.338 + AuMakeElementImportClient(elms,this->spec.freq,format,this->spec.channels,
1.339 AuTrue, buffer_size, buffer_size / 4, 0, NULL);
1.340 - AuMakeElementExportDevice(elms + 1, 0, this->hidden->dev, spec->freq,
1.341 + AuMakeElementExportDevice(elms + 1, 0, this->hidden->dev, this->spec.freq,
1.342 AuUnlimitedSamples, 0, NULL);
1.343 - AuSetElements(this->hidden->aud, this->hidden->flow, AuTrue, 2, elms,
1.344 - NULL);
1.345 - AuRegisterEventHandler(this->hidden->aud, AuEventHandlerIDMask, 0,
1.346 - this->hidden->flow, event_handler,
1.347 - (AuPointer) NULL);
1.348 + NAS_AuSetElements(this->hidden->aud, this->hidden->flow,
1.349 + AuTrue, 2, elms, NULL);
1.350 + NAS_AuRegisterEventHandler(this->hidden->aud, AuEventHandlerIDMask, 0,
1.351 + this->hidden->flow, event_handler,
1.352 + (AuPointer) NULL);
1.353
1.354 - AuStartFlow(this->hidden->aud, this->hidden->flow, NULL);
1.355 + NAS_AuStartFlow(this->hidden->aud, this->hidden->flow, NULL);
1.356
1.357 /* Allocate mixing buffer */
1.358 - this->hidden->mixlen = spec->size;
1.359 + this->hidden->mixlen = this->spec.size;
1.360 this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
1.361 if (this->hidden->mixbuf == NULL) {
1.362 - return (-1);
1.363 + NAS_CloseDevice(this);
1.364 + SDL_OutOfMemory();
1.365 + return 0;
1.366 }
1.367 - SDL_memset(this->hidden->mixbuf, spec->silence, spec->size);
1.368 -
1.369 - /* Get the parent process id (we're the parent of the audio thread) */
1.370 - this->hidden->parent = getpid();
1.371 + SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
1.372
1.373 /* We're ready to rock and roll. :-) */
1.374 - return (0);
1.375 + return 1;
1.376 +}
1.377 +
1.378 +static void
1.379 +NAS_Deinitialize(void)
1.380 +{
1.381 + UnloadNASLibrary();
1.382 }
1.383
1.384 +static int
1.385 +NAS_Init(SDL_AudioDriverImpl *impl)
1.386 +{
1.387 + if (LoadNASLibrary() < 0) {
1.388 + return 0;
1.389 + } else {
1.390 + AuServer *aud = NAS_AuOpenServer("", 0, NULL, 0, NULL, NULL);
1.391 + if (aud == NULL) {
1.392 + SDL_SetError("NAS: AuOpenServer() failed (no audio server?)");
1.393 + return 0;
1.394 + }
1.395 + NAS_AuCloseServer(aud);
1.396 + }
1.397 +
1.398 + /* Set the function pointers */
1.399 + impl->OpenDevice = NAS_OpenDevice;
1.400 + impl->PlayDevice = NAS_PlayDevice;
1.401 + impl->WaitDevice = NAS_WaitDevice;
1.402 + impl->GetDeviceBuf = NAS_GetDeviceBuf;
1.403 + impl->CloseDevice = NAS_CloseDevice;
1.404 + impl->Deinitialize = NAS_Deinitialize;
1.405 + impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: is this true? */
1.406 +
1.407 + return 1;
1.408 +}
1.409 +
1.410 +AudioBootStrap NAS_bootstrap = {
1.411 + NAS_DRIVER_NAME, "Network Audio System", NAS_Init, 0
1.412 +};
1.413 +
1.414 /* vi: set ts=4 sw=4 expandtab: */