Removed needless macros in various audio targets.
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2011 Sam Lantinga <slouken@libsdl.org>
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
21 #include "SDL_config.h"
23 /* Allow access to a raw mixing buffer */
28 #include "SDL_timer.h"
29 #include "SDL_audio.h"
30 #include "SDL_loadso.h"
31 #include "../SDL_audiomem.h"
32 #include "../SDL_audio_c.h"
33 #include "SDL_nasaudio.h"
35 static struct SDL_PrivateAudioData *this2 = NULL;
38 static void (*NAS_AuCloseServer) (AuServer *);
39 static void (*NAS_AuNextEvent) (AuServer *, AuBool, AuEvent *);
40 static AuBool(*NAS_AuDispatchEvent) (AuServer *, AuEvent *);
41 static AuFlowID(*NAS_AuCreateFlow) (AuServer *, AuStatus *);
42 static void (*NAS_AuStartFlow) (AuServer *, AuFlowID, AuStatus *);
43 static void (*NAS_AuSetElements)
44 (AuServer *, AuFlowID, AuBool, int, AuElement *, AuStatus *);
45 static void (*NAS_AuWriteElement)
46 (AuServer *, AuFlowID, int, AuUint32, AuPointer, AuBool, AuStatus *);
47 static AuServer *(*NAS_AuOpenServer)
48 (_AuConst char *, int, _AuConst char *, int, _AuConst char *, char **);
49 static AuEventHandlerRec *(*NAS_AuRegisterEventHandler)
50 (AuServer *, AuMask, int, AuID, AuEventHandlerCallback, AuPointer);
53 #ifdef SDL_AUDIO_DRIVER_NAS_DYNAMIC
55 static const char *nas_library = SDL_AUDIO_DRIVER_NAS_DYNAMIC;
56 static void *nas_handle = NULL;
59 load_nas_sym(const char *fn, void **addr)
61 *addr = SDL_LoadFunction(nas_handle, fn);
68 /* cast funcs to char* first, to please GCC's strict aliasing rules. */
69 #define SDL_NAS_SYM(x) \
70 if (!load_nas_sym(#x, (void **) (char *) &NAS_##x)) return -1
72 #define SDL_NAS_SYM(x) NAS_##x = x
78 SDL_NAS_SYM(AuCloseServer);
79 SDL_NAS_SYM(AuNextEvent);
80 SDL_NAS_SYM(AuDispatchEvent);
81 SDL_NAS_SYM(AuCreateFlow);
82 SDL_NAS_SYM(AuStartFlow);
83 SDL_NAS_SYM(AuSetElements);
84 SDL_NAS_SYM(AuWriteElement);
85 SDL_NAS_SYM(AuOpenServer);
86 SDL_NAS_SYM(AuRegisterEventHandler);
92 #ifdef SDL_AUDIO_DRIVER_NAS_DYNAMIC
95 UnloadNASLibrary(void)
97 if (nas_handle != NULL) {
98 SDL_UnloadObject(nas_handle);
107 if (nas_handle == NULL) {
108 nas_handle = SDL_LoadObject(nas_library);
109 if (nas_handle == NULL) {
110 /* Copy error string so we can use it in a new SDL_SetError(). */
111 char *origerr = SDL_GetError();
112 size_t len = SDL_strlen(origerr) + 1;
113 char *err = (char *) alloca(len);
114 SDL_strlcpy(err, origerr, len);
116 SDL_SetError("NAS: SDL_LoadObject('%s') failed: %s\n",
119 retval = load_nas_syms();
131 UnloadNASLibrary(void)
142 #endif /* SDL_AUDIO_DRIVER_NAS_DYNAMIC */
144 /* This function waits until it is possible to write a full sound buffer */
146 NAS_WaitDevice(_THIS)
148 while (this->hidden->buf_free < this->hidden->mixlen) {
150 NAS_AuNextEvent(this->hidden->aud, AuTrue, &ev);
151 NAS_AuDispatchEvent(this->hidden->aud, &ev);
156 NAS_PlayDevice(_THIS)
158 while (this->hidden->mixlen > this->hidden->buf_free) {
160 * We think the buffer is full? Yikes! Ask the server for events,
161 * in the hope that some of them is LowWater events telling us more
162 * of the buffer is free now than what we think.
165 NAS_AuNextEvent(this->hidden->aud, AuTrue, &ev);
166 NAS_AuDispatchEvent(this->hidden->aud, &ev);
168 this->hidden->buf_free -= this->hidden->mixlen;
170 /* Write the audio data */
171 NAS_AuWriteElement(this->hidden->aud, this->hidden->flow, 0,
172 this->hidden->mixlen, this->hidden->mixbuf, AuFalse,
175 this->hidden->written += this->hidden->mixlen;
178 fprintf(stderr, "Wrote %d bytes of audio data\n", this->hidden->mixlen);
183 NAS_GetDeviceBuf(_THIS)
185 return (this->hidden->mixbuf);
189 NAS_CloseDevice(_THIS)
191 if (this->hidden != NULL) {
192 if (this->hidden->mixbuf != NULL) {
193 SDL_FreeAudioMem(this->hidden->mixbuf);
194 this->hidden->mixbuf = NULL;
196 if (this->hidden->aud) {
197 NAS_AuCloseServer(this->hidden->aud);
198 this->hidden->aud = 0;
200 SDL_free(this->hidden);
201 this2 = this->hidden = NULL;
206 sdlformat_to_auformat(unsigned int fmt)
210 return AuFormatLinearUnsigned8;
212 return AuFormatLinearSigned8;
214 return AuFormatLinearUnsigned16LSB;
216 return AuFormatLinearUnsigned16MSB;
218 return AuFormatLinearSigned16LSB;
220 return AuFormatLinearSigned16MSB;
226 event_handler(AuServer * aud, AuEvent * ev, AuEventHandlerRec * hnd)
229 case AuEventTypeElementNotify:
231 AuElementNotifyEvent *event = (AuElementNotifyEvent *) ev;
233 switch (event->kind) {
234 case AuElementNotifyKindLowWater:
235 if (this2->buf_free >= 0) {
236 this2->really += event->num_bytes;
237 gettimeofday(&this2->last_tv, 0);
238 this2->buf_free += event->num_bytes;
240 this2->buf_free = event->num_bytes;
243 case AuElementNotifyKindState:
244 switch (event->cur_state) {
246 if (event->reason != AuReasonUser) {
247 if (this2->buf_free >= 0) {
248 this2->really += event->num_bytes;
249 gettimeofday(&this2->last_tv, 0);
250 this2->buf_free += event->num_bytes;
252 this2->buf_free = event->num_bytes;
264 find_device(_THIS, int nch)
266 /* These "Au" things are all macros, not functions... */
268 for (i = 0; i < AuServerNumDevices(this->hidden->aud); i++) {
269 if ((AuDeviceKind(AuServerDevice(this->hidden->aud, i)) ==
270 AuComponentKindPhysicalOutput) &&
271 AuDeviceNumTracks(AuServerDevice(this->hidden->aud, i)) == nch) {
272 return AuDeviceIdentifier(AuServerDevice(this->hidden->aud, i));
279 NAS_OpenDevice(_THIS, const char *devname, int iscapture)
283 SDL_AudioFormat test_format, format;
285 /* Initialize all variables that we clean on shutdown */
286 this->hidden = (struct SDL_PrivateAudioData *)
287 SDL_malloc((sizeof *this->hidden));
288 if (this->hidden == NULL) {
292 SDL_memset(this->hidden, 0, (sizeof *this->hidden));
294 /* Try for a closest match on audio format */
296 for (test_format = SDL_FirstAudioFormat(this->spec.format);
297 !format && test_format;) {
298 format = sdlformat_to_auformat(test_format);
299 if (format == AuNone) {
300 test_format = SDL_NextAudioFormat();
304 NAS_CloseDevice(this);
305 SDL_SetError("NAS: Couldn't find any hardware audio formats");
308 this->spec.format = test_format;
310 this->hidden->aud = NAS_AuOpenServer("", 0, NULL, 0, NULL, NULL);
311 if (this->hidden->aud == 0) {
312 NAS_CloseDevice(this);
313 SDL_SetError("NAS: Couldn't open connection to NAS server");
317 this->hidden->dev = find_device(this, this->spec.channels);
318 if ((this->hidden->dev == AuNone)
319 || (!(this->hidden->flow = NAS_AuCreateFlow(this->hidden->aud, 0)))) {
320 NAS_CloseDevice(this);
321 SDL_SetError("NAS: Couldn't find a fitting device on NAS server");
325 buffer_size = this->spec.freq;
326 if (buffer_size < 4096)
329 if (buffer_size > 32768)
330 buffer_size = 32768; /* So that the buffer won't get unmanageably big. */
332 /* Calculate the final parameters for this audio specification */
333 SDL_CalculateAudioSpec(&this->spec);
335 this2 = this->hidden;
337 AuMakeElementImportClient(elms, this->spec.freq, format,
338 this->spec.channels, AuTrue, buffer_size,
339 buffer_size / 4, 0, NULL);
340 AuMakeElementExportDevice(elms + 1, 0, this->hidden->dev, this->spec.freq,
341 AuUnlimitedSamples, 0, NULL);
342 NAS_AuSetElements(this->hidden->aud, this->hidden->flow, AuTrue, 2, elms,
344 NAS_AuRegisterEventHandler(this->hidden->aud, AuEventHandlerIDMask, 0,
345 this->hidden->flow, event_handler,
348 NAS_AuStartFlow(this->hidden->aud, this->hidden->flow, NULL);
350 /* Allocate mixing buffer */
351 this->hidden->mixlen = this->spec.size;
352 this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
353 if (this->hidden->mixbuf == NULL) {
354 NAS_CloseDevice(this);
358 SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
360 /* We're ready to rock and roll. :-) */
365 NAS_Deinitialize(void)
371 NAS_Init(SDL_AudioDriverImpl * impl)
373 if (LoadNASLibrary() < 0) {
376 AuServer *aud = NAS_AuOpenServer("", 0, NULL, 0, NULL, NULL);
378 SDL_SetError("NAS: AuOpenServer() failed (no audio server?)");
381 NAS_AuCloseServer(aud);
384 /* Set the function pointers */
385 impl->OpenDevice = NAS_OpenDevice;
386 impl->PlayDevice = NAS_PlayDevice;
387 impl->WaitDevice = NAS_WaitDevice;
388 impl->GetDeviceBuf = NAS_GetDeviceBuf;
389 impl->CloseDevice = NAS_CloseDevice;
390 impl->Deinitialize = NAS_Deinitialize;
391 impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: is this true? */
393 return 1; /* this audio target is available. */
396 AudioBootStrap NAS_bootstrap = {
397 "nas", "Network Audio System", NAS_Init, 0
400 /* vi: set ts=4 sw=4 expandtab: */