summaryrefslogtreecommitdiff
path: root/apps/plugins/sdl/src/audio/nas
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/sdl/src/audio/nas')
-rw-r--r--apps/plugins/sdl/src/audio/nas/SDL_nasaudio.c423
-rw-r--r--apps/plugins/sdl/src/audio/nas/SDL_nasaudio.h62
2 files changed, 0 insertions, 485 deletions
diff --git a/apps/plugins/sdl/src/audio/nas/SDL_nasaudio.c b/apps/plugins/sdl/src/audio/nas/SDL_nasaudio.c
deleted file mode 100644
index a561e62984..0000000000
--- a/apps/plugins/sdl/src/audio/nas/SDL_nasaudio.c
+++ /dev/null
@@ -1,423 +0,0 @@
1/*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2012 Sam Lantinga
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19 Sam Lantinga
20 slouken@libsdl.org
21
22 This driver was written by:
23 Erik Inge Bolsų
24 knan@mo.himolde.no
25*/
26#include "SDL_config.h"
27
28/* Allow access to a raw mixing buffer */
29
30#include <signal.h>
31#include <unistd.h>
32
33#include "SDL_timer.h"
34#include "SDL_audio.h"
35#include "../SDL_audiomem.h"
36#include "../SDL_audio_c.h"
37#include "../SDL_audiodev_c.h"
38#include "SDL_nasaudio.h"
39
40#ifdef SDL_AUDIO_DRIVER_NAS_DYNAMIC
41#include "SDL_loadso.h"
42#endif
43
44/* The tag name used by artsc audio */
45#define NAS_DRIVER_NAME "nas"
46
47static struct SDL_PrivateAudioData *this2 = NULL;
48
49static void (*NAS_AuCloseServer) (AuServer *);
50static void (*NAS_AuNextEvent) (AuServer *, AuBool, AuEvent *);
51static AuBool(*NAS_AuDispatchEvent) (AuServer *, AuEvent *);
52static AuFlowID(*NAS_AuCreateFlow) (AuServer *, AuStatus *);
53static void (*NAS_AuStartFlow) (AuServer *, AuFlowID, AuStatus *);
54static void (*NAS_AuSetElements)
55 (AuServer *, AuFlowID, AuBool, int, AuElement *, AuStatus *);
56static void (*NAS_AuWriteElement)
57 (AuServer *, AuFlowID, int, AuUint32, AuPointer, AuBool, AuStatus *);
58static AuServer *(*NAS_AuOpenServer)
59 (_AuConst char *, int, _AuConst char *, int, _AuConst char *, char **);
60static AuEventHandlerRec *(*NAS_AuRegisterEventHandler)
61 (AuServer *, AuMask, int, AuID, AuEventHandlerCallback, AuPointer);
62
63
64#ifdef SDL_AUDIO_DRIVER_NAS_DYNAMIC
65
66static const char *nas_library = SDL_AUDIO_DRIVER_NAS_DYNAMIC;
67static void *nas_handle = NULL;
68
69static int
70load_nas_sym(const char *fn, void **addr)
71{
72 *addr = SDL_LoadFunction(nas_handle, fn);
73 if (*addr == NULL) {
74 return 0;
75 }
76 return 1;
77}
78
79/* cast funcs to char* first, to please GCC's strict aliasing rules. */
80#define SDL_NAS_SYM(x) \
81 if (!load_nas_sym(#x, (void **) (char *) &NAS_##x)) return -1
82#else
83#define SDL_NAS_SYM(x) NAS_##x = x
84#endif
85
86static int
87load_nas_syms(void)
88{
89 SDL_NAS_SYM(AuCloseServer);
90 SDL_NAS_SYM(AuNextEvent);
91 SDL_NAS_SYM(AuDispatchEvent);
92 SDL_NAS_SYM(AuCreateFlow);
93 SDL_NAS_SYM(AuStartFlow);
94 SDL_NAS_SYM(AuSetElements);
95 SDL_NAS_SYM(AuWriteElement);
96 SDL_NAS_SYM(AuOpenServer);
97 SDL_NAS_SYM(AuRegisterEventHandler);
98 return 0;
99}
100
101#undef SDL_NAS_SYM
102
103#ifdef SDL_AUDIO_DRIVER_NAS_DYNAMIC
104
105static void
106UnloadNASLibrary(void)
107{
108 if (nas_handle != NULL) {
109 SDL_UnloadObject(nas_handle);
110 nas_handle = NULL;
111 }
112}
113
114static int
115LoadNASLibrary(void)
116{
117 int retval = 0;
118 if (nas_handle == NULL) {
119 nas_handle = SDL_LoadObject(nas_library);
120 if (nas_handle == NULL) {
121 /* Copy error string so we can use it in a new SDL_SetError(). */
122 char *origerr = SDL_GetError();
123 size_t len = SDL_strlen(origerr) + 1;
124 char *err = (char *) alloca(len);
125 SDL_strlcpy(err, origerr, len);
126 retval = -1;
127 SDL_SetError("NAS: SDL_LoadObject('%s') failed: %s\n",
128 nas_library, err);
129 } else {
130 retval = load_nas_syms();
131 if (retval < 0) {
132 UnloadNASLibrary();
133 }
134 }
135 }
136 return retval;
137}
138
139#else
140
141static void
142UnloadNASLibrary(void)
143{
144}
145
146static int
147LoadNASLibrary(void)
148{
149 load_nas_syms();
150 return 0;
151}
152
153#endif /* SDL_AUDIO_DRIVER_NAS_DYNAMIC */
154
155
156/* Audio driver functions */
157static int NAS_OpenAudio(_THIS, SDL_AudioSpec *spec);
158static void NAS_WaitAudio(_THIS);
159static void NAS_PlayAudio(_THIS);
160static Uint8 *NAS_GetAudioBuf(_THIS);
161static void NAS_CloseAudio(_THIS);
162
163/* Audio driver bootstrap functions */
164
165static int Audio_Available(void)
166{
167 if (LoadNASLibrary() == 0) {
168 AuServer *aud = NAS_AuOpenServer("", 0, NULL, 0, NULL, NULL);
169 if (!aud) {
170 UnloadNASLibrary();
171 return 0;
172 }
173 NAS_AuCloseServer(aud);
174 UnloadNASLibrary();
175 return 1;
176 }
177 return 0;
178}
179
180static void Audio_DeleteDevice(SDL_AudioDevice *device)
181{
182 UnloadNASLibrary();
183 SDL_free(device->hidden);
184 SDL_free(device);
185}
186
187static SDL_AudioDevice *Audio_CreateDevice(int devindex)
188{
189 SDL_AudioDevice *this;
190
191 if (LoadNASLibrary() < 0) {
192 return NULL;
193 }
194
195 /* Initialize all variables that we clean on shutdown */
196 this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
197 if ( this ) {
198 SDL_memset(this, 0, (sizeof *this));
199 this->hidden = (struct SDL_PrivateAudioData *)
200 SDL_malloc((sizeof *this->hidden));
201 }
202 if ( (this == NULL) || (this->hidden == NULL) ) {
203 SDL_OutOfMemory();
204 if ( this ) {
205 SDL_free(this);
206 }
207 return NULL;
208 }
209 SDL_memset(this->hidden, 0, (sizeof *this->hidden));
210
211 /* Set the function pointers */
212 this->OpenAudio = NAS_OpenAudio;
213 this->WaitAudio = NAS_WaitAudio;
214 this->PlayAudio = NAS_PlayAudio;
215 this->GetAudioBuf = NAS_GetAudioBuf;
216 this->CloseAudio = NAS_CloseAudio;
217
218 this->free = Audio_DeleteDevice;
219
220 return this;
221}
222
223AudioBootStrap NAS_bootstrap = {
224 NAS_DRIVER_NAME, "Network Audio System",
225 Audio_Available, Audio_CreateDevice
226};
227
228/* This function waits until it is possible to write a full sound buffer */
229static void NAS_WaitAudio(_THIS)
230{
231 while ( this->hidden->buf_free < this->hidden->mixlen ) {
232 AuEvent ev;
233 NAS_AuNextEvent(this->hidden->aud, AuTrue, &ev);
234 NAS_AuDispatchEvent(this->hidden->aud, &ev);
235 }
236}
237
238static void NAS_PlayAudio(_THIS)
239{
240 while (this->hidden->mixlen > this->hidden->buf_free) { /* We think the buffer is full? Yikes! Ask the server for events,
241 in the hope that some of them is LowWater events telling us more
242 of the buffer is free now than what we think. */
243 AuEvent ev;
244 NAS_AuNextEvent(this->hidden->aud, AuTrue, &ev);
245 NAS_AuDispatchEvent(this->hidden->aud, &ev);
246 }
247 this->hidden->buf_free -= this->hidden->mixlen;
248
249 /* Write the audio data */
250 NAS_AuWriteElement(this->hidden->aud, this->hidden->flow, 0, this->hidden->mixlen, this->hidden->mixbuf, AuFalse, NULL);
251
252 this->hidden->written += this->hidden->mixlen;
253
254#ifdef DEBUG_AUDIO
255 fprintf(stderr, "Wrote %d bytes of audio data\n", this->hidden->mixlen);
256#endif
257}
258
259static Uint8 *NAS_GetAudioBuf(_THIS)
260{
261 return(this->hidden->mixbuf);
262}
263
264static void NAS_CloseAudio(_THIS)
265{
266 if ( this->hidden->mixbuf != NULL ) {
267 SDL_FreeAudioMem(this->hidden->mixbuf);
268 this->hidden->mixbuf = NULL;
269 }
270 if ( this->hidden->aud ) {
271 NAS_AuCloseServer(this->hidden->aud);
272 this->hidden->aud = 0;
273 }
274}
275
276static unsigned char sdlformat_to_auformat(unsigned int fmt)
277{
278 switch (fmt)
279 {
280 case AUDIO_U8:
281 return AuFormatLinearUnsigned8;
282 case AUDIO_S8:
283 return AuFormatLinearSigned8;
284 case AUDIO_U16LSB:
285 return AuFormatLinearUnsigned16LSB;
286 case AUDIO_U16MSB:
287 return AuFormatLinearUnsigned16MSB;
288 case AUDIO_S16LSB:
289 return AuFormatLinearSigned16LSB;
290 case AUDIO_S16MSB:
291 return AuFormatLinearSigned16MSB;
292 }
293 return AuNone;
294}
295
296static AuBool
297event_handler(AuServer* aud, AuEvent* ev, AuEventHandlerRec* hnd)
298{
299 switch (ev->type) {
300 case AuEventTypeElementNotify: {
301 AuElementNotifyEvent* event = (AuElementNotifyEvent *)ev;
302
303 switch (event->kind) {
304 case AuElementNotifyKindLowWater:
305 if (this2->buf_free >= 0) {
306 this2->really += event->num_bytes;
307 gettimeofday(&this2->last_tv, 0);
308 this2->buf_free += event->num_bytes;
309 } else {
310 this2->buf_free = event->num_bytes;
311 }
312 break;
313 case AuElementNotifyKindState:
314 switch (event->cur_state) {
315 case AuStatePause:
316 if (event->reason != AuReasonUser) {
317 if (this2->buf_free >= 0) {
318 this2->really += event->num_bytes;
319 gettimeofday(&this2->last_tv, 0);
320 this2->buf_free += event->num_bytes;
321 } else {
322 this2->buf_free = event->num_bytes;
323 }
324 }
325 break;
326 }
327 }
328 }
329 }
330 return AuTrue;
331}
332
333static AuDeviceID
334find_device(_THIS, int nch)
335{
336 /* These "Au" things are all macros, not functions... */
337 int i;
338 for (i = 0; i < AuServerNumDevices(this->hidden->aud); i++) {
339 if ((AuDeviceKind(AuServerDevice(this->hidden->aud, i)) ==
340 AuComponentKindPhysicalOutput) &&
341 AuDeviceNumTracks(AuServerDevice(this->hidden->aud, i)) == nch) {
342 return AuDeviceIdentifier(AuServerDevice(this->hidden->aud, i));
343 }
344 }
345 return AuNone;
346}
347
348static int NAS_OpenAudio(_THIS, SDL_AudioSpec *spec)
349{
350 AuElement elms[3];
351 int buffer_size;
352 Uint16 test_format, format;
353
354 this->hidden->mixbuf = NULL;
355
356 /* Try for a closest match on audio format */
357 format = 0;
358 for ( test_format = SDL_FirstAudioFormat(spec->format);
359 ! format && test_format; ) {
360 format = sdlformat_to_auformat(test_format);
361
362 if (format == AuNone) {
363 test_format = SDL_NextAudioFormat();
364 }
365 }
366 if ( format == 0 ) {
367 SDL_SetError("Couldn't find any hardware audio formats");
368 return(-1);
369 }
370 spec->format = test_format;
371
372 this->hidden->aud = NAS_AuOpenServer("", 0, NULL, 0, NULL, NULL);
373 if (this->hidden->aud == 0)
374 {
375 SDL_SetError("Couldn't open connection to NAS server");
376 return (-1);
377 }
378
379 this->hidden->dev = find_device(this, spec->channels);
380 if ((this->hidden->dev == AuNone) || (!(this->hidden->flow = NAS_AuCreateFlow(this->hidden->aud, NULL)))) {
381 NAS_AuCloseServer(this->hidden->aud);
382 this->hidden->aud = 0;
383 SDL_SetError("Couldn't find a fitting playback device on NAS server");
384 return (-1);
385 }
386
387 buffer_size = spec->freq;
388 if (buffer_size < 4096)
389 buffer_size = 4096;
390
391 if (buffer_size > 32768)
392 buffer_size = 32768; /* So that the buffer won't get unmanageably big. */
393
394 /* Calculate the final parameters for this audio specification */
395 SDL_CalculateAudioSpec(spec);
396
397 this2 = this->hidden;
398
399 /* These "Au" things without a NAS_ prefix are macros, not functions... */
400 AuMakeElementImportClient(elms, spec->freq, format, spec->channels, AuTrue,
401 buffer_size, buffer_size / 4, 0, NULL);
402 AuMakeElementExportDevice(elms+1, 0, this->hidden->dev, spec->freq,
403 AuUnlimitedSamples, 0, NULL);
404 NAS_AuSetElements(this->hidden->aud, this->hidden->flow, AuTrue, 2, elms, NULL);
405 NAS_AuRegisterEventHandler(this->hidden->aud, AuEventHandlerIDMask, 0, this->hidden->flow,
406 event_handler, (AuPointer) NULL);
407
408 NAS_AuStartFlow(this->hidden->aud, this->hidden->flow, NULL);
409
410 /* Allocate mixing buffer */
411 this->hidden->mixlen = spec->size;
412 this->hidden->mixbuf = (Uint8 *)SDL_AllocAudioMem(this->hidden->mixlen);
413 if ( this->hidden->mixbuf == NULL ) {
414 return(-1);
415 }
416 SDL_memset(this->hidden->mixbuf, spec->silence, spec->size);
417
418 /* Get the parent process id (we're the parent of the audio thread) */
419 this->hidden->parent = getpid();
420
421 /* We're ready to rock and roll. :-) */
422 return(0);
423}
diff --git a/apps/plugins/sdl/src/audio/nas/SDL_nasaudio.h b/apps/plugins/sdl/src/audio/nas/SDL_nasaudio.h
deleted file mode 100644
index 1c09630880..0000000000
--- a/apps/plugins/sdl/src/audio/nas/SDL_nasaudio.h
+++ /dev/null
@@ -1,62 +0,0 @@
1/*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2012 Sam Lantinga
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19 Sam Lantinga
20 slouken@libsdl.org
21
22 This driver was written by:
23 Erik Inge Bolsų
24 knan@mo.himolde.no
25*/
26#include "SDL_config.h"
27
28#ifndef _SDL_nasaudio_h
29#define _SDL_nasaudio_h
30
31#ifdef __sgi
32#include <nas/audiolib.h>
33#else
34#include <audio/audiolib.h>
35#endif
36#include <sys/time.h>
37
38#include "../SDL_sysaudio.h"
39
40/* Hidden "this" pointer for the video functions */
41#define _THIS SDL_AudioDevice *this
42
43struct SDL_PrivateAudioData {
44 AuServer* aud;
45 AuFlowID flow;
46 AuDeviceID dev;
47
48 /* The parent process id, to detect when application quits */
49 pid_t parent;
50
51 /* Raw mixing buffer */
52 Uint8 *mixbuf;
53 int mixlen;
54
55 int written;
56 int really;
57 int bps;
58 struct timeval last_tv;
59 int buf_free;
60};
61#endif /* _SDL_nasaudio_h */
62