1/* 2 SDL - Simple DirectMedia Layer 3 Copyright (C) 1997-2012 Sam Lantinga 4 5 This library is free software; you can redistribute it and/or 6 modify it under the terms of the GNU Lesser General Public 7 License as published by the Free Software Foundation; either 8 version 2.1 of the License, or (at your option) any later version. 9 10 This library is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public 16 License along with this library; if not, write to the Free Software 17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 19 Sam Lantinga 20 slouken@libsdl.org 21*/ 22#include "SDL_config.h" 23 24/* Allow access to a raw mixing buffer */ 25 26#include "SDL.h" 27#include "SDL_audio_c.h" 28#include "SDL_audiomem.h" 29#include "SDL_sysaudio.h" 30 31#ifdef __OS2__ 32/* We'll need the DosSetPriority() API! */ 33#define INCL_DOSPROCESS 34#include <os2.h> 35#endif 36 37/* Available audio drivers */ 38static AudioBootStrap *bootstrap[] = { 39#if SDL_AUDIO_DRIVER_PULSE 40 &PULSE_bootstrap, 41#endif 42#if SDL_AUDIO_DRIVER_ALSA 43 &ALSA_bootstrap, 44#endif 45#if SDL_AUDIO_DRIVER_BSD 46 &BSD_AUDIO_bootstrap, 47#endif 48#if SDL_AUDIO_DRIVER_OSS 49 &DSP_bootstrap, 50 &DMA_bootstrap, 51#endif 52#if SDL_AUDIO_DRIVER_QNXNTO 53 &QNXNTOAUDIO_bootstrap, 54#endif 55#if SDL_AUDIO_DRIVER_SUNAUDIO 56 &SUNAUDIO_bootstrap, 57#endif 58#if SDL_AUDIO_DRIVER_DMEDIA 59 &DMEDIA_bootstrap, 60#endif 61#if SDL_AUDIO_DRIVER_ARTS 62 &ARTS_bootstrap, 63#endif 64#if SDL_AUDIO_DRIVER_ESD 65 &ESD_bootstrap, 66#endif 67#if SDL_AUDIO_DRIVER_NAS 68 &NAS_bootstrap, 69#endif 70#if SDL_AUDIO_DRIVER_DSOUND 71 &DSOUND_bootstrap, 72#endif 73#if SDL_AUDIO_DRIVER_WAVEOUT 74 &WAVEOUT_bootstrap, 75#endif 76#if SDL_AUDIO_DRIVER_PAUD 77 &Paud_bootstrap, 78#endif 79#if SDL_AUDIO_DRIVER_BAUDIO 80 &BAUDIO_bootstrap, 81#endif 82#if SDL_AUDIO_DRIVER_COREAUDIO 83 &COREAUDIO_bootstrap, 84#endif 85#if SDL_AUDIO_DRIVER_SNDMGR 86 &SNDMGR_bootstrap, 87#endif 88#if SDL_AUDIO_DRIVER_MINT 89 &MINTAUDIO_GSXB_bootstrap, 90 &MINTAUDIO_MCSN_bootstrap, 91 &MINTAUDIO_STFA_bootstrap, 92 &MINTAUDIO_XBIOS_bootstrap, 93 &MINTAUDIO_DMA8_bootstrap, 94#endif 95#if SDL_AUDIO_DRIVER_DISK 96 &DISKAUD_bootstrap, 97#endif 98#if SDL_AUDIO_DRIVER_DUMMY 99 &DUMMYAUD_bootstrap, 100#endif 101#if SDL_AUDIO_DRIVER_DC 102 &DCAUD_bootstrap, 103#endif 104#if SDL_AUDIO_DRIVER_NDS 105 &NDSAUD_bootstrap, 106#endif 107#if SDL_AUDIO_DRIVER_MMEAUDIO 108 &MMEAUDIO_bootstrap, 109#endif 110#if SDL_AUDIO_DRIVER_DART 111 &DART_bootstrap, 112#endif 113#if SDL_AUDIO_DRIVER_EPOCAUDIO 114 &EPOCAudio_bootstrap, 115#endif 116 NULL 117}; 118SDL_AudioDevice *current_audio = NULL; 119 120/* Various local functions */ 121int SDL_AudioInit(const char *driver_name); 122void SDL_AudioQuit(void); 123 124/* The general mixing thread function */ 125int SDLCALL SDL_RunAudio(void *audiop) 126{ 127 SDL_AudioDevice *audio = (SDL_AudioDevice *)audiop; 128 Uint8 *stream; 129 int stream_len; 130 void *udata; 131 void (SDLCALL *fill)(void *userdata,Uint8 *stream, int len); 132 int silence; 133 134 /* Perform any thread setup */ 135 if ( audio->ThreadInit ) { 136 audio->ThreadInit(audio); 137 } 138 audio->threadid = SDL_ThreadID(); 139 140 /* Set up the mixing function */ 141 fill = audio->spec.callback; 142 udata = audio->spec.userdata; 143 144 if ( audio->convert.needed ) { 145 if ( audio->convert.src_format == AUDIO_U8 ) { 146 silence = 0x80; 147 } else { 148 silence = 0; 149 } 150 stream_len = audio->convert.len; 151 } else { 152 silence = audio->spec.silence; 153 stream_len = audio->spec.size; 154 } 155 156#ifdef __OS2__ 157 /* Increase the priority of this thread to make sure that 158 the audio will be continuous all the time! */ 159#ifdef USE_DOSSETPRIORITY 160 if (SDL_getenv("SDL_USE_TIMECRITICAL_AUDIO")) 161 { 162#ifdef DEBUG_BUILD 163 printf("[SDL_RunAudio] : Setting priority to TimeCritical+0! (TID%d)\n", SDL_ThreadID()); 164#endif 165 DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0); 166 } 167 else 168 { 169#ifdef DEBUG_BUILD 170 printf("[SDL_RunAudio] : Setting priority to ForegroundServer+0! (TID%d)\n", SDL_ThreadID()); 171#endif 172 DosSetPriority(PRTYS_THREAD, PRTYC_FOREGROUNDSERVER, 0, 0); 173 } 174#endif 175#endif 176 177 /* Loop, filling the audio buffers */ 178 while ( audio->enabled ) { 179 180 /* Fill the current buffer with sound */ 181 if ( audio->convert.needed ) { 182 if ( audio->convert.buf ) { 183 stream = audio->convert.buf; 184 } else { 185 continue; 186 } 187 } else { 188 stream = audio->GetAudioBuf(audio); 189 if ( stream == NULL ) { 190 stream = audio->fake_stream; 191 } 192 } 193 194 SDL_memset(stream, silence, stream_len); 195 196 if ( ! audio->paused ) { 197 SDL_mutexP(audio->mixer_lock); 198 (*fill)(udata, stream, stream_len); 199 SDL_mutexV(audio->mixer_lock); 200 } 201 202 /* Convert the audio if necessary */ 203 if ( audio->convert.needed ) { 204 SDL_ConvertAudio(&audio->convert); 205 stream = audio->GetAudioBuf(audio); 206 if ( stream == NULL ) { 207 stream = audio->fake_stream; 208 } 209 SDL_memcpy(stream, audio->convert.buf, 210 audio->convert.len_cvt); 211 } 212 213 /* Ready current buffer for play and change current buffer */ 214 if ( stream != audio->fake_stream ) { 215 audio->PlayAudio(audio); 216 } 217 218 /* Wait for an audio buffer to become available */ 219 if ( stream == audio->fake_stream ) { 220 SDL_Delay((audio->spec.samples*1000)/audio->spec.freq); 221 } else { 222 audio->WaitAudio(audio); 223 } 224 } 225 226 /* Wait for the audio to drain.. */ 227 if ( audio->WaitDone ) { 228 audio->WaitDone(audio); 229 } 230 231#ifdef __OS2__ 232#ifdef DEBUG_BUILD 233 printf("[SDL_RunAudio] : Task exiting. (TID%d)\n", SDL_ThreadID()); 234#endif 235#endif 236 return(0); 237} 238 239static void SDL_LockAudio_Default(SDL_AudioDevice *audio) 240{ 241 if ( audio->thread && (SDL_ThreadID() == audio->threadid) ) { 242 return; 243 } 244 SDL_mutexP(audio->mixer_lock); 245} 246 247static void SDL_UnlockAudio_Default(SDL_AudioDevice *audio) 248{ 249 if ( audio->thread && (SDL_ThreadID() == audio->threadid) ) { 250 return; 251 } 252 SDL_mutexV(audio->mixer_lock); 253} 254 255static Uint16 SDL_ParseAudioFormat(const char *string) 256{ 257 Uint16 format = 0; 258 259 switch (*string) { 260 case 'U': 261 ++string; 262 format |= 0x0000; 263 break; 264 case 'S': 265 ++string; 266 format |= 0x8000; 267 break; 268 default: 269 return 0; 270 } 271 switch (SDL_atoi(string)) { 272 case 8: 273 string += 1; 274 format |= 8; 275 break; 276 case 16: 277 string += 2; 278 format |= 16; 279 if ( SDL_strcmp(string, "LSB") == 0 280#if SDL_BYTEORDER == SDL_LIL_ENDIAN 281 || SDL_strcmp(string, "SYS") == 0 282#endif 283 ) { 284 format |= 0x0000; 285 } 286 if ( SDL_strcmp(string, "MSB") == 0 287#if SDL_BYTEORDER == SDL_BIG_ENDIAN 288 || SDL_strcmp(string, "SYS") == 0 289#endif 290 ) { 291 format |= 0x1000; 292 } 293 break; 294 default: 295 return 0; 296 } 297 return format; 298} 299 300int SDL_AudioInit(const char *driver_name) 301{ 302 SDL_AudioDevice *audio; 303 int i = 0, idx; 304 305 /* Check to make sure we don't overwrite 'current_audio' */ 306 if ( current_audio != NULL ) { 307 SDL_AudioQuit(); 308 } 309 310 /* Select the proper audio driver */ 311 audio = NULL; 312 idx = 0; 313#if SDL_AUDIO_DRIVER_ESD 314 if ( (driver_name == NULL) && (SDL_getenv("ESPEAKER") != NULL) ) { 315 /* Ahem, we know that if ESPEAKER is set, user probably wants 316 to use ESD, but don't start it if it's not already running. 317 This probably isn't the place to do this, but... Shh! :) 318 */ 319 for ( i=0; bootstrap[i]; ++i ) { 320 if ( SDL_strcasecmp(bootstrap[i]->name, "esd") == 0 ) { 321#ifdef HAVE_PUTENV 322 const char *esd_no_spawn; 323 324 /* Don't start ESD if it's not running */ 325 esd_no_spawn = getenv("ESD_NO_SPAWN"); 326 if ( esd_no_spawn == NULL ) { 327 putenv("ESD_NO_SPAWN=1"); 328 } 329#endif 330 if ( bootstrap[i]->available() ) { 331 audio = bootstrap[i]->create(0); 332 break; 333 } 334#ifdef HAVE_UNSETENV 335 if ( esd_no_spawn == NULL ) { 336 unsetenv("ESD_NO_SPAWN"); 337 } 338#endif 339 } 340 } 341 } 342#endif /* SDL_AUDIO_DRIVER_ESD */ 343 if ( audio == NULL ) { 344 if ( driver_name != NULL ) { 345#if 0 /* This will be replaced with a better driver selection API */ 346 if ( SDL_strrchr(driver_name, ':') != NULL ) { 347 idx = atoi(SDL_strrchr(driver_name, ':')+1); 348 } 349#endif 350 for ( i=0; bootstrap[i]; ++i ) { 351 if (SDL_strcasecmp(bootstrap[i]->name, driver_name) == 0) { 352 if ( bootstrap[i]->available() ) { 353 audio=bootstrap[i]->create(idx); 354 break; 355 } 356 } 357 } 358 } else { 359 for ( i=0; bootstrap[i]; ++i ) { 360 if ( bootstrap[i]->available() ) { 361 audio = bootstrap[i]->create(idx); 362 if ( audio != NULL ) { 363 break; 364 } 365 } 366 } 367 } 368 if ( audio == NULL ) { 369 SDL_SetError("No available audio device"); 370#if 0 /* Don't fail SDL_Init() if audio isn't available. 371 SDL_OpenAudio() will handle it at that point. *sigh* 372 */ 373 return(-1); 374#endif 375 } 376 } 377 current_audio = audio; 378 if ( current_audio ) { 379 current_audio->name = bootstrap[i]->name; 380 if ( !current_audio->LockAudio && !current_audio->UnlockAudio ) { 381 current_audio->LockAudio = SDL_LockAudio_Default; 382 current_audio->UnlockAudio = SDL_UnlockAudio_Default; 383 } 384 } 385 return(0); 386} 387 388char *SDL_AudioDriverName(char *namebuf, int maxlen) 389{ 390 if ( current_audio != NULL ) { 391 SDL_strlcpy(namebuf, current_audio->name, maxlen); 392 return(namebuf); 393 } 394 return(NULL); 395} 396 397int SDL_OpenAudio(SDL_AudioSpec *desired, SDL_AudioSpec *obtained) 398{ 399 SDL_AudioDevice *audio; 400 const char *env; 401 402 /* Start up the audio driver, if necessary */ 403 if ( ! current_audio ) { 404 if ( (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) || 405 (current_audio == NULL) ) { 406 return(-1); 407 } 408 } 409 audio = current_audio; 410 411 if (audio->opened) { 412 SDL_SetError("Audio device is already opened"); 413 return(-1); 414 } 415 416 /* Verify some parameters */ 417 if ( desired->freq == 0 ) { 418 env = SDL_getenv("SDL_AUDIO_FREQUENCY"); 419 if ( env ) { 420 desired->freq = SDL_atoi(env); 421 } 422 } 423 if ( desired->freq == 0 ) { 424 /* Pick some default audio frequency */ 425 desired->freq = 22050; 426 } 427 if ( desired->format == 0 ) { 428 env = SDL_getenv("SDL_AUDIO_FORMAT"); 429 if ( env ) { 430 desired->format = SDL_ParseAudioFormat(env); 431 } 432 } 433 if ( desired->format == 0 ) { 434 /* Pick some default audio format */ 435 desired->format = AUDIO_S16; 436 } 437 if ( desired->channels == 0 ) { 438 env = SDL_getenv("SDL_AUDIO_CHANNELS"); 439 if ( env ) { 440 desired->channels = (Uint8)SDL_atoi(env); 441 } 442 } 443 if ( desired->channels == 0 ) { 444 /* Pick a default number of channels */ 445 desired->channels = 2; 446 } 447 switch ( desired->channels ) { 448 case 1: /* Mono */ 449 case 2: /* Stereo */ 450 case 4: /* surround */ 451 case 6: /* surround with center and lfe */ 452 break; 453 default: 454 SDL_SetError("1 (mono) and 2 (stereo) channels supported"); 455 return(-1); 456 } 457 if ( desired->samples == 0 ) { 458 env = SDL_getenv("SDL_AUDIO_SAMPLES"); 459 if ( env ) { 460 desired->samples = (Uint16)SDL_atoi(env); 461 } 462 } 463 if ( desired->samples == 0 ) { 464 /* Pick a default of ~46 ms at desired frequency */ 465 int samples = (desired->freq / 1000) * 46; 466 int power2 = 1; 467 while ( power2 < samples ) { 468 power2 *= 2; 469 } 470 desired->samples = power2; 471 } 472 if ( desired->callback == NULL ) { 473 SDL_SetError("SDL_OpenAudio() passed a NULL callback"); 474 return(-1); 475 } 476 477#if SDL_THREADS_DISABLED 478 /* Uses interrupt driven audio, without thread */ 479#else 480 /* Create a semaphore for locking the sound buffers */ 481 audio->mixer_lock = SDL_CreateMutex(); 482 if ( audio->mixer_lock == NULL ) { 483 SDL_SetError("Couldn't create mixer lock"); 484 SDL_CloseAudio(); 485 return(-1); 486 } 487#endif /* SDL_THREADS_DISABLED */ 488 489 /* Calculate the silence and size of the audio specification */ 490 SDL_CalculateAudioSpec(desired); 491 492 /* Open the audio subsystem */ 493 SDL_memcpy(&audio->spec, desired, sizeof(audio->spec)); 494 audio->convert.needed = 0; 495 audio->enabled = 1; 496 audio->paused = 1; 497 498 audio->opened = audio->OpenAudio(audio, &audio->spec)+1; 499 500 if ( ! audio->opened ) { 501 SDL_CloseAudio(); 502 return(-1); 503 } 504 505 /* If the audio driver changes the buffer size, accept it */ 506 if ( audio->spec.samples != desired->samples ) { 507 desired->samples = audio->spec.samples; 508 SDL_CalculateAudioSpec(desired); 509 } 510 511 /* Allocate a fake audio memory buffer */ 512 audio->fake_stream = SDL_AllocAudioMem(audio->spec.size); 513 if ( audio->fake_stream == NULL ) { 514 SDL_CloseAudio(); 515 SDL_OutOfMemory(); 516 return(-1); 517 } 518 519 /* See if we need to do any conversion */ 520 if ( obtained != NULL ) { 521 SDL_memcpy(obtained, &audio->spec, sizeof(audio->spec)); 522 } else if ( desired->freq != audio->spec.freq || 523 desired->format != audio->spec.format || 524 desired->channels != audio->spec.channels ) { 525 /* Build an audio conversion block */ 526 if ( SDL_BuildAudioCVT(&audio->convert, 527 desired->format, desired->channels, 528 desired->freq, 529 audio->spec.format, audio->spec.channels, 530 audio->spec.freq) < 0 ) { 531 SDL_CloseAudio(); 532 return(-1); 533 } 534 if ( audio->convert.needed ) { 535 audio->convert.len = (int) ( ((double) audio->spec.size) / 536 audio->convert.len_ratio ); 537 audio->convert.buf =(Uint8 *)SDL_AllocAudioMem( 538 audio->convert.len*audio->convert.len_mult); 539 if ( audio->convert.buf == NULL ) { 540 SDL_CloseAudio(); 541 SDL_OutOfMemory(); 542 return(-1); 543 } 544 } 545 } 546 547 /* Start the audio thread if necessary */ 548 switch (audio->opened) { 549 case 1: 550 /* Start the audio thread */ 551#if (defined(__WIN32__) && !defined(_WIN32_WCE)) && !defined(HAVE_LIBC) && !defined(__SYMBIAN32__) 552#undef SDL_CreateThread 553 audio->thread = SDL_CreateThread(SDL_RunAudio, audio, NULL, NULL); 554#else 555 audio->thread = SDL_CreateThread(SDL_RunAudio, audio); 556#endif 557 if ( audio->thread == NULL ) { 558 SDL_CloseAudio(); 559 SDL_SetError("Couldn't create audio thread"); 560 return(-1); 561 } 562 break; 563 564 default: 565 /* The audio is now playing */ 566 break; 567 } 568 569 return(0); 570} 571 572SDL_audiostatus SDL_GetAudioStatus(void) 573{ 574 SDL_AudioDevice *audio = current_audio; 575 SDL_audiostatus status; 576 577 status = SDL_AUDIO_STOPPED; 578 if ( audio && audio->enabled ) { 579 if ( audio->paused ) { 580 status = SDL_AUDIO_PAUSED; 581 } else { 582 status = SDL_AUDIO_PLAYING; 583 } 584 } 585 return(status); 586} 587 588void SDL_PauseAudio (int pause_on) 589{ 590 SDL_AudioDevice *audio = current_audio; 591 592 if ( audio ) { 593 audio->paused = pause_on; 594 } 595} 596 597void SDL_LockAudio (void) 598{ 599 SDL_AudioDevice *audio = current_audio; 600 601 /* Obtain a lock on the mixing buffers */ 602 if ( audio && audio->LockAudio ) { 603 audio->LockAudio(audio); 604 } 605} 606 607void SDL_UnlockAudio (void) 608{ 609 SDL_AudioDevice *audio = current_audio; 610 611 /* Release lock on the mixing buffers */ 612 if ( audio && audio->UnlockAudio ) { 613 audio->UnlockAudio(audio); 614 } 615} 616 617void SDL_CloseAudio (void) 618{ 619 SDL_QuitSubSystem(SDL_INIT_AUDIO); 620} 621 622void SDL_AudioQuit(void) 623{ 624 SDL_AudioDevice *audio = current_audio; 625 626 if ( audio ) { 627 audio->enabled = 0; 628 if ( audio->thread != NULL ) { 629 SDL_WaitThread(audio->thread, NULL); 630 } 631 if ( audio->mixer_lock != NULL ) { 632 SDL_DestroyMutex(audio->mixer_lock); 633 } 634 if ( audio->fake_stream != NULL ) { 635 SDL_FreeAudioMem(audio->fake_stream); 636 } 637 if ( audio->convert.needed ) { 638 SDL_FreeAudioMem(audio->convert.buf); 639 640 } 641 if ( audio->opened ) { 642 audio->CloseAudio(audio); 643 audio->opened = 0; 644 } 645 /* Free the driver data */ 646 audio->free(audio); 647 current_audio = NULL; 648 } 649} 650 651#define NUM_FORMATS 6 652static int format_idx; 653static int format_idx_sub; 654static Uint16 format_list[NUM_FORMATS][NUM_FORMATS] = { 655 { AUDIO_U8, AUDIO_S8, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB }, 656 { AUDIO_S8, AUDIO_U8, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB }, 657 { AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_U8, AUDIO_S8 }, 658 { AUDIO_S16MSB, AUDIO_S16LSB, AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_U8, AUDIO_S8 }, 659 { AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U8, AUDIO_S8 }, 660 { AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_S16MSB, AUDIO_S16LSB, AUDIO_U8, AUDIO_S8 }, 661}; 662 663Uint16 SDL_FirstAudioFormat(Uint16 format) 664{ 665 for ( format_idx=0; format_idx < NUM_FORMATS; ++format_idx ) { 666 if ( format_list[format_idx][0] == format ) { 667 break; 668 } 669 } 670 format_idx_sub = 0; 671 return(SDL_NextAudioFormat()); 672} 673 674Uint16 SDL_NextAudioFormat(void) 675{ 676 if ( (format_idx == NUM_FORMATS) || (format_idx_sub == NUM_FORMATS) ) { 677 return(0); 678 } 679 return(format_list[format_idx][format_idx_sub++]); 680} 681 682void SDL_CalculateAudioSpec(SDL_AudioSpec *spec) 683{ 684 switch (spec->format) { 685 case AUDIO_U8: 686 spec->silence = 0x80; 687 break; 688 default: 689 spec->silence = 0x00; 690 break; 691 } 692 spec->size = (spec->format&0xFF)/8; 693 spec->size *= spec->channels; 694 spec->size *= spec->samples; 695} 696 697void SDL_Audio_SetCaption(const char *caption) 698{ 699 if ((current_audio) && (current_audio->SetCaption)) { 700 current_audio->SetCaption(current_audio, caption); 701 } 702} 703 704