Skip to content
This repository has been archived by the owner on Feb 11, 2021. It is now read-only.

Latest commit

 

History

History
412 lines (355 loc) · 11.7 KB

SDL_nasaudio.c

File metadata and controls

412 lines (355 loc) · 11.7 KB
 
Apr 26, 2001
Apr 26, 2001
1
2
/*
SDL - Simple DirectMedia Layer
Feb 1, 2006
Feb 1, 2006
3
Copyright (C) 1997-2006 Sam Lantinga
Apr 26, 2001
Apr 26, 2001
4
5
This library is free software; you can redistribute it and/or
Feb 1, 2006
Feb 1, 2006
6
modify it under the terms of the GNU Lesser General Public
Apr 26, 2001
Apr 26, 2001
7
License as published by the Free Software Foundation; either
Feb 1, 2006
Feb 1, 2006
8
version 2.1 of the License, or (at your option) any later version.
Apr 26, 2001
Apr 26, 2001
9
10
11
12
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Feb 1, 2006
Feb 1, 2006
13
Lesser General Public License for more details.
Apr 26, 2001
Apr 26, 2001
14
Feb 1, 2006
Feb 1, 2006
15
16
17
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Apr 26, 2001
Apr 26, 2001
18
19
Sam Lantinga
Dec 14, 2001
Dec 14, 2001
20
slouken@libsdl.org
Apr 26, 2001
Apr 26, 2001
21
22
23
24
25
This driver was written by:
Erik Inge Bolsø
knan@mo.himolde.no
*/
Feb 21, 2006
Feb 21, 2006
26
#include "SDL_config.h"
Apr 26, 2001
Apr 26, 2001
27
28
29
30
31
32
/* Allow access to a raw mixing buffer */
#include <signal.h>
#include <unistd.h>
Feb 10, 2006
Feb 10, 2006
33
#include "SDL_timer.h"
Apr 26, 2001
Apr 26, 2001
34
#include "SDL_audio.h"
Oct 7, 2006
Oct 7, 2006
35
#include "SDL_loadso.h"
Feb 16, 2006
Feb 16, 2006
36
37
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
Apr 26, 2001
Apr 26, 2001
38
39
#include "SDL_nasaudio.h"
Oct 7, 2006
Oct 7, 2006
40
/* The tag name used by nas audio */
Apr 26, 2001
Apr 26, 2001
41
42
43
44
#define NAS_DRIVER_NAME "nas"
static struct SDL_PrivateAudioData *this2 = NULL;
Oct 7, 2006
Oct 7, 2006
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
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;
Apr 26, 2001
Apr 26, 2001
65
Jul 10, 2006
Jul 10, 2006
66
static int
Oct 7, 2006
Oct 7, 2006
67
load_nas_sym(const char *fn, void **addr)
Apr 26, 2001
Apr 26, 2001
68
{
Oct 7, 2006
Oct 7, 2006
69
70
*addr = SDL_LoadFunction(nas_handle, fn);
if (*addr == NULL) {
Jul 10, 2006
Jul 10, 2006
71
return 0;
Oct 7, 2006
Oct 7, 2006
72
}
Jul 10, 2006
Jul 10, 2006
73
return 1;
Apr 26, 2001
Apr 26, 2001
74
75
}
Oct 7, 2006
Oct 7, 2006
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
/* 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_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 int library_load_count = 0;
static void
UnloadNASLibrary(void)
{
if ((nas_handle != NULL) && (--library_load_count == 0)) {
SDL_UnloadObject(nas_handle);
nas_handle = NULL;
}
}
static int
LoadNASLibrary(void)
{
int retval = 0;
if (library_load_count++ == 0) {
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);
library_load_count--;
retval = -1;
SDL_SetError("NAS: SDL_LoadObject('%s') failed: %s\n",
nas_library, err);
} else {
retval = load_nas_syms();
if (retval < 0) {
UnloadNASLibrary();
}
}
}
return retval;
}
#else
static void
UnloadNASLibrary(void)
{
}
static int
LoadNASLibrary(void)
{
load_nas_syms();
return 0;
}
#endif /* SDL_AUDIO_DRIVER_NAS_DYNAMIC */
static int
NAS_Available(void)
{
int available = 0;
if (LoadNASLibrary() >= 0) {
AuServer *aud = NAS_AuOpenServer("", 0, NULL, 0, NULL, NULL);
if (aud != NULL) {
available = 1;
NAS_AuCloseServer(aud);
}
UnloadNASLibrary();
}
return available;
}
Apr 26, 2001
Apr 26, 2001
169
/* This function waits until it is possible to write a full sound buffer */
Jul 10, 2006
Jul 10, 2006
170
static void
Oct 7, 2006
Oct 7, 2006
171
NAS_WaitDevice(_THIS)
Apr 26, 2001
Apr 26, 2001
172
{
Jul 10, 2006
Jul 10, 2006
173
174
while (this->hidden->buf_free < this->hidden->mixlen) {
AuEvent ev;
Oct 7, 2006
Oct 7, 2006
175
176
NAS_AuNextEvent(this->hidden->aud, AuTrue, &ev);
NAS_AuDispatchEvent(this->hidden->aud, &ev);
Jul 10, 2006
Jul 10, 2006
177
}
Apr 26, 2001
Apr 26, 2001
178
179
}
Jul 10, 2006
Jul 10, 2006
180
static void
Oct 7, 2006
Oct 7, 2006
181
NAS_PlayDevice(_THIS)
Apr 26, 2001
Apr 26, 2001
182
{
Oct 7, 2006
Oct 7, 2006
183
184
185
186
187
188
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.
*/
Jul 10, 2006
Jul 10, 2006
189
AuEvent ev;
Oct 7, 2006
Oct 7, 2006
190
191
NAS_AuNextEvent(this->hidden->aud, AuTrue, &ev);
NAS_AuDispatchEvent(this->hidden->aud, &ev);
Jul 10, 2006
Jul 10, 2006
192
193
194
195
}
this->hidden->buf_free -= this->hidden->mixlen;
/* Write the audio data */
Oct 7, 2006
Oct 7, 2006
196
NAS_AuWriteElement(this->hidden->aud, this->hidden->flow, 0,
Jul 10, 2006
Jul 10, 2006
197
198
199
200
this->hidden->mixlen, this->hidden->mixbuf, AuFalse, NULL);
this->hidden->written += this->hidden->mixlen;
Apr 26, 2001
Apr 26, 2001
201
#ifdef DEBUG_AUDIO
Jul 10, 2006
Jul 10, 2006
202
fprintf(stderr, "Wrote %d bytes of audio data\n", this->hidden->mixlen);
Apr 26, 2001
Apr 26, 2001
203
204
205
#endif
}
Jul 10, 2006
Jul 10, 2006
206
static Uint8 *
Oct 7, 2006
Oct 7, 2006
207
NAS_GetDeviceBuf(_THIS)
Apr 26, 2001
Apr 26, 2001
208
{
Jul 10, 2006
Jul 10, 2006
209
return (this->hidden->mixbuf);
Apr 26, 2001
Apr 26, 2001
210
211
}
Jul 10, 2006
Jul 10, 2006
212
static void
Oct 7, 2006
Oct 7, 2006
213
NAS_CloseDevice(_THIS)
Apr 26, 2001
Apr 26, 2001
214
{
Oct 7, 2006
Oct 7, 2006
215
216
217
218
219
220
if (this->hidden != NULL) {
if (this->hidden->mixbuf != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
}
if (this->hidden->aud) {
Oct 7, 2006
Oct 7, 2006
221
NAS_AuCloseServer(this->hidden->aud);
Oct 7, 2006
Oct 7, 2006
222
223
224
this->hidden->aud = 0;
}
SDL_free(this->hidden);
Oct 7, 2006
Oct 7, 2006
225
this2 = this->hidden = NULL;
Oct 7, 2006
Oct 7, 2006
226
UnloadNASLibrary();
Jul 10, 2006
Jul 10, 2006
227
}
Apr 26, 2001
Apr 26, 2001
228
229
}
Jul 10, 2006
Jul 10, 2006
230
231
static unsigned char
sdlformat_to_auformat(unsigned int fmt)
Apr 26, 2001
Apr 26, 2001
232
{
Jul 10, 2006
Jul 10, 2006
233
switch (fmt) {
Apr 26, 2001
Apr 26, 2001
234
case AUDIO_U8:
Jul 10, 2006
Jul 10, 2006
235
return AuFormatLinearUnsigned8;
Apr 26, 2001
Apr 26, 2001
236
case AUDIO_S8:
Jul 10, 2006
Jul 10, 2006
237
return AuFormatLinearSigned8;
Apr 26, 2001
Apr 26, 2001
238
case AUDIO_U16LSB:
Jul 10, 2006
Jul 10, 2006
239
return AuFormatLinearUnsigned16LSB;
Apr 26, 2001
Apr 26, 2001
240
case AUDIO_U16MSB:
Jul 10, 2006
Jul 10, 2006
241
return AuFormatLinearUnsigned16MSB;
Apr 26, 2001
Apr 26, 2001
242
case AUDIO_S16LSB:
Jul 10, 2006
Jul 10, 2006
243
return AuFormatLinearSigned16LSB;
Apr 26, 2001
Apr 26, 2001
244
case AUDIO_S16MSB:
Jul 10, 2006
Jul 10, 2006
245
return AuFormatLinearSigned16MSB;
Apr 26, 2001
Apr 26, 2001
246
}
Jul 10, 2006
Jul 10, 2006
247
return AuNone;
Apr 26, 2001
Apr 26, 2001
248
249
250
}
static AuBool
Jul 10, 2006
Jul 10, 2006
251
event_handler(AuServer * aud, AuEvent * ev, AuEventHandlerRec * hnd)
Apr 26, 2001
Apr 26, 2001
252
{
Jul 10, 2006
Jul 10, 2006
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
switch (ev->type) {
case AuEventTypeElementNotify:
{
AuElementNotifyEvent *event = (AuElementNotifyEvent *) ev;
switch (event->kind) {
case AuElementNotifyKindLowWater:
if (this2->buf_free >= 0) {
this2->really += event->num_bytes;
gettimeofday(&this2->last_tv, 0);
this2->buf_free += event->num_bytes;
} else {
this2->buf_free = event->num_bytes;
}
break;
case AuElementNotifyKindState:
switch (event->cur_state) {
case AuStatePause:
if (event->reason != AuReasonUser) {
if (this2->buf_free >= 0) {
this2->really += event->num_bytes;
gettimeofday(&this2->last_tv, 0);
this2->buf_free += event->num_bytes;
} else {
this2->buf_free = event->num_bytes;
}
}
break;
}
}
}
}
return AuTrue;
Apr 26, 2001
Apr 26, 2001
286
287
288
289
290
}
static AuDeviceID
find_device(_THIS, int nch)
{
Oct 7, 2006
Oct 7, 2006
291
/* These "Au" things are all macros, not functions... */
Jul 10, 2006
Jul 10, 2006
292
293
294
295
296
297
298
299
300
int i;
for (i = 0; i < AuServerNumDevices(this->hidden->aud); i++) {
if ((AuDeviceKind(AuServerDevice(this->hidden->aud, i)) ==
AuComponentKindPhysicalOutput) &&
AuDeviceNumTracks(AuServerDevice(this->hidden->aud, i)) == nch) {
return AuDeviceIdentifier(AuServerDevice(this->hidden->aud, i));
}
}
return AuNone;
Apr 26, 2001
Apr 26, 2001
301
302
}
Jul 10, 2006
Jul 10, 2006
303
static int
Oct 7, 2006
Oct 7, 2006
304
NAS_OpenDevice(_THIS, const char *devname, int iscapture)
Apr 26, 2001
Apr 26, 2001
305
{
Jul 10, 2006
Jul 10, 2006
306
307
AuElement elms[3];
int buffer_size;
Aug 24, 2006
Aug 24, 2006
308
SDL_AudioFormat test_format, format;
Jul 10, 2006
Jul 10, 2006
309
Oct 7, 2006
Oct 7, 2006
310
311
312
313
314
315
316
317
/* 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));
Jul 10, 2006
Jul 10, 2006
318
Oct 7, 2006
Oct 7, 2006
319
320
321
322
323
if (LoadNASLibrary() < 0) {
NAS_CloseDevice(this);
return 0;
}
Jul 10, 2006
Jul 10, 2006
324
325
/* Try for a closest match on audio format */
format = 0;
Oct 7, 2006
Oct 7, 2006
326
for (test_format = SDL_FirstAudioFormat(this->spec.format);
Jul 10, 2006
Jul 10, 2006
327
328
329
330
331
332
333
!format && test_format;) {
format = sdlformat_to_auformat(test_format);
if (format == AuNone) {
test_format = SDL_NextAudioFormat();
}
}
if (format == 0) {
Oct 7, 2006
Oct 7, 2006
334
335
336
NAS_CloseDevice(this);
SDL_SetError("NAS: Couldn't find any hardware audio formats");
return 0;
Jul 10, 2006
Jul 10, 2006
337
}
Oct 7, 2006
Oct 7, 2006
338
this->spec.format = test_format;
Jul 10, 2006
Jul 10, 2006
339
Oct 7, 2006
Oct 7, 2006
340
this->hidden->aud = NAS_AuOpenServer("", 0, NULL, 0, NULL, NULL);
Jul 10, 2006
Jul 10, 2006
341
if (this->hidden->aud == 0) {
Oct 7, 2006
Oct 7, 2006
342
343
344
NAS_CloseDevice(this);
SDL_SetError("NAS: Couldn't open connection to NAS server");
return 0;
Jul 10, 2006
Jul 10, 2006
345
346
}
Oct 7, 2006
Oct 7, 2006
347
this->hidden->dev = find_device(this, this->spec.channels);
Jul 10, 2006
Jul 10, 2006
348
if ((this->hidden->dev == AuNone)
Oct 7, 2006
Oct 7, 2006
349
|| (!(this->hidden->flow = NAS_AuCreateFlow(this->hidden->aud, 0)))) {
Oct 7, 2006
Oct 7, 2006
350
351
352
NAS_CloseDevice(this);
SDL_SetError("NAS: Couldn't find a fitting device on NAS server");
return 0;
Jul 10, 2006
Jul 10, 2006
353
354
}
Oct 7, 2006
Oct 7, 2006
355
buffer_size = this->spec.freq;
Jul 10, 2006
Jul 10, 2006
356
357
358
359
360
361
362
if (buffer_size < 4096)
buffer_size = 4096;
if (buffer_size > 32768)
buffer_size = 32768; /* So that the buffer won't get unmanageably big. */
/* Calculate the final parameters for this audio specification */
Oct 7, 2006
Oct 7, 2006
363
SDL_CalculateAudioSpec(&this->spec);
Jul 10, 2006
Jul 10, 2006
364
365
366
this2 = this->hidden;
Oct 7, 2006
Oct 7, 2006
367
AuMakeElementImportClient(elms,this->spec.freq,format,this->spec.channels,
Jul 10, 2006
Jul 10, 2006
368
AuTrue, buffer_size, buffer_size / 4, 0, NULL);
Oct 7, 2006
Oct 7, 2006
369
AuMakeElementExportDevice(elms + 1, 0, this->hidden->dev, this->spec.freq,
Jul 10, 2006
Jul 10, 2006
370
AuUnlimitedSamples, 0, NULL);
Oct 7, 2006
Oct 7, 2006
371
372
373
374
375
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);
Jul 10, 2006
Jul 10, 2006
376
Oct 7, 2006
Oct 7, 2006
377
NAS_AuStartFlow(this->hidden->aud, this->hidden->flow, NULL);
Jul 10, 2006
Jul 10, 2006
378
379
/* Allocate mixing buffer */
Oct 7, 2006
Oct 7, 2006
380
this->hidden->mixlen = this->spec.size;
Jul 10, 2006
Jul 10, 2006
381
382
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
Oct 7, 2006
Oct 7, 2006
383
384
NAS_CloseDevice(this);
SDL_OutOfMemory();
Oct 7, 2006
Oct 7, 2006
385
return 0;
Jul 10, 2006
Jul 10, 2006
386
}
Oct 7, 2006
Oct 7, 2006
387
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
Jul 10, 2006
Jul 10, 2006
388
389
/* We're ready to rock and roll. :-) */
Oct 7, 2006
Oct 7, 2006
390
return 1;
Apr 26, 2001
Apr 26, 2001
391
}
Jul 10, 2006
Jul 10, 2006
392
Oct 7, 2006
Oct 7, 2006
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
static int
NAS_Init(SDL_AudioDriverImpl *impl)
{
/* 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->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: is this true? */
return 1;
}
AudioBootStrap NAS_bootstrap = {
NAS_DRIVER_NAME, "Network Audio System",
NAS_Available, NAS_Init, 0
};
Jul 10, 2006
Jul 10, 2006
412
/* vi: set ts=4 sw=4 expandtab: */