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