Mercurial > sdl-ios-xcode
diff src/audio/nas/SDL_nasaudio.c @ 2049:5f6550e5184f
Merged SDL-ryan-multiple-audio-device branch r2803:2871 into the trunk.
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Tue, 17 Oct 2006 09:15:21 +0000 |
parents | 3b4ce57c6215 |
children | 866052b01ee5 |
line wrap: on
line diff
--- a/src/audio/nas/SDL_nasaudio.c Sun Oct 01 16:10:41 2006 +0000 +++ b/src/audio/nas/SDL_nasaudio.c Tue Oct 17 09:15:21 2006 +0000 @@ -32,106 +32,149 @@ #include "SDL_timer.h" #include "SDL_audio.h" +#include "SDL_loadso.h" #include "../SDL_audiomem.h" #include "../SDL_audio_c.h" -#include "../SDL_audiodev_c.h" #include "SDL_nasaudio.h" -/* The tag name used by artsc audio */ +/* The tag name used by nas audio */ #define NAS_DRIVER_NAME "nas" static struct SDL_PrivateAudioData *this2 = NULL; -/* Audio driver functions */ -static int NAS_OpenAudio(_THIS, SDL_AudioSpec * spec); -static void NAS_WaitAudio(_THIS); -static void NAS_PlayAudio(_THIS); -static Uint8 *NAS_GetAudioBuf(_THIS); -static void NAS_CloseAudio(_THIS); -/* Audio driver bootstrap functions */ +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 -Audio_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; } -static void -Audio_DeleteDevice(SDL_AudioDevice * device) +/* 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_free(device->hidden); - SDL_free(device); + 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 void +UnloadNASLibrary(void) +{ + if (nas_handle != NULL) { + SDL_UnloadObject(nas_handle); + nas_handle = NULL; + } } -static SDL_AudioDevice * -Audio_CreateDevice(int devindex) +static int +LoadNASLibrary(void) { - SDL_AudioDevice *this; - - /* Initialize all variables that we clean on shutdown */ - this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice)); - if (this) { - SDL_memset(this, 0, (sizeof *this)); - this->hidden = (struct SDL_PrivateAudioData *) - SDL_malloc((sizeof *this->hidden)); + int retval = 0; + if (nas_handle == NULL) { + 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); + retval = -1; + SDL_SetError("NAS: SDL_LoadObject('%s') failed: %s\n", + nas_library, err); + } else { + retval = load_nas_syms(); + if (retval < 0) { + UnloadNASLibrary(); + } + } } - if ((this == NULL) || (this->hidden == NULL)) { - SDL_OutOfMemory(); - if (this) { - SDL_free(this); - } - return (0); - } - SDL_memset(this->hidden, 0, (sizeof *this->hidden)); - - /* Set the function pointers */ - this->OpenAudio = NAS_OpenAudio; - this->WaitAudio = NAS_WaitAudio; - this->PlayAudio = NAS_PlayAudio; - this->GetAudioBuf = NAS_GetAudioBuf; - this->CloseAudio = NAS_CloseAudio; - - this->free = Audio_DeleteDevice; - - return this; + return retval; } -AudioBootStrap NAS_bootstrap = { - NAS_DRIVER_NAME, "Network Audio System", - Audio_Available, Audio_CreateDevice -}; +#else + +static void +UnloadNASLibrary(void) +{ +} + +static int +LoadNASLibrary(void) +{ + load_nas_syms(); + return 0; +} + +#endif /* SDL_AUDIO_DRIVER_NAS_DYNAMIC */ /* This function waits until it is possible to write a full sound buffer */ static void -NAS_WaitAudio(_THIS) +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); } } static void -NAS_PlayAudio(_THIS) +NAS_PlayDevice(_THIS) { - while (this->hidden->mixlen > this->hidden->buf_free) { /* We think the buffer is full? Yikes! Ask the server for events, - in the hope that some of them is LowWater events telling us more - of the buffer is free now than what we think. */ + while (this->hidden->mixlen > this->hidden->buf_free) { + /* + * We think the buffer is full? Yikes! Ask the server for events, + * in the hope that some of them is LowWater events telling us more + * 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; @@ -142,21 +185,25 @@ } static Uint8 * -NAS_GetAudioBuf(_THIS) +NAS_GetDeviceBuf(_THIS) { return (this->hidden->mixbuf); } static void -NAS_CloseAudio(_THIS) +NAS_CloseDevice(_THIS) { - if (this->hidden->mixbuf != NULL) { - SDL_FreeAudioMem(this->hidden->mixbuf); - this->hidden->mixbuf = NULL; - } - if (this->hidden->aud) { - AuCloseServer(this->hidden->aud); - this->hidden->aud = 0; + if (this->hidden != NULL) { + if (this->hidden->mixbuf != NULL) { + SDL_FreeAudioMem(this->hidden->mixbuf); + this->hidden->mixbuf = NULL; + } + if (this->hidden->aud) { + NAS_AuCloseServer(this->hidden->aud); + this->hidden->aud = 0; + } + SDL_free(this->hidden); + this2 = this->hidden = NULL; } } @@ -221,6 +268,7 @@ 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)) == @@ -233,46 +281,53 @@ } static int -NAS_OpenAudio(_THIS, SDL_AudioSpec * spec) +NAS_OpenDevice(_THIS, const char *devname, int iscapture) { AuElement elms[3]; int buffer_size; SDL_AudioFormat test_format, format; - this->hidden->mixbuf = NULL; + /* Initialize all variables that we clean on shutdown */ + this->hidden = (struct SDL_PrivateAudioData *) + SDL_malloc((sizeof *this->hidden)); + if (this->hidden == NULL) { + SDL_OutOfMemory(); + return 0; + } + SDL_memset(this->hidden, 0, (sizeof *this->hidden)); /* Try for a closest match on audio format */ format = 0; - for (test_format = SDL_FirstAudioFormat(spec->format); + for (test_format = SDL_FirstAudioFormat(this->spec.format); !format && test_format;) { format = sdlformat_to_auformat(test_format); - if (format == AuNone) { test_format = SDL_NextAudioFormat(); } } if (format == 0) { - SDL_SetError("Couldn't find any hardware audio formats"); - return (-1); + NAS_CloseDevice(this); + SDL_SetError("NAS: Couldn't find any hardware audio formats"); + return 0; } - spec->format = test_format; + 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) { - SDL_SetError("Couldn't open connection to NAS server"); - return (-1); + NAS_CloseDevice(this); + SDL_SetError("NAS: Couldn't open connection to NAS server"); + return 0; } - this->hidden->dev = find_device(this, spec->channels); + this->hidden->dev = find_device(this, this->spec.channels); if ((this->hidden->dev == AuNone) - || (!(this->hidden->flow = AuCreateFlow(this->hidden->aud, NULL)))) { - AuCloseServer(this->hidden->aud); - this->hidden->aud = 0; - SDL_SetError("Couldn't find a fitting playback device on NAS server"); - return (-1); + || (!(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; } - buffer_size = spec->freq; + buffer_size = this->spec.freq; if (buffer_size < 4096) buffer_size = 4096; @@ -280,35 +335,70 @@ buffer_size = 32768; /* So that the buffer won't get unmanageably big. */ /* Calculate the final parameters for this audio specification */ - SDL_CalculateAudioSpec(spec); + SDL_CalculateAudioSpec(&this->spec); this2 = this->hidden; - AuMakeElementImportClient(elms, spec->freq, format, spec->channels, + AuMakeElementImportClient(elms,this->spec.freq,format,this->spec.channels, AuTrue, buffer_size, buffer_size / 4, 0, NULL); - AuMakeElementExportDevice(elms + 1, 0, this->hidden->dev, spec->freq, + 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 = spec->size; + this->hidden->mixlen = this->spec.size; this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); if (this->hidden->mixbuf == NULL) { - return (-1); + NAS_CloseDevice(this); + SDL_OutOfMemory(); + return 0; } - SDL_memset(this->hidden->mixbuf, spec->silence, spec->size); - - /* Get the parent process id (we're the parent of the audio thread) */ - this->hidden->parent = getpid(); + SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); /* We're ready to rock and roll. :-) */ - return (0); + return 1; +} + +static void +NAS_Deinitialize(void) +{ + UnloadNASLibrary(); } +static int +NAS_Init(SDL_AudioDriverImpl *impl) +{ + if (LoadNASLibrary() < 0) { + return 0; + } else { + AuServer *aud = NAS_AuOpenServer("", 0, NULL, 0, NULL, NULL); + if (aud == NULL) { + SDL_SetError("NAS: AuOpenServer() failed (no audio server?)"); + return 0; + } + NAS_AuCloseServer(aud); + } + + /* Set the function pointers */ + impl->OpenDevice = NAS_OpenDevice; + impl->PlayDevice = NAS_PlayDevice; + impl->WaitDevice = NAS_WaitDevice; + impl->GetDeviceBuf = NAS_GetDeviceBuf; + impl->CloseDevice = NAS_CloseDevice; + impl->Deinitialize = NAS_Deinitialize; + impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: is this true? */ + + return 1; +} + +AudioBootStrap NAS_bootstrap = { + NAS_DRIVER_NAME, "Network Audio System", NAS_Init, 0 +}; + /* vi: set ts=4 sw=4 expandtab: */