2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2009 Sam Lantinga
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.
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.
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
22 #include "SDL_config.h"
24 /* Allow access to a raw mixing buffer */
27 #include "SDL_audio_c.h"
28 #include "SDL_audiomem.h"
29 #include "SDL_sysaudio.h"
32 /* We'll need the DosSetPriority() API! */
33 #define INCL_DOSPROCESS
37 /* Available audio drivers */
38 static AudioBootStrap *bootstrap[] = {
39 #if SDL_AUDIO_DRIVER_BSD
42 #if SDL_AUDIO_DRIVER_PULSE
45 #if SDL_AUDIO_DRIVER_ALSA
48 #if SDL_AUDIO_DRIVER_OSS
52 #if SDL_AUDIO_DRIVER_QNXNTO
53 &QNXNTOAUDIO_bootstrap,
55 #if SDL_AUDIO_DRIVER_SUNAUDIO
58 #if SDL_AUDIO_DRIVER_DMEDIA
61 #if SDL_AUDIO_DRIVER_ARTS
64 #if SDL_AUDIO_DRIVER_ESD
67 #if SDL_AUDIO_DRIVER_NAS
70 #if SDL_AUDIO_DRIVER_DSOUND
73 #if SDL_AUDIO_DRIVER_WAVEOUT
76 #if SDL_AUDIO_DRIVER_PAUD
79 #if SDL_AUDIO_DRIVER_BAUDIO
82 #if SDL_AUDIO_DRIVER_COREAUDIO
85 #if SDL_AUDIO_DRIVER_SNDMGR
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,
95 #if SDL_AUDIO_DRIVER_DISK
98 #if SDL_AUDIO_DRIVER_DUMMY
101 #if SDL_AUDIO_DRIVER_DC
104 #if SDL_AUDIO_DRIVER_NDS
107 #if SDL_AUDIO_DRIVER_MMEAUDIO
110 #if SDL_AUDIO_DRIVER_DART
113 #if SDL_AUDIO_DRIVER_EPOCAUDIO
114 &EPOCAudio_bootstrap,
118 SDL_AudioDevice *current_audio = NULL;
120 /* Various local functions */
121 int SDL_AudioInit(const char *driver_name);
122 void SDL_AudioQuit(void);
124 /* The general mixing thread function */
125 int SDLCALL SDL_RunAudio(void *audiop)
127 SDL_AudioDevice *audio = (SDL_AudioDevice *)audiop;
131 void (SDLCALL *fill)(void *userdata,Uint8 *stream, int len);
134 /* Perform any thread setup */
135 if ( audio->ThreadInit ) {
136 audio->ThreadInit(audio);
138 audio->threadid = SDL_ThreadID();
140 /* Set up the mixing function */
141 fill = audio->spec.callback;
142 udata = audio->spec.userdata;
144 if ( audio->convert.needed ) {
145 if ( audio->convert.src_format == AUDIO_U8 ) {
150 stream_len = audio->convert.len;
152 silence = audio->spec.silence;
153 stream_len = audio->spec.size;
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"))
163 printf("[SDL_RunAudio] : Setting priority to TimeCritical+0! (TID%d)\n", SDL_ThreadID());
165 DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0);
170 printf("[SDL_RunAudio] : Setting priority to ForegroundServer+0! (TID%d)\n", SDL_ThreadID());
172 DosSetPriority(PRTYS_THREAD, PRTYC_FOREGROUNDSERVER, 0, 0);
177 /* Loop, filling the audio buffers */
178 while ( audio->enabled ) {
180 /* Fill the current buffer with sound */
181 if ( audio->convert.needed ) {
182 if ( audio->convert.buf ) {
183 stream = audio->convert.buf;
188 stream = audio->GetAudioBuf(audio);
189 if ( stream == NULL ) {
190 stream = audio->fake_stream;
194 SDL_memset(stream, silence, stream_len);
196 if ( ! audio->paused ) {
197 SDL_mutexP(audio->mixer_lock);
198 (*fill)(udata, stream, stream_len);
199 SDL_mutexV(audio->mixer_lock);
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;
209 SDL_memcpy(stream, audio->convert.buf,
210 audio->convert.len_cvt);
213 /* Ready current buffer for play and change current buffer */
214 if ( stream != audio->fake_stream ) {
215 audio->PlayAudio(audio);
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);
222 audio->WaitAudio(audio);
226 /* Wait for the audio to drain.. */
227 if ( audio->WaitDone ) {
228 audio->WaitDone(audio);
233 printf("[SDL_RunAudio] : Task exiting. (TID%d)\n", SDL_ThreadID());
239 static void SDL_LockAudio_Default(SDL_AudioDevice *audio)
241 if ( audio->thread && (SDL_ThreadID() == audio->threadid) ) {
244 SDL_mutexP(audio->mixer_lock);
247 static void SDL_UnlockAudio_Default(SDL_AudioDevice *audio)
249 if ( audio->thread && (SDL_ThreadID() == audio->threadid) ) {
252 SDL_mutexV(audio->mixer_lock);
255 static Uint16 SDL_ParseAudioFormat(const char *string)
271 switch (SDL_atoi(string)) {
279 if ( SDL_strcmp(string, "LSB") == 0
280 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
281 || SDL_strcmp(string, "SYS") == 0
286 if ( SDL_strcmp(string, "MSB") == 0
287 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
288 || SDL_strcmp(string, "SYS") == 0
300 int SDL_AudioInit(const char *driver_name)
302 SDL_AudioDevice *audio;
305 /* Check to make sure we don't overwrite 'current_audio' */
306 if ( current_audio != NULL ) {
310 /* Select the proper audio driver */
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! :)
319 for ( i=0; bootstrap[i]; ++i ) {
320 if ( SDL_strcasecmp(bootstrap[i]->name, "esd") == 0 ) {
322 const char *esd_no_spawn;
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");
330 if ( bootstrap[i]->available() ) {
331 audio = bootstrap[i]->create(0);
335 if ( esd_no_spawn == NULL ) {
336 unsetenv("ESD_NO_SPAWN");
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);
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);
359 for ( i=0; bootstrap[i]; ++i ) {
360 if ( bootstrap[i]->available() ) {
361 audio = bootstrap[i]->create(idx);
362 if ( audio != NULL ) {
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*
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;
388 char *SDL_AudioDriverName(char *namebuf, int maxlen)
390 if ( current_audio != NULL ) {
391 SDL_strlcpy(namebuf, current_audio->name, maxlen);
397 int SDL_OpenAudio(SDL_AudioSpec *desired, SDL_AudioSpec *obtained)
399 SDL_AudioDevice *audio;
402 /* Start up the audio driver, if necessary */
403 if ( ! current_audio ) {
404 if ( (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) ||
405 (current_audio == NULL) ) {
409 audio = current_audio;
412 SDL_SetError("Audio device is already opened");
416 /* Verify some parameters */
417 if ( desired->freq == 0 ) {
418 env = SDL_getenv("SDL_AUDIO_FREQUENCY");
420 desired->freq = SDL_atoi(env);
423 if ( desired->freq == 0 ) {
424 /* Pick some default audio frequency */
425 desired->freq = 22050;
427 if ( desired->format == 0 ) {
428 env = SDL_getenv("SDL_AUDIO_FORMAT");
430 desired->format = SDL_ParseAudioFormat(env);
433 if ( desired->format == 0 ) {
434 /* Pick some default audio format */
435 desired->format = AUDIO_S16;
437 if ( desired->channels == 0 ) {
438 env = SDL_getenv("SDL_AUDIO_CHANNELS");
440 desired->channels = (Uint8)SDL_atoi(env);
443 if ( desired->channels == 0 ) {
444 /* Pick a default number of channels */
445 desired->channels = 2;
447 switch ( desired->channels ) {
450 case 4: /* surround */
451 case 6: /* surround with center and lfe */
454 SDL_SetError("1 (mono) and 2 (stereo) channels supported");
457 if ( desired->samples == 0 ) {
458 env = SDL_getenv("SDL_AUDIO_SAMPLES");
460 desired->samples = (Uint16)SDL_atoi(env);
463 if ( desired->samples == 0 ) {
464 /* Pick a default of ~46 ms at desired frequency */
465 int samples = (desired->freq / 1000) * 46;
467 while ( power2 < samples ) {
470 desired->samples = power2;
472 if ( desired->callback == NULL ) {
473 SDL_SetError("SDL_OpenAudio() passed a NULL callback");
477 #if SDL_THREADS_DISABLED
478 /* Uses interrupt driven audio, without thread */
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");
487 #endif /* SDL_THREADS_DISABLED */
489 /* Calculate the silence and size of the audio specification */
490 SDL_CalculateAudioSpec(desired);
492 /* Open the audio subsystem */
493 SDL_memcpy(&audio->spec, desired, sizeof(audio->spec));
494 audio->convert.needed = 0;
498 audio->opened = audio->OpenAudio(audio, &audio->spec)+1;
500 if ( ! audio->opened ) {
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);
511 /* Allocate a fake audio memory buffer */
512 audio->fake_stream = SDL_AllocAudioMem(audio->spec.size);
513 if ( audio->fake_stream == NULL ) {
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,
529 audio->spec.format, audio->spec.channels,
530 audio->spec.freq) < 0 ) {
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 ) {
547 /* Start the audio thread if necessary */
548 switch (audio->opened) {
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);
555 audio->thread = SDL_CreateThread(SDL_RunAudio, audio);
557 if ( audio->thread == NULL ) {
559 SDL_SetError("Couldn't create audio thread");
565 /* The audio is now playing */
572 SDL_audiostatus SDL_GetAudioStatus(void)
574 SDL_AudioDevice *audio = current_audio;
575 SDL_audiostatus status;
577 status = SDL_AUDIO_STOPPED;
578 if ( audio && audio->enabled ) {
579 if ( audio->paused ) {
580 status = SDL_AUDIO_PAUSED;
582 status = SDL_AUDIO_PLAYING;
588 void SDL_PauseAudio (int pause_on)
590 SDL_AudioDevice *audio = current_audio;
593 audio->paused = pause_on;
597 void SDL_LockAudio (void)
599 SDL_AudioDevice *audio = current_audio;
601 /* Obtain a lock on the mixing buffers */
602 if ( audio && audio->LockAudio ) {
603 audio->LockAudio(audio);
607 void SDL_UnlockAudio (void)
609 SDL_AudioDevice *audio = current_audio;
611 /* Release lock on the mixing buffers */
612 if ( audio && audio->UnlockAudio ) {
613 audio->UnlockAudio(audio);
617 void SDL_CloseAudio (void)
619 SDL_QuitSubSystem(SDL_INIT_AUDIO);
622 void SDL_AudioQuit(void)
624 SDL_AudioDevice *audio = current_audio;
628 if ( audio->thread != NULL ) {
629 SDL_WaitThread(audio->thread, NULL);
631 if ( audio->mixer_lock != NULL ) {
632 SDL_DestroyMutex(audio->mixer_lock);
634 if ( audio->fake_stream != NULL ) {
635 SDL_FreeAudioMem(audio->fake_stream);
637 if ( audio->convert.needed ) {
638 SDL_FreeAudioMem(audio->convert.buf);
641 if ( audio->opened ) {
642 audio->CloseAudio(audio);
645 /* Free the driver data */
647 current_audio = NULL;
651 #define NUM_FORMATS 6
652 static int format_idx;
653 static int format_idx_sub;
654 static 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 },
663 Uint16 SDL_FirstAudioFormat(Uint16 format)
665 for ( format_idx=0; format_idx < NUM_FORMATS; ++format_idx ) {
666 if ( format_list[format_idx][0] == format ) {
671 return(SDL_NextAudioFormat());
674 Uint16 SDL_NextAudioFormat(void)
676 if ( (format_idx == NUM_FORMATS) || (format_idx_sub == NUM_FORMATS) ) {
679 return(format_list[format_idx][format_idx_sub++]);
682 void SDL_CalculateAudioSpec(SDL_AudioSpec *spec)
684 switch (spec->format) {
686 spec->silence = 0x80;
689 spec->silence = 0x00;
692 spec->size = (spec->format&0xFF)/8;
693 spec->size *= spec->channels;
694 spec->size *= spec->samples;