Mercurial > sdl-ios-xcode
comparison src/audio/arts/SDL_artsaudio.c @ 2049:5f6550e5184f
Merged SDL-ryan-multiple-audio-device branch r2803:2871 into the trunk.
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Tue, 17 Oct 2006 09:15:21 +0000 |
parents | 3b4ce57c6215 |
children | 866052b01ee5 |
comparison
equal
deleted
inserted
replaced
2048:6067c7f9a672 | 2049:5f6550e5184f |
---|---|
25 | 25 |
26 #include "SDL_timer.h" | 26 #include "SDL_timer.h" |
27 #include "SDL_audio.h" | 27 #include "SDL_audio.h" |
28 #include "../SDL_audiomem.h" | 28 #include "../SDL_audiomem.h" |
29 #include "../SDL_audio_c.h" | 29 #include "../SDL_audio_c.h" |
30 #include "../SDL_audiodev_c.h" | |
31 #include "SDL_artsaudio.h" | 30 #include "SDL_artsaudio.h" |
32 | 31 |
33 #ifdef SDL_AUDIO_DRIVER_ARTS_DYNAMIC | 32 #ifdef SDL_AUDIO_DRIVER_ARTS_DYNAMIC |
34 #include "SDL_name.h" | 33 #include "SDL_name.h" |
35 #include "SDL_loadso.h" | 34 #include "SDL_loadso.h" |
38 #endif | 37 #endif |
39 | 38 |
40 /* The tag name used by artsc audio */ | 39 /* The tag name used by artsc audio */ |
41 #define ARTS_DRIVER_NAME "arts" | 40 #define ARTS_DRIVER_NAME "arts" |
42 | 41 |
43 /* Audio driver functions */ | |
44 static int ARTS_OpenAudio(_THIS, SDL_AudioSpec * spec); | |
45 static void ARTS_WaitAudio(_THIS); | |
46 static void ARTS_PlayAudio(_THIS); | |
47 static Uint8 *ARTS_GetAudioBuf(_THIS); | |
48 static void ARTS_CloseAudio(_THIS); | |
49 | |
50 #ifdef SDL_AUDIO_DRIVER_ARTS_DYNAMIC | 42 #ifdef SDL_AUDIO_DRIVER_ARTS_DYNAMIC |
51 | 43 |
52 static const char *arts_library = SDL_AUDIO_DRIVER_ARTS_DYNAMIC; | 44 static const char *arts_library = SDL_AUDIO_DRIVER_ARTS_DYNAMIC; |
53 static void *arts_handle = NULL; | 45 static void *arts_handle = NULL; |
54 static int arts_loaded = 0; | 46 |
55 | 47 /* !!! FIXME: I hate this SDL_NAME clutter...it makes everything so messy! */ |
56 static int (*SDL_NAME(arts_init)) (void); | 48 static int (*SDL_NAME(arts_init)) (void); |
57 static void (*SDL_NAME(arts_free)) (void); | 49 static void (*SDL_NAME(arts_free)) (void); |
58 static arts_stream_t(*SDL_NAME(arts_play_stream)) (int rate, int bits, | 50 static arts_stream_t(*SDL_NAME(arts_play_stream)) (int rate, int bits, |
59 int channels, | 51 int channels, |
60 const char *name); | 52 const char *name); |
63 static int (*SDL_NAME(arts_stream_get)) (arts_stream_t s, | 55 static int (*SDL_NAME(arts_stream_get)) (arts_stream_t s, |
64 arts_parameter_t param); | 56 arts_parameter_t param); |
65 static int (*SDL_NAME(arts_write)) (arts_stream_t s, const void *buffer, | 57 static int (*SDL_NAME(arts_write)) (arts_stream_t s, const void *buffer, |
66 int count); | 58 int count); |
67 static void (*SDL_NAME(arts_close_stream)) (arts_stream_t s); | 59 static void (*SDL_NAME(arts_close_stream)) (arts_stream_t s); |
68 | 60 static void (*SDL_NAME(arts_close_stream)) (arts_stream_t s); |
61 static const char *(*SDL_NAME(arts_error_text)) (int errorcode); | |
62 | |
63 #define SDL_ARTS_SYM(x) { #x, (void **) (char *) &SDL_NAME(x) } | |
69 static struct | 64 static struct |
70 { | 65 { |
71 const char *name; | 66 const char *name; |
72 void **func; | 67 void **func; |
73 } arts_functions[] = { | 68 } arts_functions[] = { |
74 { | 69 SDL_ARTS_SYM(arts_init), |
75 "arts_init", (void **) &SDL_NAME(arts_init)}, { | 70 SDL_ARTS_SYM(arts_free), |
76 "arts_free", (void **) &SDL_NAME(arts_free)}, { | 71 SDL_ARTS_SYM(arts_play_stream), |
77 "arts_play_stream", (void **) &SDL_NAME(arts_play_stream)}, { | 72 SDL_ARTS_SYM(arts_stream_set), |
78 "arts_stream_set", (void **) &SDL_NAME(arts_stream_set)}, { | 73 SDL_ARTS_SYM(arts_stream_get), |
79 "arts_stream_get", (void **) &SDL_NAME(arts_stream_get)}, { | 74 SDL_ARTS_SYM(arts_write), |
80 "arts_write", (void **) &SDL_NAME(arts_write)}, { | 75 SDL_ARTS_SYM(arts_close_stream), |
81 "arts_close_stream", (void **) &SDL_NAME(arts_close_stream)},}; | 76 SDL_ARTS_SYM(arts_error_text), |
77 }; | |
78 #undef SDL_ARTS_SYM | |
82 | 79 |
83 static void | 80 static void |
84 UnloadARTSLibrary() | 81 UnloadARTSLibrary() |
85 { | 82 { |
86 if (arts_loaded) { | 83 if (arts_handle != NULL) { |
87 SDL_UnloadObject(arts_handle); | 84 SDL_UnloadObject(arts_handle); |
88 arts_handle = NULL; | 85 arts_handle = NULL; |
89 arts_loaded = 0; | |
90 } | 86 } |
91 } | 87 } |
92 | 88 |
93 static int | 89 static int |
94 LoadARTSLibrary(void) | 90 LoadARTSLibrary(void) |
95 { | 91 { |
96 int i, retval = -1; | 92 int i, retval = -1; |
97 | 93 |
98 arts_handle = SDL_LoadObject(arts_library); | 94 if (arts_handle == NULL) { |
99 if (arts_handle) { | 95 arts_handle = SDL_LoadObject(arts_library); |
100 arts_loaded = 1; | 96 if (arts_handle != NULL) { |
101 retval = 0; | 97 retval = 0; |
102 for (i = 0; i < SDL_arraysize(arts_functions); ++i) { | 98 for (i = 0; i < SDL_arraysize(arts_functions); ++i) { |
103 *arts_functions[i].func = | 99 *arts_functions[i].func = |
104 SDL_LoadFunction(arts_handle, arts_functions[i].name); | 100 SDL_LoadFunction(arts_handle, arts_functions[i].name); |
105 if (!*arts_functions[i].func) { | 101 if (!*arts_functions[i].func) { |
106 retval = -1; | 102 retval = -1; |
107 UnloadARTSLibrary(); | 103 UnloadARTSLibrary(); |
108 break; | 104 break; |
105 } | |
109 } | 106 } |
110 } | 107 } |
111 } | 108 } |
109 | |
112 return retval; | 110 return retval; |
113 } | 111 } |
114 | 112 |
115 #else | 113 #else |
116 | 114 |
126 return 0; | 124 return 0; |
127 } | 125 } |
128 | 126 |
129 #endif /* SDL_AUDIO_DRIVER_ARTS_DYNAMIC */ | 127 #endif /* SDL_AUDIO_DRIVER_ARTS_DYNAMIC */ |
130 | 128 |
131 /* Audio driver bootstrap functions */ | |
132 | |
133 static int | |
134 Audio_Available(void) | |
135 { | |
136 int available = 0; | |
137 | |
138 if (LoadARTSLibrary() < 0) { | |
139 return available; | |
140 } | |
141 if (SDL_NAME(arts_init) () == 0) { | |
142 #define ARTS_CRASH_HACK /* Play a stream so aRts doesn't crash */ | |
143 #ifdef ARTS_CRASH_HACK | |
144 arts_stream_t stream2; | |
145 stream2 = SDL_NAME(arts_play_stream) (44100, 16, 2, "SDL"); | |
146 SDL_NAME(arts_write) (stream2, "", 0); | |
147 SDL_NAME(arts_close_stream) (stream2); | |
148 #endif | |
149 available = 1; | |
150 SDL_NAME(arts_free) (); | |
151 } | |
152 UnloadARTSLibrary(); | |
153 | |
154 return available; | |
155 } | |
156 | |
157 static void | |
158 Audio_DeleteDevice(SDL_AudioDevice * device) | |
159 { | |
160 SDL_free(device->hidden); | |
161 SDL_free(device); | |
162 UnloadARTSLibrary(); | |
163 } | |
164 | |
165 static SDL_AudioDevice * | |
166 Audio_CreateDevice(int devindex) | |
167 { | |
168 SDL_AudioDevice *this; | |
169 | |
170 /* Initialize all variables that we clean on shutdown */ | |
171 LoadARTSLibrary(); | |
172 this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice)); | |
173 if (this) { | |
174 SDL_memset(this, 0, (sizeof *this)); | |
175 this->hidden = (struct SDL_PrivateAudioData *) | |
176 SDL_malloc((sizeof *this->hidden)); | |
177 } | |
178 if ((this == NULL) || (this->hidden == NULL)) { | |
179 SDL_OutOfMemory(); | |
180 if (this) { | |
181 SDL_free(this); | |
182 } | |
183 return (0); | |
184 } | |
185 SDL_memset(this->hidden, 0, (sizeof *this->hidden)); | |
186 stream = 0; | |
187 | |
188 /* Set the function pointers */ | |
189 this->OpenAudio = ARTS_OpenAudio; | |
190 this->WaitAudio = ARTS_WaitAudio; | |
191 this->PlayAudio = ARTS_PlayAudio; | |
192 this->GetAudioBuf = ARTS_GetAudioBuf; | |
193 this->CloseAudio = ARTS_CloseAudio; | |
194 | |
195 this->free = Audio_DeleteDevice; | |
196 | |
197 return this; | |
198 } | |
199 | |
200 AudioBootStrap ARTS_bootstrap = { | |
201 ARTS_DRIVER_NAME, "Analog Realtime Synthesizer", | |
202 Audio_Available, Audio_CreateDevice | |
203 }; | |
204 | |
205 /* This function waits until it is possible to write a full sound buffer */ | 129 /* This function waits until it is possible to write a full sound buffer */ |
206 static void | 130 static void |
207 ARTS_WaitAudio(_THIS) | 131 ARTS_WaitDevice(_THIS) |
208 { | 132 { |
209 Sint32 ticks; | 133 Sint32 ticks; |
210 | 134 |
211 /* Check to see if the thread-parent process is still alive */ | 135 /* Check to see if the thread-parent process is still alive */ |
212 { | 136 { |
213 static int cnt = 0; | 137 static int cnt = 0; |
214 /* Note that this only works with thread implementations | 138 /* Note that this only works with thread implementations |
215 that use a different process id for each thread. | 139 that use a different process id for each thread. |
216 */ | 140 */ |
217 if (parent && (((++cnt) % 10) == 0)) { /* Check every 10 loops */ | 141 /* Check every 10 loops */ |
218 if (kill(parent, 0) < 0) { | 142 if (this->hidden->parent && (((++cnt) % 10) == 0)) { |
143 if (kill(this->hidden->parent, 0) < 0) { | |
219 this->enabled = 0; | 144 this->enabled = 0; |
220 } | 145 } |
221 } | 146 } |
222 } | 147 } |
223 | 148 |
224 /* Use timer for general audio synchronization */ | 149 /* Use timer for general audio synchronization */ |
225 ticks = ((Sint32) (next_frame - SDL_GetTicks())) - FUDGE_TICKS; | 150 ticks = ((Sint32) (this->hidden->next_frame-SDL_GetTicks())) - FUDGE_TICKS; |
226 if (ticks > 0) { | 151 if (ticks > 0) { |
227 SDL_Delay(ticks); | 152 SDL_Delay(ticks); |
228 } | 153 } |
229 } | 154 } |
230 | 155 |
231 static void | 156 static void |
232 ARTS_PlayAudio(_THIS) | 157 ARTS_PlayDevice(_THIS) |
233 { | 158 { |
234 int written; | |
235 | |
236 /* Write the audio data */ | 159 /* Write the audio data */ |
237 written = SDL_NAME(arts_write) (stream, mixbuf, mixlen); | 160 int written = SDL_NAME(arts_write) ( |
161 this->hidden->stream, | |
162 this->hidden->mixbuf, | |
163 this->hidden->mixlen); | |
238 | 164 |
239 /* If timer synchronization is enabled, set the next write frame */ | 165 /* If timer synchronization is enabled, set the next write frame */ |
240 if (frame_ticks) { | 166 if (this->hidden->frame_ticks) { |
241 next_frame += frame_ticks; | 167 this->hidden->next_frame += this->hidden->frame_ticks; |
242 } | 168 } |
243 | 169 |
244 /* If we couldn't write, assume fatal error for now */ | 170 /* If we couldn't write, assume fatal error for now */ |
245 if (written < 0) { | 171 if (written < 0) { |
246 this->enabled = 0; | 172 this->enabled = 0; |
248 #ifdef DEBUG_AUDIO | 174 #ifdef DEBUG_AUDIO |
249 fprintf(stderr, "Wrote %d bytes of audio data\n", written); | 175 fprintf(stderr, "Wrote %d bytes of audio data\n", written); |
250 #endif | 176 #endif |
251 } | 177 } |
252 | 178 |
179 static void | |
180 ARTS_WaitDone(_THIS) | |
181 { | |
182 /* !!! FIXME: camp here until buffer drains... SDL_Delay(???); */ | |
183 } | |
184 | |
185 | |
253 static Uint8 * | 186 static Uint8 * |
254 ARTS_GetAudioBuf(_THIS) | 187 ARTS_GetDeviceBuf(_THIS) |
255 { | 188 { |
256 return (mixbuf); | 189 return (this->hidden->mixbuf); |
257 } | 190 } |
258 | 191 |
259 static void | 192 |
260 ARTS_CloseAudio(_THIS) | 193 static void |
261 { | 194 ARTS_CloseDevice(_THIS) |
262 if (mixbuf != NULL) { | 195 { |
263 SDL_FreeAudioMem(mixbuf); | 196 if (this->hidden != NULL) { |
264 mixbuf = NULL; | 197 if (this->hidden->mixbuf != NULL) { |
265 } | 198 SDL_FreeAudioMem(this->hidden->mixbuf); |
266 if (stream) { | 199 this->hidden->mixbuf = NULL; |
267 SDL_NAME(arts_close_stream) (stream); | 200 } |
268 stream = 0; | 201 if (this->hidden->stream) { |
269 } | 202 SDL_NAME(arts_close_stream) (this->hidden->stream); |
270 SDL_NAME(arts_free) (); | 203 this->hidden->stream = 0; |
271 } | 204 } |
205 SDL_NAME(arts_free) (); | |
206 SDL_free(this->hidden); | |
207 this->hidden = NULL; | |
208 } | |
209 } | |
210 | |
272 | 211 |
273 static int | 212 static int |
274 ARTS_OpenAudio(_THIS, SDL_AudioSpec * spec) | 213 ARTS_OpenDevice(_THIS, const char *devname, int iscapture) |
275 { | 214 { |
276 int bits, frag_spec; | 215 int rc = 0; |
277 SDL_AudioFormat test_format, format; | 216 int bits = 0, frag_spec = 0; |
278 | 217 SDL_AudioFormat test_format = 0, format = 0; |
279 /* Reset the timer synchronization flag */ | 218 |
280 frame_ticks = 0.0; | 219 /* Initialize all variables that we clean on shutdown */ |
281 | 220 this->hidden = (struct SDL_PrivateAudioData *) |
282 mixbuf = NULL; | 221 SDL_malloc((sizeof *this->hidden)); |
222 if (this->hidden == NULL) { | |
223 SDL_OutOfMemory(); | |
224 return 0; | |
225 } | |
226 SDL_memset(this->hidden, 0, (sizeof *this->hidden)); | |
283 | 227 |
284 /* Try for a closest match on audio format */ | 228 /* Try for a closest match on audio format */ |
285 format = 0; | 229 for (test_format = SDL_FirstAudioFormat(this->spec.format); |
286 bits = 0; | |
287 for (test_format = SDL_FirstAudioFormat(spec->format); | |
288 !format && test_format;) { | 230 !format && test_format;) { |
289 #ifdef DEBUG_AUDIO | 231 #ifdef DEBUG_AUDIO |
290 fprintf(stderr, "Trying format 0x%4.4x\n", test_format); | 232 fprintf(stderr, "Trying format 0x%4.4x\n", test_format); |
291 #endif | 233 #endif |
292 switch (test_format) { | 234 switch (test_format) { |
305 if (!format) { | 247 if (!format) { |
306 test_format = SDL_NextAudioFormat(); | 248 test_format = SDL_NextAudioFormat(); |
307 } | 249 } |
308 } | 250 } |
309 if (format == 0) { | 251 if (format == 0) { |
252 ARTS_CloseDevice(this); | |
310 SDL_SetError("Couldn't find any hardware audio formats"); | 253 SDL_SetError("Couldn't find any hardware audio formats"); |
311 return (-1); | 254 return 0; |
312 } | 255 } |
313 spec->format = test_format; | 256 this->spec.format = test_format; |
314 | 257 |
315 if (SDL_NAME(arts_init) () != 0) { | 258 if ((rc = SDL_NAME(arts_init) ()) != 0) { |
316 SDL_SetError("Unable to initialize ARTS"); | 259 ARTS_CloseDevice(this); |
317 return (-1); | 260 SDL_SetError( "Unable to initialize ARTS: %s", |
318 } | 261 SDL_NAME(arts_error_text)(rc) ); |
319 stream = | 262 return 0; |
320 SDL_NAME(arts_play_stream) (spec->freq, bits, spec->channels, "SDL"); | 263 } |
264 this->hidden->stream = SDL_NAME(arts_play_stream) ( | |
265 this->spec.freq, | |
266 bits, this->spec.channels, | |
267 "SDL"); | |
321 | 268 |
322 /* Calculate the final parameters for this audio specification */ | 269 /* Calculate the final parameters for this audio specification */ |
323 SDL_CalculateAudioSpec(spec); | 270 SDL_CalculateAudioSpec(&this->spec); |
324 | 271 |
325 /* Determine the power of two of the fragment size */ | 272 /* Determine the power of two of the fragment size */ |
326 for (frag_spec = 0; (0x01 << frag_spec) < spec->size; ++frag_spec); | 273 for (frag_spec = 0; (0x01 << frag_spec) < this->spec.size; ++frag_spec); |
327 if ((0x01 << frag_spec) != spec->size) { | 274 if ((0x01 << frag_spec) != this->spec.size) { |
275 ARTS_CloseDevice(this); | |
328 SDL_SetError("Fragment size must be a power of two"); | 276 SDL_SetError("Fragment size must be a power of two"); |
329 return (-1); | 277 return 0; |
330 } | 278 } |
331 frag_spec |= 0x00020000; /* two fragments, for low latency */ | 279 frag_spec |= 0x00020000; /* two fragments, for low latency */ |
332 | 280 |
333 #ifdef ARTS_P_PACKET_SETTINGS | 281 #ifdef ARTS_P_PACKET_SETTINGS |
334 SDL_NAME(arts_stream_set) (stream, ARTS_P_PACKET_SETTINGS, frag_spec); | 282 SDL_NAME(arts_stream_set) (this->hidden->stream, |
283 ARTS_P_PACKET_SETTINGS, frag_spec); | |
335 #else | 284 #else |
336 SDL_NAME(arts_stream_set) (stream, ARTS_P_PACKET_SIZE, | 285 SDL_NAME(arts_stream_set) (this->hidden->stream, ARTS_P_PACKET_SIZE, |
337 frag_spec & 0xffff); | 286 frag_spec & 0xffff); |
338 SDL_NAME(arts_stream_set) (stream, ARTS_P_PACKET_COUNT, frag_spec >> 16); | 287 SDL_NAME(arts_stream_set) (this->hidden->stream, ARTS_P_PACKET_COUNT, |
288 frag_spec >> 16); | |
339 #endif | 289 #endif |
340 spec->size = SDL_NAME(arts_stream_get) (stream, ARTS_P_PACKET_SIZE); | 290 this->spec.size = SDL_NAME(arts_stream_get) (this->hidden->stream, |
291 ARTS_P_PACKET_SIZE); | |
341 | 292 |
342 /* Allocate mixing buffer */ | 293 /* Allocate mixing buffer */ |
343 mixlen = spec->size; | 294 this->hidden->mixlen = this->spec.size; |
344 mixbuf = (Uint8 *) SDL_AllocAudioMem(mixlen); | 295 this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); |
345 if (mixbuf == NULL) { | 296 if (this->hidden->mixbuf == NULL) { |
346 return (-1); | 297 ARTS_CloseDevice(this); |
347 } | 298 SDL_OutOfMemory(); |
348 SDL_memset(mixbuf, spec->silence, spec->size); | 299 return 0; |
300 } | |
301 SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); | |
349 | 302 |
350 /* Get the parent process id (we're the parent of the audio thread) */ | 303 /* Get the parent process id (we're the parent of the audio thread) */ |
351 parent = getpid(); | 304 this->hidden->parent = getpid(); |
352 | 305 |
353 /* We're ready to rock and roll. :-) */ | 306 /* We're ready to rock and roll. :-) */ |
354 return (0); | 307 return 1; |
355 } | 308 } |
309 | |
310 | |
311 static void | |
312 ARTS_Deinitialize(void) | |
313 { | |
314 UnloadARTSLibrary(); | |
315 } | |
316 | |
317 | |
318 static int | |
319 ARTS_Init(SDL_AudioDriverImpl *impl) | |
320 { | |
321 if (LoadARTSLibrary() < 0) { | |
322 return 0; | |
323 } else { | |
324 if (SDL_NAME(arts_init) () != 0) { | |
325 UnloadARTSLibrary(); | |
326 SDL_SetError("ARTS: arts_init failed (no audio server?)"); | |
327 return 0; | |
328 } | |
329 | |
330 /* Play a stream so aRts doesn't crash */ | |
331 arts_stream_t stream; | |
332 stream = SDL_NAME(arts_play_stream) (44100, 16, 2, "SDL"); | |
333 SDL_NAME(arts_write) (stream, "", 0); | |
334 SDL_NAME(arts_close_stream) (stream); | |
335 SDL_NAME(arts_free) (); | |
336 } | |
337 | |
338 /* Set the function pointers */ | |
339 impl->OpenDevice = ARTS_OpenDevice; | |
340 impl->PlayDevice = ARTS_PlayDevice; | |
341 impl->WaitDevice = ARTS_WaitDevice; | |
342 impl->GetDeviceBuf = ARTS_GetDeviceBuf; | |
343 impl->CloseDevice = ARTS_CloseDevice; | |
344 impl->WaitDone = ARTS_WaitDone; | |
345 impl->Deinitialize = ARTS_Deinitialize; | |
346 impl->OnlyHasDefaultOutputDevice = 1; | |
347 | |
348 return 1; | |
349 } | |
350 | |
351 | |
352 AudioBootStrap ARTS_bootstrap = { | |
353 ARTS_DRIVER_NAME, "Analog RealTime Synthesizer", ARTS_Init, 0 | |
354 }; | |
356 | 355 |
357 /* vi: set ts=4 sw=4 expandtab: */ | 356 /* vi: set ts=4 sw=4 expandtab: */ |