Mercurial > sdl-ios-xcode
comparison src/audio/SDL_audio.c @ 3784:37c9c4590689 SDL-ryan-multiple-audio-device
First batch of heavy lifting on supporting multiple audio devices at once.
This has a long way to go yet, most of the drivers aren't updated for the
new interfaces, and it's still got some obvious bugs, FIXMEs, and wistlist
items.
Don't use yet.
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Sun, 01 Oct 2006 05:24:03 +0000 |
parents | 3a64f57eb3cf |
children | b70f4e9291bb |
comparison
equal
deleted
inserted
replaced
3783:dc3870a3f30d | 3784:37c9c4590689 |
---|---|
31 #ifdef __OS2__ | 31 #ifdef __OS2__ |
32 /* We'll need the DosSetPriority() API! */ | 32 /* We'll need the DosSetPriority() API! */ |
33 #define INCL_DOSPROCESS | 33 #define INCL_DOSPROCESS |
34 #include <os2.h> | 34 #include <os2.h> |
35 #endif | 35 #endif |
36 | |
37 static SDL_AudioDriver current_audio; | |
38 | |
39 /* !!! FIXME: don't use a static array, but it's Good Enough For Now... */ | |
40 static SDL_AudioDevice *open_devices[16]; | |
41 | |
36 | 42 |
37 /* Available audio drivers */ | 43 /* Available audio drivers */ |
38 static AudioBootStrap *bootstrap[] = { | 44 static AudioBootStrap *bootstrap[] = { |
39 #if SDL_AUDIO_DRIVER_BSD | 45 #if SDL_AUDIO_DRIVER_BSD |
40 &BSD_AUDIO_bootstrap, | 46 &BSD_AUDIO_bootstrap, |
107 #if SDL_AUDIO_DRIVER_DART | 113 #if SDL_AUDIO_DRIVER_DART |
108 &DART_bootstrap, | 114 &DART_bootstrap, |
109 #endif | 115 #endif |
110 NULL | 116 NULL |
111 }; | 117 }; |
112 SDL_AudioDevice *current_audio = NULL; | |
113 | |
114 /* Various local functions */ | |
115 int SDL_AudioInit(const char *driver_name); | |
116 void SDL_AudioQuit(void); | |
117 | 118 |
118 #if SDL_AUDIO_DRIVER_AHI | 119 #if SDL_AUDIO_DRIVER_AHI |
119 static int audio_configured = 0; | 120 static int audio_configured = 0; |
120 #endif | 121 #endif |
121 | 122 |
123 static SDL_AudioDevice *get_audio_device(SDL_AudioDeviceID id) | |
124 { | |
125 id--; | |
126 if ( (id >= SDL_arraysize(open_devices)) || (open_devices[id] == NULL) ) { | |
127 SDL_SetError("Invalid audio device ID"); | |
128 return NULL; | |
129 } | |
130 | |
131 return open_devices[id]; | |
132 } | |
133 | |
134 | |
122 /* The general mixing thread function */ | 135 /* The general mixing thread function */ |
123 int SDLCALL | 136 int SDLCALL |
124 SDL_RunAudio(void *audiop) | 137 SDL_RunAudio(void *devicep) |
125 { | 138 { |
126 SDL_AudioDevice *audio = (SDL_AudioDevice *) audiop; | 139 SDL_AudioDevice *device = (SDL_AudioDevice *) devicep; |
140 const int legacy_device = (device == open_devices[0]); | |
127 Uint8 *stream; | 141 Uint8 *stream; |
128 int stream_len; | 142 int stream_len; |
129 void *udata; | 143 void *udata; |
130 void (SDLCALL * fill) (void *userdata, Uint8 * stream, int len); | 144 void (SDLCALL * fill) (void *userdata, Uint8 * stream, int len); |
131 int silence; | 145 int silence; |
146 | |
147 /* !!! FIXME: can we push this into the Amiga driver? */ | |
132 #if SDL_AUDIO_DRIVER_AHI | 148 #if SDL_AUDIO_DRIVER_AHI |
149 #error this is probably broken. | |
133 int started = 0; | 150 int started = 0; |
134 | 151 |
135 /* AmigaOS NEEDS that the audio driver is opened in the thread that uses it! */ | 152 /* AmigaOS NEEDS that the audio driver is opened in the thread that uses it! */ |
136 | 153 |
137 D(bug("Task audio started audio struct:<%lx>...\n", audiop)); | 154 D(bug("Task audio started audio struct:<%lx>...\n", audiop)); |
143 } | 160 } |
144 D(bug("OpenAudio...OK\n")); | 161 D(bug("OpenAudio...OK\n")); |
145 #endif | 162 #endif |
146 | 163 |
147 /* Perform any thread setup */ | 164 /* Perform any thread setup */ |
148 if (audio->ThreadInit) { | 165 if (current_audio.impl.ThreadInit != NULL) { |
149 audio->ThreadInit(audio); | 166 current_audio.impl.ThreadInit(device); |
150 } | 167 } |
151 audio->threadid = SDL_ThreadID(); | 168 device->threadid = SDL_ThreadID(); |
152 | 169 |
153 /* Set up the mixing function */ | 170 /* Set up the mixing function */ |
154 fill = audio->spec.callback; | 171 fill = device->spec.callback; |
155 udata = audio->spec.userdata; | 172 udata = device->spec.userdata; |
156 | 173 |
157 #if SDL_AUDIO_DRIVER_AHI | 174 #if SDL_AUDIO_DRIVER_AHI |
158 audio_configured = 1; | 175 audio_configured = 1; |
159 | 176 |
160 D(bug("Audio configured... Checking for conversion\n")); | 177 D(bug("Audio configured... Checking for conversion\n")); |
161 SDL_mutexP(audio->mixer_lock); | 178 SDL_mutexP(audio->mixer_lock); |
162 D(bug("Semaphore obtained...\n")); | 179 D(bug("Semaphore obtained...\n")); |
163 #endif | 180 #endif |
164 | 181 |
165 if (audio->convert.needed) { | 182 if (device->convert.needed) { |
166 if (audio->convert.src_format == AUDIO_U8) { | 183 if (device->convert.src_format == AUDIO_U8) { |
167 silence = 0x80; | 184 silence = 0x80; |
168 } else { | 185 } else { |
169 silence = 0; | 186 silence = 0; |
170 } | 187 } |
171 stream_len = audio->convert.len; | 188 stream_len = device->convert.len; |
172 } else { | 189 } else { |
173 silence = audio->spec.silence; | 190 silence = device->spec.silence; |
174 stream_len = audio->spec.size; | 191 stream_len = device->spec.size; |
175 } | 192 } |
176 | 193 |
177 #if SDL_AUDIO_DRIVER_AHI | 194 #if SDL_AUDIO_DRIVER_AHI |
178 SDL_mutexV(audio->mixer_lock); | 195 SDL_mutexV(device->mixer_lock); |
179 D(bug("Entering audio loop...\n")); | 196 D(bug("Entering audio loop...\n")); |
180 #endif | 197 #endif |
181 | 198 |
199 /* !!! FIXME: push this out of core. */ | |
182 #ifdef __OS2__ | 200 #ifdef __OS2__ |
183 /* Increase the priority of this thread to make sure that | 201 /* Increase the priority of this thread to make sure that |
184 the audio will be continuous all the time! */ | 202 the audio will be continuous all the time! */ |
185 #ifdef USE_DOSSETPRIORITY | 203 #ifdef USE_DOSSETPRIORITY |
186 if (SDL_getenv("SDL_USE_TIMECRITICAL_AUDIO")) { | 204 if (SDL_getenv("SDL_USE_TIMECRITICAL_AUDIO")) { |
200 } | 218 } |
201 #endif | 219 #endif |
202 #endif | 220 #endif |
203 | 221 |
204 /* Loop, filling the audio buffers */ | 222 /* Loop, filling the audio buffers */ |
205 while (audio->enabled) { | 223 while (device->enabled) { |
206 | 224 |
207 /* Fill the current buffer with sound */ | 225 /* Fill the current buffer with sound */ |
208 if (audio->convert.needed) { | 226 if (device->convert.needed) { |
209 if (audio->convert.buf) { | 227 if (device->convert.buf) { |
210 stream = audio->convert.buf; | 228 stream = device->convert.buf; |
211 } else { | 229 } else { |
212 continue; | 230 continue; |
213 } | 231 } |
214 } else { | 232 } else { |
215 stream = audio->GetAudioBuf(audio); | 233 stream = current_audio.impl.GetAudioBuf(device); |
216 if (stream == NULL) { | 234 if (stream == NULL) { |
217 stream = audio->fake_stream; | 235 stream = device->fake_stream; |
218 } | 236 } |
219 } | 237 } |
220 SDL_memset(stream, silence, stream_len); | 238 |
221 | 239 /* New code should fill buffer or set it to silence themselves. */ |
222 if (!audio->paused) { | 240 if (legacy_device) { |
223 SDL_mutexP(audio->mixer_lock); | 241 SDL_memset(stream, silence, stream_len); |
242 } | |
243 | |
244 if (!device->paused) { | |
245 SDL_mutexP(device->mixer_lock); | |
224 (*fill) (udata, stream, stream_len); | 246 (*fill) (udata, stream, stream_len); |
225 SDL_mutexV(audio->mixer_lock); | 247 SDL_mutexV(device->mixer_lock); |
226 } | 248 } |
227 | 249 |
228 /* Convert the audio if necessary */ | 250 /* Convert the audio if necessary */ |
229 if (audio->convert.needed) { | 251 if (device->convert.needed) { |
230 SDL_ConvertAudio(&audio->convert); | 252 SDL_ConvertAudio(&device->convert); |
231 stream = audio->GetAudioBuf(audio); | 253 stream = current_audio.impl.GetAudioBuf(device); |
232 if (stream == NULL) { | 254 if (stream == NULL) { |
233 stream = audio->fake_stream; | 255 stream = device->fake_stream; |
234 } | 256 } |
235 SDL_memcpy(stream, audio->convert.buf, audio->convert.len_cvt); | 257 SDL_memcpy(stream, device->convert.buf, device->convert.len_cvt); |
236 } | 258 } |
237 | 259 |
238 /* Ready current buffer for play and change current buffer */ | 260 /* Ready current buffer for play and change current buffer */ |
239 if (stream != audio->fake_stream) { | 261 if (stream != device->fake_stream) { |
240 audio->PlayAudio(audio); | 262 current_audio.impl.PlayAudio(device); |
241 } | 263 } |
242 | 264 |
243 /* Wait for an audio buffer to become available */ | 265 /* Wait for an audio buffer to become available */ |
244 if (stream == audio->fake_stream) { | 266 if (stream == device->fake_stream) { |
245 SDL_Delay((audio->spec.samples * 1000) / audio->spec.freq); | 267 SDL_Delay((device->spec.samples * 1000) / device->spec.freq); |
246 } else { | 268 } else { |
247 audio->WaitAudio(audio); | 269 current_audio.impl.WaitAudio(device); |
248 } | 270 } |
249 } | 271 } |
250 | 272 |
251 /* Wait for the audio to drain.. */ | 273 /* Wait for the audio to drain.. */ |
252 if (audio->WaitDone) { | 274 if (current_audio.impl.WaitDone) { |
253 audio->WaitDone(audio); | 275 current_audio.impl.WaitDone(device); |
254 } | 276 } |
255 #if SDL_AUDIO_DRIVER_AHI | 277 #if SDL_AUDIO_DRIVER_AHI |
256 D(bug("WaitAudio...Done\n")); | 278 D(bug("WaitAudio...Done\n")); |
257 | 279 |
258 audio->CloseAudio(audio); | 280 audio->CloseAudio(audio); |
328 } | 350 } |
329 | 351 |
330 int | 352 int |
331 SDL_AudioInit(const char *driver_name) | 353 SDL_AudioInit(const char *driver_name) |
332 { | 354 { |
333 SDL_AudioDevice *audio; | 355 int i = 0; |
334 int i = 0, idx; | 356 int initialized = 0; |
335 | 357 |
336 /* Check to make sure we don't overwrite 'current_audio' */ | 358 if (SDL_WasInit(SDL_INIT_AUDIO)) { |
337 if (current_audio != NULL) { | 359 SDL_AudioQuit(); /* shutdown driver if already running. */ |
338 SDL_AudioQuit(); | 360 } |
339 } | 361 |
362 SDL_memset(¤t_audio, '\0', sizeof (current_audio)); | |
363 SDL_memset(open_devices, '\0', sizeof (open_devices)); | |
364 | |
365 /* !!! FIXME: build a priority list of available drivers... */ | |
340 | 366 |
341 /* Select the proper audio driver */ | 367 /* Select the proper audio driver */ |
342 audio = NULL; | |
343 idx = 0; | |
344 if (driver_name == NULL) { | 368 if (driver_name == NULL) { |
345 driver_name = SDL_getenv("SDL_AUDIODRIVER"); | 369 driver_name = SDL_getenv("SDL_AUDIODRIVER"); |
346 } | 370 } |
371 | |
372 /* !!! FIXME: move this esound shite into the esound driver... */ | |
347 #if SDL_AUDIO_DRIVER_ESD | 373 #if SDL_AUDIO_DRIVER_ESD |
348 if ((driver_name == NULL) && (SDL_getenv("ESPEAKER") != NULL)) { | 374 if ((driver_name == NULL) && (SDL_getenv("ESPEAKER") != NULL)) { |
349 /* Ahem, we know that if ESPEAKER is set, user probably wants | 375 /* Ahem, we know that if ESPEAKER is set, user probably wants |
350 to use ESD, but don't start it if it's not already running. | 376 to use ESD, but don't start it if it's not already running. |
351 This probably isn't the place to do this, but... Shh! :) | 377 This probably isn't the place to do this, but... Shh! :) |
360 if (esd_no_spawn == NULL) { | 386 if (esd_no_spawn == NULL) { |
361 putenv("ESD_NO_SPAWN=1"); | 387 putenv("ESD_NO_SPAWN=1"); |
362 } | 388 } |
363 #endif | 389 #endif |
364 if (bootstrap[i]->available()) { | 390 if (bootstrap[i]->available()) { |
365 audio = bootstrap[i]->create(0); | 391 SDL_memset(¤t_audio, 0, sizeof (current_audio)); |
392 current_audio.name = bootstrap[i]->name; | |
393 current_audio.desc = bootstrap[i]->desc; | |
394 initialized = bootstrap[i]->init(¤t_audio.impl); | |
366 break; | 395 break; |
367 } | 396 } |
368 #ifdef HAVE_UNSETENV | 397 #ifdef HAVE_UNSETENV |
369 if (esd_no_spawn == NULL) { | 398 if (esd_no_spawn == NULL) { |
370 unsetenv("ESD_NO_SPAWN"); | 399 unsetenv("ESD_NO_SPAWN"); |
372 #endif | 401 #endif |
373 } | 402 } |
374 } | 403 } |
375 } | 404 } |
376 #endif /* SDL_AUDIO_DRIVER_ESD */ | 405 #endif /* SDL_AUDIO_DRIVER_ESD */ |
377 if (audio == NULL) { | 406 |
407 if (!initialized) { | |
378 if (driver_name != NULL) { | 408 if (driver_name != NULL) { |
379 for (i = 0; bootstrap[i]; ++i) { | 409 for (i = 0; bootstrap[i]; ++i) { |
380 if (SDL_strcasecmp(bootstrap[i]->name, driver_name) == 0) { | 410 if (SDL_strcasecmp(bootstrap[i]->name, driver_name) == 0) { |
381 if (bootstrap[i]->available()) { | 411 if (bootstrap[i]->available()) { |
382 audio = bootstrap[i]->create(idx); | 412 SDL_memset(¤t_audio, 0, sizeof (current_audio)); |
413 current_audio.name = bootstrap[i]->name; | |
414 current_audio.desc = bootstrap[i]->desc; | |
415 initialized = bootstrap[i]->init(¤t_audio.impl); | |
383 } | 416 } |
384 break; | 417 break; |
385 } | 418 } |
386 } | 419 } |
387 } else { | 420 } else { |
388 for (i = 0; bootstrap[i]; ++i) { | 421 for (i = 0; (!initialized) && (bootstrap[i]); ++i) { |
389 if (bootstrap[i]->available()) { | 422 if (bootstrap[i]->available()) { |
390 audio = bootstrap[i]->create(idx); | 423 SDL_memset(¤t_audio, 0, sizeof (current_audio)); |
391 if (audio != NULL) { | 424 current_audio.name = bootstrap[i]->name; |
392 break; | 425 current_audio.desc = bootstrap[i]->desc; |
393 } | 426 initialized = bootstrap[i]->init(¤t_audio.impl); |
394 } | 427 } |
395 } | 428 } |
396 } | 429 } |
397 if (audio == NULL) { | 430 if (!initialized) { |
398 if (driver_name) { | 431 if (driver_name) { |
399 SDL_SetError("%s not available", driver_name); | 432 SDL_SetError("%s not available", driver_name); |
400 } else { | 433 } else { |
401 SDL_SetError("No available audio device"); | 434 SDL_SetError("No available audio device"); |
402 } | 435 } |
403 #if 0 | 436 SDL_memset(¤t_audio, 0, sizeof (current_audio)); |
404 /* Don't fail SDL_Init() if audio isn't available. | 437 return (-1); /* No driver was available, so fail. */ |
405 SDL_OpenAudio() will handle it at that point. *sigh* | 438 } |
406 */ | 439 } |
407 return (-1); | 440 |
408 #endif | 441 if (!current_audio.impl.LockAudio && !current_audio.impl.UnlockAudio) { |
409 } | 442 current_audio.impl.LockAudio = SDL_LockAudio_Default; |
410 } | 443 current_audio.impl.UnlockAudio = SDL_UnlockAudio_Default; |
411 current_audio = audio; | |
412 if (current_audio) { | |
413 current_audio->name = bootstrap[i]->name; | |
414 if (!current_audio->LockAudio && !current_audio->UnlockAudio) { | |
415 current_audio->LockAudio = SDL_LockAudio_Default; | |
416 current_audio->UnlockAudio = SDL_UnlockAudio_Default; | |
417 } | |
418 } | 444 } |
419 return (0); | 445 return (0); |
420 } | 446 } |
421 | 447 |
422 /* | 448 /* |
423 * Get the current audio driver name | 449 * Get the current audio driver name |
424 */ | 450 */ |
425 const char * | 451 const char * |
426 SDL_GetCurrentAudioDriver() | 452 SDL_GetCurrentAudioDriver() |
427 { | 453 { |
428 if (current_audio) { | 454 return current_audio.name; |
429 return current_audio->name; | 455 } |
430 } | 456 |
431 return (NULL); | 457 static void |
432 } | 458 close_audio_device(SDL_AudioDevice *device) |
433 | 459 { |
434 int | 460 device->enabled = 0; |
435 SDL_OpenAudio(SDL_AudioSpec * desired, SDL_AudioSpec * obtained) | 461 if (device->thread != NULL) { |
436 { | 462 SDL_WaitThread(device->thread, NULL); |
437 SDL_AudioDevice *audio; | 463 } |
438 const char *env; | 464 if (device->mixer_lock != NULL) { |
439 | 465 SDL_DestroyMutex(device->mixer_lock); |
440 /* Start up the audio driver, if necessary */ | 466 } |
441 if (!current_audio) { | 467 if (device->fake_stream != NULL) { |
442 if ((SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) || | 468 SDL_FreeAudioMem(device->fake_stream); |
443 (current_audio == NULL)) { | 469 } |
444 return (-1); | 470 if (device->convert.needed) { |
445 } | 471 SDL_FreeAudioMem(device->convert.buf); |
446 } | 472 } |
447 audio = current_audio; | 473 #if !SDL_AUDIO_DRIVER_AHI /* !!! FIXME: get rid of this #if. */ |
448 | 474 if (device->opened) { |
449 if (audio->opened) { | 475 current_audio.impl.CloseAudio(device); |
450 SDL_SetError("Audio device is already opened"); | 476 device->opened = 0; |
451 return (-1); | 477 } |
452 } | 478 #endif |
453 | 479 SDL_FreeAudioMem(device); |
454 /* Verify some parameters */ | 480 } |
455 if (desired->freq == 0) { | 481 |
456 env = SDL_getenv("SDL_AUDIO_FREQUENCY"); | 482 |
457 if (env) { | 483 /* |
458 desired->freq = SDL_atoi(env); | 484 * Sanity check desired AudioSpec for SDL_OpenAudio() in (orig). |
459 } | 485 * Fills in a sanitized copy in (prepared). |
460 } | 486 * Returns non-zero if okay, zero on fatal parameters in (orig). |
461 if (desired->freq == 0) { | 487 */ |
462 /* Pick some default audio frequency */ | 488 static int |
463 desired->freq = 22050; | 489 prepare_audiospec(const SDL_AudioSpec *orig, SDL_AudioSpec *prepared) |
464 } | 490 { |
465 if (desired->format == 0) { | 491 SDL_memcpy(prepared, orig, sizeof (SDL_AudioSpec)); |
466 env = SDL_getenv("SDL_AUDIO_FORMAT"); | 492 |
467 if (env) { | 493 if (orig->callback == NULL) { |
468 desired->format = SDL_ParseAudioFormat(env); | 494 SDL_SetError("SDL_OpenAudio() passed a NULL callback"); |
469 } | 495 return 0; |
470 } | 496 } |
471 if (desired->format == 0) { | 497 |
472 /* Pick some default audio format */ | 498 if (orig->freq == 0) { |
473 desired->format = AUDIO_S16; | 499 const char *env = SDL_getenv("SDL_AUDIO_FREQUENCY"); |
474 } | 500 if ( (!env) || ((prepared->freq = SDL_atoi(env)) == 0) ) { |
475 if (desired->channels == 0) { | 501 prepared->freq = 22050; /* a reasonable default */ |
476 env = SDL_getenv("SDL_AUDIO_CHANNELS"); | 502 } |
477 if (env) { | 503 } |
478 desired->channels = (Uint8) SDL_atoi(env); | 504 |
479 } | 505 if (orig->format == 0) { |
480 } | 506 const char *env = SDL_getenv("SDL_AUDIO_FORMAT"); |
481 if (desired->channels == 0) { | 507 if ((!env) || ((prepared->format = SDL_ParseAudioFormat(env)) == 0)) { |
482 /* Pick a default number of channels */ | 508 prepared->format = AUDIO_S16; /* a reasonable default */ |
483 desired->channels = 2; | 509 } |
484 } | 510 } |
485 switch (desired->channels) { | 511 |
512 switch (orig->channels) { | |
513 case 0: { | |
514 const char *env = SDL_getenv("SDL_AUDIO_CHANNELS"); | |
515 if ( (!env) || ((prepared->channels = SDL_atoi(env)) == 0) ) { | |
516 prepared->channels = 2; /* a reasonable default */ | |
517 } | |
518 break; | |
519 } | |
486 case 1: /* Mono */ | 520 case 1: /* Mono */ |
487 case 2: /* Stereo */ | 521 case 2: /* Stereo */ |
488 case 4: /* surround */ | 522 case 4: /* surround */ |
489 case 6: /* surround with center and lfe */ | 523 case 6: /* surround with center and lfe */ |
490 break; | 524 break; |
491 default: | 525 default: |
492 SDL_SetError("1 (mono) and 2 (stereo) channels supported"); | 526 SDL_SetError("Unsupported number of audio channels."); |
493 return (-1); | 527 return 0; |
494 } | 528 } |
495 if (desired->samples == 0) { | 529 |
496 env = SDL_getenv("SDL_AUDIO_SAMPLES"); | 530 if (orig->samples == 0) { |
497 if (env) { | 531 const char *env = SDL_getenv("SDL_AUDIO_SAMPLES"); |
498 desired->samples = (Uint16) SDL_atoi(env); | 532 if ( (!env) || ((prepared->samples = (Uint16) SDL_atoi(env)) == 0) ) { |
499 } | 533 /* Pick a default of ~46 ms at desired frequency */ |
500 } | 534 /* !!! FIXME: remove this when the non-Po2 resampling is in. */ |
501 if (desired->samples == 0) { | 535 const int samples = (prepared->freq / 1000) * 46; |
502 /* Pick a default of ~46 ms at desired frequency */ | 536 int power2 = 1; |
503 int samples = (desired->freq / 1000) * 46; | 537 while (power2 < samples) { |
504 int power2 = 1; | 538 power2 *= 2; |
505 while (power2 < samples) { | 539 } |
506 power2 *= 2; | 540 prepared->samples = power2; |
507 } | 541 } |
508 desired->samples = power2; | 542 } |
509 } | 543 |
510 if (desired->callback == NULL) { | 544 /* Calculate the silence and size of the audio specification */ |
511 SDL_SetError("SDL_OpenAudio() passed a NULL callback"); | 545 SDL_CalculateAudioSpec(prepared); |
512 return (-1); | 546 |
513 } | 547 return 1; |
548 } | |
549 | |
550 | |
551 static SDL_AudioDeviceID | |
552 open_audio_device(const char *devname, int iscapture, | |
553 const SDL_AudioSpec *_desired, SDL_AudioSpec *obtained, | |
554 int min_id) | |
555 { | |
556 int i = 0; | |
557 SDL_AudioDeviceID id = 0; | |
558 SDL_AudioSpec desired; | |
559 SDL_AudioDevice *device; | |
560 | |
561 if (iscapture) { | |
562 SDL_SetError("Audio capture support not implemented yet!"); | |
563 return 0; /* !!! FIXME */ | |
564 } | |
565 | |
566 if (!SDL_WasInit(SDL_INIT_AUDIO)) { | |
567 SDL_SetError("Audio subsystem is not initialized"); | |
568 return 0; | |
569 } | |
570 | |
571 if (!prepare_audiospec(_desired, &desired)) { | |
572 return 0; | |
573 } | |
574 | |
575 device = (SDL_AudioDevice *) SDL_AllocAudioMem(sizeof (SDL_AudioDevice)); | |
576 if (device == NULL) { | |
577 SDL_OutOfMemory(); | |
578 return 0; | |
579 } | |
580 SDL_memset(device, '\0', sizeof (SDL_AudioDevice)); | |
581 SDL_memcpy(&device->spec, &desired, sizeof (SDL_AudioSpec)); | |
582 device->driver = ¤t_audio; /* !!! FIXME: unused... */ | |
583 device->enabled = 1; | |
584 device->paused = 1; | |
585 | |
586 /* !!! FIXME: Get this out of the core. */ | |
514 #if defined(__MINT__) && SDL_THREADS_DISABLED | 587 #if defined(__MINT__) && SDL_THREADS_DISABLED |
515 /* Uses interrupt driven audio, without thread */ | 588 /* Uses interrupt driven audio, without thread */ |
516 #else | 589 #else |
517 /* Create a semaphore for locking the sound buffers */ | 590 /* Create a semaphore for locking the sound buffers */ |
518 audio->mixer_lock = SDL_CreateMutex(); | 591 device->mixer_lock = SDL_CreateMutex(); |
519 if (audio->mixer_lock == NULL) { | 592 if (device->mixer_lock == NULL) { |
520 SDL_SetError("Couldn't create mixer lock"); | 593 SDL_SetError("Couldn't create mixer lock"); |
521 SDL_CloseAudio(); | 594 return 0; |
522 return (-1); | |
523 } | 595 } |
524 #endif /* __MINT__ */ | 596 #endif /* __MINT__ */ |
525 | 597 |
526 /* Calculate the silence and size of the audio specification */ | 598 /* !!! FIXME: Get this #if out of the core. */ |
527 SDL_CalculateAudioSpec(desired); | 599 /* AmigaOS opens audio inside the main loop */ |
528 | |
529 /* Open the audio subsystem */ | |
530 SDL_memcpy(&audio->spec, desired, sizeof(audio->spec)); | |
531 audio->convert.needed = 0; | |
532 audio->enabled = 1; | |
533 audio->paused = 1; | |
534 | |
535 #if !SDL_AUDIO_DRIVER_AHI | 600 #if !SDL_AUDIO_DRIVER_AHI |
536 | 601 if (!current_audio.impl.OpenAudio(device, devname, iscapture)) { |
537 /* AmigaOS opens audio inside the main loop */ | 602 close_audio_device(device); |
538 audio->opened = audio->OpenAudio(audio, &audio->spec) + 1; | 603 return 0; |
539 | 604 } |
540 if (!audio->opened) { | 605 device->opened = 2; /* !!! FIXME */ |
541 SDL_CloseAudio(); | |
542 return (-1); | |
543 } | |
544 #else | 606 #else |
607 # error needs to be fixed for new internal API. Email Ryan for details. | |
608 | |
545 D(bug("Locking semaphore...")); | 609 D(bug("Locking semaphore...")); |
546 SDL_mutexP(audio->mixer_lock); | 610 SDL_mutexP(audio->mixer_lock); |
547 | 611 |
548 | 612 |
549 audio->thread = SDL_CreateThread(SDL_RunAudio, audio); | 613 audio->thread = SDL_CreateThread(SDL_RunAudio, audio); |
551 | 615 |
552 if (audio->thread == NULL) { | 616 if (audio->thread == NULL) { |
553 SDL_mutexV(audio->mixer_lock); | 617 SDL_mutexV(audio->mixer_lock); |
554 SDL_CloseAudio(); | 618 SDL_CloseAudio(); |
555 SDL_SetError("Couldn't create audio thread"); | 619 SDL_SetError("Couldn't create audio thread"); |
556 return (-1); | 620 return 0; |
557 } | 621 } |
558 | 622 |
559 while (!audio_configured) | 623 while (!audio_configured) |
560 SDL_Delay(100); | 624 SDL_Delay(100); |
561 #endif | 625 #endif |
562 | 626 |
563 /* If the audio driver changes the buffer size, accept it */ | 627 /* If the audio driver changes the buffer size, accept it */ |
564 if (audio->spec.samples != desired->samples) { | 628 if (device->spec.samples != desired.samples) { |
565 desired->samples = audio->spec.samples; | 629 desired.samples = device->spec.samples; |
566 SDL_CalculateAudioSpec(desired); | 630 SDL_CalculateAudioSpec(&device->spec); |
567 } | 631 } |
568 | 632 |
569 /* Allocate a fake audio memory buffer */ | 633 /* Allocate a fake audio memory buffer */ |
570 audio->fake_stream = SDL_AllocAudioMem(audio->spec.size); | 634 device->fake_stream = SDL_AllocAudioMem(device->spec.size); |
571 if (audio->fake_stream == NULL) { | 635 if (device->fake_stream == NULL) { |
572 SDL_CloseAudio(); | 636 close_audio_device(device); |
573 SDL_OutOfMemory(); | 637 SDL_OutOfMemory(); |
574 return (-1); | 638 return 0; |
575 } | 639 } |
576 | 640 |
577 /* See if we need to do any conversion */ | 641 /* See if we need to do any conversion */ |
578 if (obtained != NULL) { | 642 if (obtained != NULL) { |
579 SDL_memcpy(obtained, &audio->spec, sizeof(audio->spec)); | 643 SDL_memcpy(obtained, &device->spec, sizeof(SDL_AudioSpec)); |
580 } else if (desired->freq != audio->spec.freq || | 644 } else if (desired.freq != device->spec.freq || |
581 desired->format != audio->spec.format || | 645 desired.format != device->spec.format || |
582 desired->channels != audio->spec.channels) { | 646 desired.channels != device->spec.channels) { |
583 /* Build an audio conversion block */ | 647 /* Build an audio conversion block */ |
584 if (SDL_BuildAudioCVT(&audio->convert, | 648 if (SDL_BuildAudioCVT(&device->convert, |
585 desired->format, desired->channels, | 649 desired.format, desired.channels, |
586 desired->freq, | 650 desired.freq, |
587 audio->spec.format, audio->spec.channels, | 651 device->spec.format, device->spec.channels, |
588 audio->spec.freq) < 0) { | 652 device->spec.freq) < 0) { |
589 SDL_CloseAudio(); | 653 close_audio_device(device); |
590 return (-1); | 654 return 0; |
591 } | 655 } |
592 if (audio->convert.needed) { | 656 if (device->convert.needed) { |
593 audio->convert.len = desired->size; | 657 device->convert.len = desired.size; |
594 audio->convert.buf = | 658 device->convert.buf = |
595 (Uint8 *) SDL_AllocAudioMem(audio->convert.len * | 659 (Uint8 *) SDL_AllocAudioMem(device->convert.len * |
596 audio->convert.len_mult); | 660 device->convert.len_mult); |
597 if (audio->convert.buf == NULL) { | 661 if (device->convert.buf == NULL) { |
598 SDL_CloseAudio(); | 662 close_audio_device(device); |
599 SDL_OutOfMemory(); | 663 SDL_OutOfMemory(); |
600 return (-1); | 664 return 0; |
601 } | 665 } |
602 } | 666 } |
603 } | 667 } |
668 | |
669 /* Find an available device ID and store the structure... */ | |
670 for (id = min_id-1; id < SDL_arraysize(open_devices); id++) { | |
671 if (open_devices[id] == NULL) { | |
672 open_devices[id] = device; | |
673 break; | |
674 } | |
675 } | |
676 | |
677 /* !!! FIXME: remove static array... */ | |
678 if (id == SDL_arraysize(open_devices)) { | |
679 SDL_SetError("Too many open audio devices"); | |
680 close_audio_device(device); | |
681 return 0; | |
682 } | |
683 | |
604 #if !SDL_AUDIO_DRIVER_AHI | 684 #if !SDL_AUDIO_DRIVER_AHI |
605 /* Start the audio thread if necessary */ | 685 /* Start the audio thread if necessary */ |
606 switch (audio->opened) { | 686 switch (device->opened) { /* !!! FIXME: what is this?! */ |
607 case 1: | 687 case 1: |
608 /* Start the audio thread */ | 688 /* Start the audio thread */ |
689 /* !!! FIXME: this is nasty. */ | |
609 #if (defined(__WIN32__) && !defined(_WIN32_WCE)) && !defined(HAVE_LIBC) | 690 #if (defined(__WIN32__) && !defined(_WIN32_WCE)) && !defined(HAVE_LIBC) |
610 #undef SDL_CreateThread | 691 #undef SDL_CreateThread |
611 audio->thread = SDL_CreateThread(SDL_RunAudio, audio, NULL, NULL); | 692 device->thread = SDL_CreateThread(SDL_RunAudio, device, NULL, NULL); |
612 #else | 693 #else |
613 audio->thread = SDL_CreateThread(SDL_RunAudio, audio); | 694 device->thread = SDL_CreateThread(SDL_RunAudio, device); |
614 #endif | 695 #endif |
615 if (audio->thread == NULL) { | 696 if (device->thread == NULL) { |
616 SDL_CloseAudio(); | 697 SDL_CloseAudioDevice(id+1); |
617 SDL_SetError("Couldn't create audio thread"); | 698 SDL_SetError("Couldn't create audio thread"); |
618 return (-1); | 699 return 0; |
619 } | 700 } |
620 break; | 701 break; |
621 | 702 |
622 default: | 703 default: |
623 /* The audio is now playing */ | 704 /* The audio is now playing */ |
627 SDL_mutexV(audio->mixer_lock); | 708 SDL_mutexV(audio->mixer_lock); |
628 D(bug("SDL_OpenAudio USCITA...\n")); | 709 D(bug("SDL_OpenAudio USCITA...\n")); |
629 | 710 |
630 #endif | 711 #endif |
631 | 712 |
632 return (0); | 713 return id+1; |
714 } | |
715 | |
716 | |
717 int | |
718 SDL_OpenAudio(const SDL_AudioSpec * desired, SDL_AudioSpec * obtained) | |
719 { | |
720 SDL_AudioDeviceID id = 0; | |
721 | |
722 /* Start up the audio driver, if necessary. This is legacy behaviour! */ | |
723 if (!SDL_WasInit(SDL_INIT_AUDIO)) { | |
724 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) { | |
725 return (-1); | |
726 } | |
727 } | |
728 | |
729 /* SDL_OpenAudio() is legacy and can only act on Device ID #1. */ | |
730 if (open_devices[0] != NULL) { | |
731 SDL_SetError("Audio device is already opened"); | |
732 return (-1); | |
733 } | |
734 | |
735 id = open_audio_device(NULL, 0, desired, obtained, 1); | |
736 if (id > 1) { /* this should never happen in theory... */ | |
737 SDL_CloseAudioDevice(id); | |
738 SDL_SetError("Internal error"); /* MUST be Device ID #1! */ | |
739 return (-1); | |
740 } | |
741 | |
742 return ((id == 0) ? -1 : 0); | |
743 } | |
744 | |
745 SDL_AudioDeviceID | |
746 SDL_OpenAudioDevice(const char *device, int iscapture, | |
747 const SDL_AudioSpec *desired, SDL_AudioSpec *obtained) | |
748 { | |
749 return open_audio_device(device, iscapture, desired, obtained, 2); | |
633 } | 750 } |
634 | 751 |
635 SDL_audiostatus | 752 SDL_audiostatus |
636 SDL_GetAudioStatus(void) | 753 SDL_GetAudioDeviceStatus(SDL_AudioDeviceID devid) |
637 { | 754 { |
638 SDL_AudioDevice *audio = current_audio; | 755 SDL_AudioDevice *device = get_audio_device(devid); |
639 SDL_audiostatus status; | 756 SDL_audiostatus status = SDL_AUDIO_STOPPED; |
640 | 757 if (device && device->enabled) { |
641 status = SDL_AUDIO_STOPPED; | 758 if (device->paused) { |
642 if (audio && audio->enabled) { | |
643 if (audio->paused) { | |
644 status = SDL_AUDIO_PAUSED; | 759 status = SDL_AUDIO_PAUSED; |
645 } else { | 760 } else { |
646 status = SDL_AUDIO_PLAYING; | 761 status = SDL_AUDIO_PLAYING; |
647 } | 762 } |
648 } | 763 } |
649 return (status); | 764 return (status); |
650 } | 765 } |
651 | 766 |
767 | |
768 SDL_audiostatus | |
769 SDL_GetAudioStatus(void) | |
770 { | |
771 return SDL_GetAudioDeviceStatus(1); | |
772 } | |
773 | |
774 void | |
775 SDL_PauseAudioDevice(SDL_AudioDeviceID devid, int pause_on) | |
776 { | |
777 SDL_AudioDevice *device = get_audio_device(devid); | |
778 if (device) { | |
779 device->paused = pause_on; | |
780 } | |
781 } | |
782 | |
652 void | 783 void |
653 SDL_PauseAudio(int pause_on) | 784 SDL_PauseAudio(int pause_on) |
654 { | 785 { |
655 SDL_AudioDevice *audio = current_audio; | 786 SDL_PauseAudioDevice(1, pause_on); |
656 | 787 } |
657 if (audio) { | 788 |
658 audio->paused = pause_on; | 789 |
790 void | |
791 SDL_LockAudioDevice(SDL_AudioDeviceID devid) | |
792 { | |
793 if (current_audio.impl.LockAudio != NULL) { | |
794 SDL_AudioDevice *device = get_audio_device(devid); | |
795 /* Obtain a lock on the mixing buffers */ | |
796 if (device) { | |
797 current_audio.impl.LockAudio(device); | |
798 } | |
659 } | 799 } |
660 } | 800 } |
661 | 801 |
662 void | 802 void |
663 SDL_LockAudio(void) | 803 SDL_LockAudio(void) |
664 { | 804 { |
665 SDL_AudioDevice *audio = current_audio; | 805 SDL_LockAudioDevice(1); |
666 | 806 } |
667 /* Obtain a lock on the mixing buffers */ | 807 |
668 if (audio && audio->LockAudio) { | 808 void |
669 audio->LockAudio(audio); | 809 SDL_UnlockAudioDevice(SDL_AudioDeviceID devid) |
810 { | |
811 if (current_audio.impl.UnlockAudio != NULL) { | |
812 SDL_AudioDevice *device = get_audio_device(devid); | |
813 /* Obtain a lock on the mixing buffers */ | |
814 if (device) { | |
815 current_audio.impl.UnlockAudio(device); | |
816 } | |
670 } | 817 } |
671 } | 818 } |
672 | 819 |
673 void | 820 void |
674 SDL_UnlockAudio(void) | 821 SDL_UnlockAudio(void) |
675 { | 822 { |
676 SDL_AudioDevice *audio = current_audio; | 823 SDL_UnlockAudioDevice(1); |
677 | 824 } |
678 /* Release lock on the mixing buffers */ | 825 |
679 if (audio && audio->UnlockAudio) { | 826 void |
680 audio->UnlockAudio(audio); | 827 SDL_CloseAudioDevice(SDL_AudioDeviceID devid) |
828 { | |
829 SDL_AudioDevice *device = get_audio_device(devid); | |
830 if (device) { | |
831 close_audio_device(device); | |
832 open_devices[devid-1] = NULL; | |
681 } | 833 } |
682 } | 834 } |
683 | 835 |
684 void | 836 void |
685 SDL_CloseAudio(void) | 837 SDL_CloseAudio(void) |
686 { | 838 { |
687 SDL_QuitSubSystem(SDL_INIT_AUDIO); | 839 SDL_CloseAudioDevice(1); |
688 } | 840 } |
689 | 841 |
690 void | 842 void |
691 SDL_AudioQuit(void) | 843 SDL_AudioQuit(void) |
692 { | 844 { |
693 SDL_AudioDevice *audio = current_audio; | 845 SDL_AudioDeviceID i; |
694 | 846 for (i = 0; i < SDL_arraysize(open_devices); i++) { |
695 if (audio) { | 847 SDL_CloseAudioDevice(i); |
696 audio->enabled = 0; | 848 } |
697 if (audio->thread != NULL) { | 849 /* Free the driver data */ |
698 SDL_WaitThread(audio->thread, NULL); | 850 |
699 } | 851 /* !!! FIXME! current_audio.free(¤t_audio); */ |
700 if (audio->mixer_lock != NULL) { | 852 SDL_memset(¤t_audio, '\0', sizeof (current_audio)); |
701 SDL_DestroyMutex(audio->mixer_lock); | 853 SDL_memset(open_devices, '\0', sizeof (open_devices)); |
702 } | |
703 if (audio->fake_stream != NULL) { | |
704 SDL_FreeAudioMem(audio->fake_stream); | |
705 } | |
706 if (audio->convert.needed) { | |
707 SDL_FreeAudioMem(audio->convert.buf); | |
708 | |
709 } | |
710 #if !SDL_AUDIO_DRIVER_AHI | |
711 if (audio->opened) { | |
712 audio->CloseAudio(audio); | |
713 audio->opened = 0; | |
714 } | |
715 #endif | |
716 /* Free the driver data */ | |
717 audio->free(audio); | |
718 current_audio = NULL; | |
719 } | |
720 } | 854 } |
721 | 855 |
722 #define NUM_FORMATS 10 | 856 #define NUM_FORMATS 10 |
723 static int format_idx; | 857 static int format_idx; |
724 static int format_idx_sub; | 858 static int format_idx_sub; |
775 break; | 909 break; |
776 default: | 910 default: |
777 spec->silence = 0x00; | 911 spec->silence = 0x00; |
778 break; | 912 break; |
779 } | 913 } |
780 spec->size = (spec->format & 0xFF) / 8; | 914 spec->size = SDL_AUDIO_BITSIZE(spec->format) / 8; |
781 spec->size *= spec->channels; | 915 spec->size *= spec->channels; |
782 spec->size *= spec->samples; | 916 spec->size *= spec->samples; |
783 } | 917 } |
784 | 918 |
919 | |
920 /* | |
921 * Moved here from SDL_mixer.c, since it relies on internals of an opened | |
922 * audio device (and is deprecated, by the way!). | |
923 */ | |
924 void | |
925 SDL_MixAudio(Uint8 * dst, const Uint8 * src, Uint32 len, int volume) | |
926 { | |
927 /* Mix the user-level audio format */ | |
928 SDL_AudioDevice *device = get_audio_device(1); | |
929 if (device != NULL) { | |
930 SDL_AudioFormat format; | |
931 if (device->convert.needed) { | |
932 format = device->convert.src_format; | |
933 } else { | |
934 format = device->spec.format; | |
935 } | |
936 SDL_MixAudioFormat(dst, src, format, len, volume); | |
937 } | |
938 } | |
939 | |
785 /* vi: set ts=4 sw=4 expandtab: */ | 940 /* vi: set ts=4 sw=4 expandtab: */ |