Mercurial > sdl-ios-xcode
comparison src/audio/nas/SDL_nasaudio.c @ 3825:76c5a414b996 SDL-ryan-multiple-audio-device
Dynamic loading for NAS audio driver.
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Sat, 07 Oct 2006 07:25:30 +0000 |
parents | 748707e2ddd1 |
children | 66fb40445587 |
comparison
equal
deleted
inserted
replaced
3824:25052dd25810 | 3825:76c5a414b996 |
---|---|
30 #include <signal.h> | 30 #include <signal.h> |
31 #include <unistd.h> | 31 #include <unistd.h> |
32 | 32 |
33 #include "SDL_timer.h" | 33 #include "SDL_timer.h" |
34 #include "SDL_audio.h" | 34 #include "SDL_audio.h" |
35 #include "SDL_loadso.h" | |
35 #include "../SDL_audiomem.h" | 36 #include "../SDL_audiomem.h" |
36 #include "../SDL_audio_c.h" | 37 #include "../SDL_audio_c.h" |
37 #include "SDL_nasaudio.h" | 38 #include "SDL_nasaudio.h" |
38 | 39 |
39 /* The tag name used by nas audio */ | 40 /* The tag name used by nas audio */ |
40 #define NAS_DRIVER_NAME "nas" | 41 #define NAS_DRIVER_NAME "nas" |
41 | 42 |
42 static struct SDL_PrivateAudioData *this2 = NULL; | 43 static struct SDL_PrivateAudioData *this2 = NULL; |
43 | 44 |
44 /* !!! FIXME: dynamic loading? */ | 45 |
46 static void (*NAS_AuCloseServer)(AuServer *); | |
47 static void (*NAS_AuNextEvent)(AuServer *, AuBool, AuEvent *); | |
48 static AuBool (*NAS_AuDispatchEvent)(AuServer *, AuEvent *); | |
49 static AuFlowID (*NAS_AuCreateFlow)(AuServer *, AuStatus *); | |
50 static void (*NAS_AuStartFlow)(AuServer *, AuFlowID, AuStatus *); | |
51 static void (*NAS_AuSetElements) | |
52 (AuServer *, AuFlowID, AuBool, int, AuElement *, AuStatus *); | |
53 static void (*NAS_AuWriteElement) | |
54 (AuServer *, AuFlowID, int, AuUint32, AuPointer, AuBool, AuStatus *); | |
55 static AuServer *(*NAS_AuOpenServer) | |
56 (_AuConst char *, int, _AuConst char *, int, _AuConst char *, char **); | |
57 static AuEventHandlerRec *(*NAS_AuRegisterEventHandler) | |
58 (AuServer *, AuMask, int, AuID, AuEventHandlerCallback, AuPointer); | |
59 | |
60 | |
61 #ifdef SDL_AUDIO_DRIVER_NAS_DYNAMIC | |
62 | |
63 static const char *nas_library = SDL_AUDIO_DRIVER_NAS_DYNAMIC; | |
64 static void *nas_handle = NULL; | |
65 | |
66 static int | |
67 load_nas_sym(const char *fn, void **addr) | |
68 { | |
69 *addr = SDL_LoadFunction(nas_handle, fn); | |
70 if (*addr == NULL) { | |
71 return 0; | |
72 } | |
73 return 1; | |
74 } | |
75 | |
76 /* cast funcs to char* first, to please GCC's strict aliasing rules. */ | |
77 #define SDL_NAS_SYM(x) \ | |
78 if (!load_nas_sym(#x, (void **) (char *) &NAS_##x)) return -1 | |
79 #else | |
80 #define SDL_NAS_SYM(x) NAS_##x = x | |
81 #endif | |
82 | |
83 static int load_nas_syms(void) | |
84 { | |
85 SDL_NAS_SYM(AuCloseServer); | |
86 SDL_NAS_SYM(AuNextEvent); | |
87 SDL_NAS_SYM(AuDispatchEvent); | |
88 SDL_NAS_SYM(AuCreateFlow); | |
89 SDL_NAS_SYM(AuStartFlow); | |
90 SDL_NAS_SYM(AuSetElements); | |
91 SDL_NAS_SYM(AuWriteElement); | |
92 SDL_NAS_SYM(AuOpenServer); | |
93 SDL_NAS_SYM(AuRegisterEventHandler); | |
94 return 0; | |
95 } | |
96 #undef SDL_NAS_SYM | |
97 | |
98 #ifdef SDL_AUDIO_DRIVER_NAS_DYNAMIC | |
99 | |
100 static int library_load_count = 0; | |
101 | |
102 static void | |
103 UnloadNASLibrary(void) | |
104 { | |
105 if ((nas_handle != NULL) && (--library_load_count == 0)) { | |
106 SDL_UnloadObject(nas_handle); | |
107 nas_handle = NULL; | |
108 } | |
109 } | |
110 | |
111 static int | |
112 LoadNASLibrary(void) | |
113 { | |
114 int retval = 0; | |
115 if (library_load_count++ == 0) { | |
116 nas_handle = SDL_LoadObject(nas_library); | |
117 if (nas_handle == NULL) { | |
118 /* Copy error string so we can use it in a new SDL_SetError(). */ | |
119 char *origerr = SDL_GetError(); | |
120 size_t len = SDL_strlen(origerr) + 1; | |
121 char *err = (char *) alloca(len); | |
122 SDL_strlcpy(err, origerr, len); | |
123 | |
124 library_load_count--; | |
125 retval = -1; | |
126 SDL_SetError("NAS: SDL_LoadObject('%s') failed: %s\n", | |
127 nas_library, err); | |
128 } else { | |
129 retval = load_nas_syms(); | |
130 if (retval < 0) { | |
131 UnloadNASLibrary(); | |
132 } | |
133 } | |
134 } | |
135 return retval; | |
136 } | |
137 | |
138 #else | |
139 | |
140 static void | |
141 UnloadNASLibrary(void) | |
142 { | |
143 } | |
144 | |
145 static int | |
146 LoadNASLibrary(void) | |
147 { | |
148 load_nas_syms(); | |
149 return 0; | |
150 } | |
151 | |
152 #endif /* SDL_AUDIO_DRIVER_NAS_DYNAMIC */ | |
45 | 153 |
46 static int | 154 static int |
47 NAS_Available(void) | 155 NAS_Available(void) |
48 { | 156 { |
49 AuServer *aud = AuOpenServer("", 0, NULL, 0, NULL, NULL); | 157 int available = 0; |
50 if (!aud) | 158 if (LoadNASLibrary() >= 0) { |
51 return 0; | 159 AuServer *aud = NAS_AuOpenServer("", 0, NULL, 0, NULL, NULL); |
52 | 160 if (aud != NULL) { |
53 AuCloseServer(aud); | 161 available = 1; |
54 return 1; | 162 NAS_AuCloseServer(aud); |
163 } | |
164 UnloadNASLibrary(); | |
165 } | |
166 return available; | |
55 } | 167 } |
56 | 168 |
57 /* This function waits until it is possible to write a full sound buffer */ | 169 /* This function waits until it is possible to write a full sound buffer */ |
58 static void | 170 static void |
59 NAS_WaitDevice(_THIS) | 171 NAS_WaitDevice(_THIS) |
60 { | 172 { |
61 while (this->hidden->buf_free < this->hidden->mixlen) { | 173 while (this->hidden->buf_free < this->hidden->mixlen) { |
62 AuEvent ev; | 174 AuEvent ev; |
63 AuNextEvent(this->hidden->aud, AuTrue, &ev); | 175 NAS_AuNextEvent(this->hidden->aud, AuTrue, &ev); |
64 AuDispatchEvent(this->hidden->aud, &ev); | 176 NAS_AuDispatchEvent(this->hidden->aud, &ev); |
65 } | 177 } |
66 } | 178 } |
67 | 179 |
68 static void | 180 static void |
69 NAS_PlayDevice(_THIS) | 181 NAS_PlayDevice(_THIS) |
73 * We think the buffer is full? Yikes! Ask the server for events, | 185 * We think the buffer is full? Yikes! Ask the server for events, |
74 * in the hope that some of them is LowWater events telling us more | 186 * in the hope that some of them is LowWater events telling us more |
75 * of the buffer is free now than what we think. | 187 * of the buffer is free now than what we think. |
76 */ | 188 */ |
77 AuEvent ev; | 189 AuEvent ev; |
78 AuNextEvent(this->hidden->aud, AuTrue, &ev); | 190 NAS_AuNextEvent(this->hidden->aud, AuTrue, &ev); |
79 AuDispatchEvent(this->hidden->aud, &ev); | 191 NAS_AuDispatchEvent(this->hidden->aud, &ev); |
80 } | 192 } |
81 this->hidden->buf_free -= this->hidden->mixlen; | 193 this->hidden->buf_free -= this->hidden->mixlen; |
82 | 194 |
83 /* Write the audio data */ | 195 /* Write the audio data */ |
84 AuWriteElement(this->hidden->aud, this->hidden->flow, 0, | 196 NAS_AuWriteElement(this->hidden->aud, this->hidden->flow, 0, |
85 this->hidden->mixlen, this->hidden->mixbuf, AuFalse, NULL); | 197 this->hidden->mixlen, this->hidden->mixbuf, AuFalse, NULL); |
86 | 198 |
87 this->hidden->written += this->hidden->mixlen; | 199 this->hidden->written += this->hidden->mixlen; |
88 | 200 |
89 #ifdef DEBUG_AUDIO | 201 #ifdef DEBUG_AUDIO |
104 if (this->hidden->mixbuf != NULL) { | 216 if (this->hidden->mixbuf != NULL) { |
105 SDL_FreeAudioMem(this->hidden->mixbuf); | 217 SDL_FreeAudioMem(this->hidden->mixbuf); |
106 this->hidden->mixbuf = NULL; | 218 this->hidden->mixbuf = NULL; |
107 } | 219 } |
108 if (this->hidden->aud) { | 220 if (this->hidden->aud) { |
109 AuCloseServer(this->hidden->aud); | 221 NAS_AuCloseServer(this->hidden->aud); |
110 this->hidden->aud = 0; | 222 this->hidden->aud = 0; |
111 } | 223 } |
112 SDL_free(this->hidden); | 224 SDL_free(this->hidden); |
113 this2 = this->hidden = NULL; | 225 this2 = this->hidden = NULL; |
226 UnloadNASLibrary(); | |
114 } | 227 } |
115 } | 228 } |
116 | 229 |
117 static unsigned char | 230 static unsigned char |
118 sdlformat_to_auformat(unsigned int fmt) | 231 sdlformat_to_auformat(unsigned int fmt) |
173 } | 286 } |
174 | 287 |
175 static AuDeviceID | 288 static AuDeviceID |
176 find_device(_THIS, int nch) | 289 find_device(_THIS, int nch) |
177 { | 290 { |
291 /* These "Au" things are all macros, not functions... */ | |
178 int i; | 292 int i; |
179 for (i = 0; i < AuServerNumDevices(this->hidden->aud); i++) { | 293 for (i = 0; i < AuServerNumDevices(this->hidden->aud); i++) { |
180 if ((AuDeviceKind(AuServerDevice(this->hidden->aud, i)) == | 294 if ((AuDeviceKind(AuServerDevice(this->hidden->aud, i)) == |
181 AuComponentKindPhysicalOutput) && | 295 AuComponentKindPhysicalOutput) && |
182 AuDeviceNumTracks(AuServerDevice(this->hidden->aud, i)) == nch) { | 296 AuDeviceNumTracks(AuServerDevice(this->hidden->aud, i)) == nch) { |
199 if (this->hidden == NULL) { | 313 if (this->hidden == NULL) { |
200 SDL_OutOfMemory(); | 314 SDL_OutOfMemory(); |
201 return 0; | 315 return 0; |
202 } | 316 } |
203 SDL_memset(this->hidden, 0, (sizeof *this->hidden)); | 317 SDL_memset(this->hidden, 0, (sizeof *this->hidden)); |
318 | |
319 if (LoadNASLibrary() < 0) { | |
320 NAS_CloseDevice(this); | |
321 return 0; | |
322 } | |
204 | 323 |
205 /* Try for a closest match on audio format */ | 324 /* Try for a closest match on audio format */ |
206 format = 0; | 325 format = 0; |
207 for (test_format = SDL_FirstAudioFormat(this->spec.format); | 326 for (test_format = SDL_FirstAudioFormat(this->spec.format); |
208 !format && test_format;) { | 327 !format && test_format;) { |
216 SDL_SetError("NAS: Couldn't find any hardware audio formats"); | 335 SDL_SetError("NAS: Couldn't find any hardware audio formats"); |
217 return 0; | 336 return 0; |
218 } | 337 } |
219 this->spec.format = test_format; | 338 this->spec.format = test_format; |
220 | 339 |
221 this->hidden->aud = AuOpenServer("", 0, NULL, 0, NULL, NULL); | 340 this->hidden->aud = NAS_AuOpenServer("", 0, NULL, 0, NULL, NULL); |
222 if (this->hidden->aud == 0) { | 341 if (this->hidden->aud == 0) { |
223 NAS_CloseDevice(this); | 342 NAS_CloseDevice(this); |
224 SDL_SetError("NAS: Couldn't open connection to NAS server"); | 343 SDL_SetError("NAS: Couldn't open connection to NAS server"); |
225 return 0; | 344 return 0; |
226 } | 345 } |
227 | 346 |
228 this->hidden->dev = find_device(this, this->spec.channels); | 347 this->hidden->dev = find_device(this, this->spec.channels); |
229 if ((this->hidden->dev == AuNone) | 348 if ((this->hidden->dev == AuNone) |
230 || (!(this->hidden->flow = AuCreateFlow(this->hidden->aud, NULL)))) { | 349 || (!(this->hidden->flow = NAS_AuCreateFlow(this->hidden->aud, 0)))) { |
231 NAS_CloseDevice(this); | 350 NAS_CloseDevice(this); |
232 SDL_SetError("NAS: Couldn't find a fitting device on NAS server"); | 351 SDL_SetError("NAS: Couldn't find a fitting device on NAS server"); |
233 return 0; | 352 return 0; |
234 } | 353 } |
235 | 354 |
247 | 366 |
248 AuMakeElementImportClient(elms,this->spec.freq,format,this->spec.channels, | 367 AuMakeElementImportClient(elms,this->spec.freq,format,this->spec.channels, |
249 AuTrue, buffer_size, buffer_size / 4, 0, NULL); | 368 AuTrue, buffer_size, buffer_size / 4, 0, NULL); |
250 AuMakeElementExportDevice(elms + 1, 0, this->hidden->dev, this->spec.freq, | 369 AuMakeElementExportDevice(elms + 1, 0, this->hidden->dev, this->spec.freq, |
251 AuUnlimitedSamples, 0, NULL); | 370 AuUnlimitedSamples, 0, NULL); |
252 AuSetElements(this->hidden->aud, this->hidden->flow, AuTrue, 2, elms, NULL); | 371 NAS_AuSetElements(this->hidden->aud, this->hidden->flow, |
253 AuRegisterEventHandler(this->hidden->aud, AuEventHandlerIDMask, 0, | 372 AuTrue, 2, elms, NULL); |
254 this->hidden->flow, event_handler, | 373 NAS_AuRegisterEventHandler(this->hidden->aud, AuEventHandlerIDMask, 0, |
255 (AuPointer) NULL); | 374 this->hidden->flow, event_handler, |
256 | 375 (AuPointer) NULL); |
257 AuStartFlow(this->hidden->aud, this->hidden->flow, NULL); | 376 |
377 NAS_AuStartFlow(this->hidden->aud, this->hidden->flow, NULL); | |
258 | 378 |
259 /* Allocate mixing buffer */ | 379 /* Allocate mixing buffer */ |
260 this->hidden->mixlen = this->spec.size; | 380 this->hidden->mixlen = this->spec.size; |
261 this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); | 381 this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); |
262 if (this->hidden->mixbuf == NULL) { | 382 if (this->hidden->mixbuf == NULL) { |
263 NAS_CloseDevice(this); | 383 NAS_CloseDevice(this); |
264 SDL_OutOfMemory(); | 384 SDL_OutOfMemory(); |
265 return (-1); | 385 return 0; |
266 } | 386 } |
267 SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); | 387 SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); |
268 | 388 |
269 /* We're ready to rock and roll. :-) */ | 389 /* We're ready to rock and roll. :-) */ |
270 return 1; | 390 return 1; |