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

Latest commit

 

History

History
408 lines (352 loc) · 11.7 KB

SDL_nasaudio.c

File metadata and controls

408 lines (352 loc) · 11.7 KB
 
Apr 26, 2001
Apr 26, 2001
1
2
/*
SDL - Simple DirectMedia Layer
Dec 8, 2008
Dec 8, 2008
3
Copyright (C) 1997-2009 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 17, 2006
Oct 17, 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 17, 2006
Oct 17, 2006
40
/* The tag name used by nas audio */
Apr 26, 2001
Apr 26, 2001
41
42
43
44
45
#define NAS_DRIVER_NAME "nas"
static struct SDL_PrivateAudioData *this2 = NULL;
Oct 28, 2006
Oct 28, 2006
46
47
48
49
50
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 *);
Oct 17, 2006
Oct 17, 2006
51
static void (*NAS_AuSetElements)
Oct 28, 2006
Oct 28, 2006
52
(AuServer *, AuFlowID, AuBool, int, AuElement *, AuStatus *);
Oct 17, 2006
Oct 17, 2006
53
static void (*NAS_AuWriteElement)
Oct 28, 2006
Oct 28, 2006
54
(AuServer *, AuFlowID, int, AuUint32, AuPointer, AuBool, AuStatus *);
Oct 17, 2006
Oct 17, 2006
55
static AuServer *(*NAS_AuOpenServer)
Oct 28, 2006
Oct 28, 2006
56
(_AuConst char *, int, _AuConst char *, int, _AuConst char *, char **);
Oct 17, 2006
Oct 17, 2006
57
static AuEventHandlerRec *(*NAS_AuRegisterEventHandler)
Oct 28, 2006
Oct 28, 2006
58
(AuServer *, AuMask, int, AuID, AuEventHandlerCallback, AuPointer);
Oct 17, 2006
Oct 17, 2006
59
60
61
62
63
64
#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 17, 2006
Oct 17, 2006
67
load_nas_sym(const char *fn, void **addr)
Apr 26, 2001
Apr 26, 2001
68
{
Oct 17, 2006
Oct 17, 2006
69
70
*addr = SDL_LoadFunction(nas_handle, fn);
if (*addr == NULL) {
Jul 10, 2006
Jul 10, 2006
71
return 0;
Oct 17, 2006
Oct 17, 2006
72
}
Jul 10, 2006
Jul 10, 2006
73
return 1;
Apr 26, 2001
Apr 26, 2001
74
75
}
Oct 17, 2006
Oct 17, 2006
76
77
78
79
80
81
82
/* 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
Oct 28, 2006
Oct 28, 2006
83
84
static int
load_nas_syms(void)
Apr 26, 2001
Apr 26, 2001
85
{
Oct 17, 2006
Oct 17, 2006
86
87
88
89
90
91
92
93
94
95
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;
Apr 26, 2001
Apr 26, 2001
96
}
Oct 28, 2006
Oct 28, 2006
97
Oct 17, 2006
Oct 17, 2006
98
#undef SDL_NAS_SYM
Apr 26, 2001
Apr 26, 2001
99
Oct 17, 2006
Oct 17, 2006
100
#ifdef SDL_AUDIO_DRIVER_NAS_DYNAMIC
Jul 10, 2006
Jul 10, 2006
101
Oct 17, 2006
Oct 17, 2006
102
103
104
105
106
107
static void
UnloadNASLibrary(void)
{
if (nas_handle != NULL) {
SDL_UnloadObject(nas_handle);
nas_handle = NULL;
Jul 10, 2006
Jul 10, 2006
108
}
Oct 17, 2006
Oct 17, 2006
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
}
static int
LoadNASLibrary(void)
{
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",
Oct 28, 2006
Oct 28, 2006
125
nas_library, err);
Oct 17, 2006
Oct 17, 2006
126
127
128
129
130
} else {
retval = load_nas_syms();
if (retval < 0) {
UnloadNASLibrary();
}
Jul 10, 2006
Jul 10, 2006
131
132
}
}
Oct 17, 2006
Oct 17, 2006
133
134
return retval;
}
Jul 10, 2006
Jul 10, 2006
135
Oct 17, 2006
Oct 17, 2006
136
#else
Jul 10, 2006
Jul 10, 2006
137
Oct 17, 2006
Oct 17, 2006
138
139
140
141
static void
UnloadNASLibrary(void)
{
}
Jul 10, 2006
Jul 10, 2006
142
Oct 17, 2006
Oct 17, 2006
143
144
145
146
147
static int
LoadNASLibrary(void)
{
load_nas_syms();
return 0;
Apr 26, 2001
Apr 26, 2001
148
149
}
Oct 17, 2006
Oct 17, 2006
150
#endif /* SDL_AUDIO_DRIVER_NAS_DYNAMIC */
Apr 26, 2001
Apr 26, 2001
151
152
/* This function waits until it is possible to write a full sound buffer */
Jul 10, 2006
Jul 10, 2006
153
static void
Oct 17, 2006
Oct 17, 2006
154
NAS_WaitDevice(_THIS)
Apr 26, 2001
Apr 26, 2001
155
{
Jul 10, 2006
Jul 10, 2006
156
157
while (this->hidden->buf_free < this->hidden->mixlen) {
AuEvent ev;
Oct 17, 2006
Oct 17, 2006
158
159
NAS_AuNextEvent(this->hidden->aud, AuTrue, &ev);
NAS_AuDispatchEvent(this->hidden->aud, &ev);
Jul 10, 2006
Jul 10, 2006
160
}
Apr 26, 2001
Apr 26, 2001
161
162
}
Jul 10, 2006
Jul 10, 2006
163
static void
Oct 17, 2006
Oct 17, 2006
164
NAS_PlayDevice(_THIS)
Apr 26, 2001
Apr 26, 2001
165
{
Oct 17, 2006
Oct 17, 2006
166
167
168
169
170
171
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
172
AuEvent ev;
Oct 17, 2006
Oct 17, 2006
173
174
NAS_AuNextEvent(this->hidden->aud, AuTrue, &ev);
NAS_AuDispatchEvent(this->hidden->aud, &ev);
Jul 10, 2006
Jul 10, 2006
175
176
177
178
}
this->hidden->buf_free -= this->hidden->mixlen;
/* Write the audio data */
Oct 17, 2006
Oct 17, 2006
179
NAS_AuWriteElement(this->hidden->aud, this->hidden->flow, 0,
Oct 28, 2006
Oct 28, 2006
180
181
this->hidden->mixlen, this->hidden->mixbuf, AuFalse,
NULL);
Jul 10, 2006
Jul 10, 2006
182
183
184
this->hidden->written += this->hidden->mixlen;
Apr 26, 2001
Apr 26, 2001
185
#ifdef DEBUG_AUDIO
Jul 10, 2006
Jul 10, 2006
186
fprintf(stderr, "Wrote %d bytes of audio data\n", this->hidden->mixlen);
Apr 26, 2001
Apr 26, 2001
187
188
189
#endif
}
Jul 10, 2006
Jul 10, 2006
190
static Uint8 *
Oct 17, 2006
Oct 17, 2006
191
NAS_GetDeviceBuf(_THIS)
Apr 26, 2001
Apr 26, 2001
192
{
Jul 10, 2006
Jul 10, 2006
193
return (this->hidden->mixbuf);
Apr 26, 2001
Apr 26, 2001
194
195
}
Jul 10, 2006
Jul 10, 2006
196
static void
Oct 17, 2006
Oct 17, 2006
197
NAS_CloseDevice(_THIS)
Apr 26, 2001
Apr 26, 2001
198
{
Oct 17, 2006
Oct 17, 2006
199
200
201
202
203
204
205
206
207
208
209
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;
Jul 10, 2006
Jul 10, 2006
210
}
Apr 26, 2001
Apr 26, 2001
211
212
}
Jul 10, 2006
Jul 10, 2006
213
214
static unsigned char
sdlformat_to_auformat(unsigned int fmt)
Apr 26, 2001
Apr 26, 2001
215
{
Jul 10, 2006
Jul 10, 2006
216
switch (fmt) {
Apr 26, 2001
Apr 26, 2001
217
case AUDIO_U8:
Jul 10, 2006
Jul 10, 2006
218
return AuFormatLinearUnsigned8;
Apr 26, 2001
Apr 26, 2001
219
case AUDIO_S8:
Jul 10, 2006
Jul 10, 2006
220
return AuFormatLinearSigned8;
Apr 26, 2001
Apr 26, 2001
221
case AUDIO_U16LSB:
Jul 10, 2006
Jul 10, 2006
222
return AuFormatLinearUnsigned16LSB;
Apr 26, 2001
Apr 26, 2001
223
case AUDIO_U16MSB:
Jul 10, 2006
Jul 10, 2006
224
return AuFormatLinearUnsigned16MSB;
Apr 26, 2001
Apr 26, 2001
225
case AUDIO_S16LSB:
Jul 10, 2006
Jul 10, 2006
226
return AuFormatLinearSigned16LSB;
Apr 26, 2001
Apr 26, 2001
227
case AUDIO_S16MSB:
Jul 10, 2006
Jul 10, 2006
228
return AuFormatLinearSigned16MSB;
Apr 26, 2001
Apr 26, 2001
229
}
Jul 10, 2006
Jul 10, 2006
230
return AuNone;
Apr 26, 2001
Apr 26, 2001
231
232
233
}
static AuBool
Jul 10, 2006
Jul 10, 2006
234
event_handler(AuServer * aud, AuEvent * ev, AuEventHandlerRec * hnd)
Apr 26, 2001
Apr 26, 2001
235
{
Jul 10, 2006
Jul 10, 2006
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
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
269
270
271
272
273
}
static AuDeviceID
find_device(_THIS, int nch)
{
Oct 17, 2006
Oct 17, 2006
274
/* These "Au" things are all macros, not functions... */
Jul 10, 2006
Jul 10, 2006
275
276
277
278
279
280
281
282
283
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
284
285
}
Jul 10, 2006
Jul 10, 2006
286
static int
Oct 17, 2006
Oct 17, 2006
287
NAS_OpenDevice(_THIS, const char *devname, int iscapture)
Apr 26, 2001
Apr 26, 2001
288
{
Jul 10, 2006
Jul 10, 2006
289
290
AuElement elms[3];
int buffer_size;
Aug 24, 2006
Aug 24, 2006
291
SDL_AudioFormat test_format, format;
Jul 10, 2006
Jul 10, 2006
292
Oct 17, 2006
Oct 17, 2006
293
294
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
Oct 28, 2006
Oct 28, 2006
295
SDL_malloc((sizeof *this->hidden));
Oct 17, 2006
Oct 17, 2006
296
297
298
299
300
if (this->hidden == NULL) {
SDL_OutOfMemory();
return 0;
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
Jul 10, 2006
Jul 10, 2006
301
302
303
/* Try for a closest match on audio format */
format = 0;
Oct 17, 2006
Oct 17, 2006
304
for (test_format = SDL_FirstAudioFormat(this->spec.format);
Jul 10, 2006
Jul 10, 2006
305
306
307
308
309
310
311
!format && test_format;) {
format = sdlformat_to_auformat(test_format);
if (format == AuNone) {
test_format = SDL_NextAudioFormat();
}
}
if (format == 0) {
Oct 17, 2006
Oct 17, 2006
312
313
314
NAS_CloseDevice(this);
SDL_SetError("NAS: Couldn't find any hardware audio formats");
return 0;
Jul 10, 2006
Jul 10, 2006
315
}
Oct 17, 2006
Oct 17, 2006
316
this->spec.format = test_format;
Jul 10, 2006
Jul 10, 2006
317
Oct 17, 2006
Oct 17, 2006
318
this->hidden->aud = NAS_AuOpenServer("", 0, NULL, 0, NULL, NULL);
Jul 10, 2006
Jul 10, 2006
319
if (this->hidden->aud == 0) {
Oct 17, 2006
Oct 17, 2006
320
321
322
NAS_CloseDevice(this);
SDL_SetError("NAS: Couldn't open connection to NAS server");
return 0;
Jul 10, 2006
Jul 10, 2006
323
324
}
Oct 17, 2006
Oct 17, 2006
325
this->hidden->dev = find_device(this, this->spec.channels);
Jul 10, 2006
Jul 10, 2006
326
if ((this->hidden->dev == AuNone)
Oct 17, 2006
Oct 17, 2006
327
328
329
330
|| (!(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;
Jul 10, 2006
Jul 10, 2006
331
332
}
Oct 17, 2006
Oct 17, 2006
333
buffer_size = this->spec.freq;
Jul 10, 2006
Jul 10, 2006
334
335
336
337
338
339
340
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 17, 2006
Oct 17, 2006
341
SDL_CalculateAudioSpec(&this->spec);
Jul 10, 2006
Jul 10, 2006
342
343
344
this2 = this->hidden;
Oct 28, 2006
Oct 28, 2006
345
346
347
AuMakeElementImportClient(elms, this->spec.freq, format,
this->spec.channels, AuTrue, buffer_size,
buffer_size / 4, 0, NULL);
Oct 17, 2006
Oct 17, 2006
348
AuMakeElementExportDevice(elms + 1, 0, this->hidden->dev, this->spec.freq,
Jul 10, 2006
Jul 10, 2006
349
AuUnlimitedSamples, 0, NULL);
Oct 28, 2006
Oct 28, 2006
350
351
NAS_AuSetElements(this->hidden->aud, this->hidden->flow, AuTrue, 2, elms,
NULL);
Oct 17, 2006
Oct 17, 2006
352
353
354
NAS_AuRegisterEventHandler(this->hidden->aud, AuEventHandlerIDMask, 0,
this->hidden->flow, event_handler,
(AuPointer) NULL);
Jul 10, 2006
Jul 10, 2006
355
Oct 17, 2006
Oct 17, 2006
356
NAS_AuStartFlow(this->hidden->aud, this->hidden->flow, NULL);
Jul 10, 2006
Jul 10, 2006
357
358
/* Allocate mixing buffer */
Oct 17, 2006
Oct 17, 2006
359
this->hidden->mixlen = this->spec.size;
Jul 10, 2006
Jul 10, 2006
360
361
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
Oct 17, 2006
Oct 17, 2006
362
363
364
NAS_CloseDevice(this);
SDL_OutOfMemory();
return 0;
Jul 10, 2006
Jul 10, 2006
365
}
Oct 17, 2006
Oct 17, 2006
366
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
Jul 10, 2006
Jul 10, 2006
367
368
/* We're ready to rock and roll. :-) */
Oct 17, 2006
Oct 17, 2006
369
return 1;
Apr 26, 2001
Apr 26, 2001
370
}
Jul 10, 2006
Jul 10, 2006
371
Oct 17, 2006
Oct 17, 2006
372
373
374
375
376
377
378
static void
NAS_Deinitialize(void)
{
UnloadNASLibrary();
}
static int
Oct 28, 2006
Oct 28, 2006
379
NAS_Init(SDL_AudioDriverImpl * impl)
Oct 17, 2006
Oct 17, 2006
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
{
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;
Oct 28, 2006
Oct 28, 2006
399
impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: is this true? */
Oct 17, 2006
Oct 17, 2006
400
Jan 1, 2009
Jan 1, 2009
401
return 2; /* 2 == definitely has an audio device. */
Oct 17, 2006
Oct 17, 2006
402
403
404
405
406
407
}
AudioBootStrap NAS_bootstrap = {
NAS_DRIVER_NAME, "Network Audio System", NAS_Init, 0
};
Jul 10, 2006
Jul 10, 2006
408
/* vi: set ts=4 sw=4 expandtab: */