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(&current_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(&current_audio, 0, sizeof (current_audio));
392 current_audio.name = bootstrap[i]->name;
393 current_audio.desc = bootstrap[i]->desc;
394 initialized = bootstrap[i]->init(&current_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(&current_audio, 0, sizeof (current_audio));
413 current_audio.name = bootstrap[i]->name;
414 current_audio.desc = bootstrap[i]->desc;
415 initialized = bootstrap[i]->init(&current_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(&current_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(&current_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(&current_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 = &current_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(&current_audio); */
700 if (audio->mixer_lock != NULL) { 852 SDL_memset(&current_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: */