2 Simple DirectMedia Layer
3 Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
21 #include "../SDL_internal.h"
23 /* Allow access to a raw mixing buffer */
26 #include "SDL_audio.h"
27 #include "SDL_audio_c.h"
28 #include "SDL_sysaudio.h"
29 #include "../thread/SDL_systhread.h"
31 #define _THIS SDL_AudioDevice *_this
33 static SDL_AudioDriver current_audio;
34 static SDL_AudioDevice *open_devices[16];
36 /* Available audio drivers */
37 static const AudioBootStrap *const bootstrap[] = {
38 #if SDL_AUDIO_DRIVER_PULSEAUDIO
39 &PULSEAUDIO_bootstrap,
41 #if SDL_AUDIO_DRIVER_ALSA
44 #if SDL_AUDIO_DRIVER_SNDIO
47 #if SDL_AUDIO_DRIVER_NETBSD
48 &NETBSDAUDIO_bootstrap,
50 #if SDL_AUDIO_DRIVER_OSS
53 #if SDL_AUDIO_DRIVER_QSA
56 #if SDL_AUDIO_DRIVER_SUNAUDIO
59 #if SDL_AUDIO_DRIVER_ARTS
62 #if SDL_AUDIO_DRIVER_ESD
65 #if SDL_AUDIO_DRIVER_NACL
68 #if SDL_AUDIO_DRIVER_NAS
71 #if SDL_AUDIO_DRIVER_WASAPI
74 #if SDL_AUDIO_DRIVER_DSOUND
77 #if SDL_AUDIO_DRIVER_WINMM
80 #if SDL_AUDIO_DRIVER_PAUDIO
83 #if SDL_AUDIO_DRIVER_HAIKU
84 &HAIKUAUDIO_bootstrap,
86 #if SDL_AUDIO_DRIVER_COREAUDIO
89 #if SDL_AUDIO_DRIVER_FUSIONSOUND
90 &FUSIONSOUND_bootstrap,
92 #if SDL_AUDIO_DRIVER_ANDROID
93 &ANDROIDAUDIO_bootstrap,
95 #if SDL_AUDIO_DRIVER_PSP
98 #if SDL_AUDIO_DRIVER_EMSCRIPTEN
99 &EMSCRIPTENAUDIO_bootstrap,
101 #if SDL_AUDIO_DRIVER_JACK
104 #if SDL_AUDIO_DRIVER_DISK
105 &DISKAUDIO_bootstrap,
107 #if SDL_AUDIO_DRIVER_DUMMY
108 &DUMMYAUDIO_bootstrap,
114 #ifdef HAVE_LIBSAMPLERATE_H
115 #ifdef SDL_LIBSAMPLERATE_DYNAMIC
116 static void *SRC_lib = NULL;
118 SDL_bool SRC_available = SDL_FALSE;
119 int SRC_converter = 0;
120 SRC_STATE* (*SRC_src_new)(int converter_type, int channels, int *error) = NULL;
121 int (*SRC_src_process)(SRC_STATE *state, SRC_DATA *data) = NULL;
122 int (*SRC_src_reset)(SRC_STATE *state) = NULL;
123 SRC_STATE* (*SRC_src_delete)(SRC_STATE *state) = NULL;
124 const char* (*SRC_src_strerror)(int error) = NULL;
127 LoadLibSampleRate(void)
129 const char *hint = SDL_GetHint(SDL_HINT_AUDIO_RESAMPLING_MODE);
131 SRC_available = SDL_FALSE;
134 if (!hint || *hint == '0' || SDL_strcasecmp(hint, "default") == 0) {
135 return SDL_FALSE; /* don't load anything. */
136 } else if (*hint == '1' || SDL_strcasecmp(hint, "fast") == 0) {
137 SRC_converter = SRC_SINC_FASTEST;
138 } else if (*hint == '2' || SDL_strcasecmp(hint, "medium") == 0) {
139 SRC_converter = SRC_SINC_MEDIUM_QUALITY;
140 } else if (*hint == '3' || SDL_strcasecmp(hint, "best") == 0) {
141 SRC_converter = SRC_SINC_BEST_QUALITY;
143 return SDL_FALSE; /* treat it like "default", don't load anything. */
146 #ifdef SDL_LIBSAMPLERATE_DYNAMIC
147 SDL_assert(SRC_lib == NULL);
148 SRC_lib = SDL_LoadObject(SDL_LIBSAMPLERATE_DYNAMIC);
154 SRC_src_new = (SRC_STATE* (*)(int converter_type, int channels, int *error))SDL_LoadFunction(SRC_lib, "src_new");
155 SRC_src_process = (int (*)(SRC_STATE *state, SRC_DATA *data))SDL_LoadFunction(SRC_lib, "src_process");
156 SRC_src_reset = (int(*)(SRC_STATE *state))SDL_LoadFunction(SRC_lib, "src_reset");
157 SRC_src_delete = (SRC_STATE* (*)(SRC_STATE *state))SDL_LoadFunction(SRC_lib, "src_delete");
158 SRC_src_strerror = (const char* (*)(int error))SDL_LoadFunction(SRC_lib, "src_strerror");
160 if (!SRC_src_new || !SRC_src_process || !SRC_src_reset || !SRC_src_delete || !SRC_src_strerror) {
161 SDL_UnloadObject(SRC_lib);
166 SRC_src_new = src_new;
167 SRC_src_process = src_process;
168 SRC_src_reset = src_reset;
169 SRC_src_delete = src_delete;
170 SRC_src_strerror = src_strerror;
173 SRC_available = SDL_TRUE;
178 UnloadLibSampleRate(void)
180 #ifdef SDL_LIBSAMPLERATE_DYNAMIC
181 if (SRC_lib != NULL) {
182 SDL_UnloadObject(SRC_lib);
187 SRC_available = SDL_FALSE;
189 SRC_src_process = NULL;
190 SRC_src_reset = NULL;
191 SRC_src_delete = NULL;
192 SRC_src_strerror = NULL;
196 static SDL_AudioDevice *
197 get_audio_device(SDL_AudioDeviceID id)
200 if ((id >= SDL_arraysize(open_devices)) || (open_devices[id] == NULL)) {
201 SDL_SetError("Invalid audio device ID");
205 return open_devices[id];
209 /* stubs for audio drivers that don't need a specific entry point... */
211 SDL_AudioDetectDevices_Default(void)
213 /* you have to write your own implementation if these assertions fail. */
214 SDL_assert(current_audio.impl.OnlyHasDefaultOutputDevice);
215 SDL_assert(current_audio.impl.OnlyHasDefaultCaptureDevice || !current_audio.impl.HasCaptureSupport);
217 SDL_AddAudioDevice(SDL_FALSE, DEFAULT_OUTPUT_DEVNAME, (void *) ((size_t) 0x1));
218 if (current_audio.impl.HasCaptureSupport) {
219 SDL_AddAudioDevice(SDL_TRUE, DEFAULT_INPUT_DEVNAME, (void *) ((size_t) 0x2));
224 SDL_AudioThreadInit_Default(_THIS)
229 SDL_AudioThreadDeinit_Default(_THIS)
234 SDL_AudioBeginLoopIteration_Default(_THIS)
239 SDL_AudioWaitDevice_Default(_THIS)
244 SDL_AudioPlayDevice_Default(_THIS)
249 SDL_AudioGetPendingBytes_Default(_THIS)
255 SDL_AudioGetDeviceBuf_Default(_THIS)
261 SDL_AudioCaptureFromDevice_Default(_THIS, void *buffer, int buflen)
263 return -1; /* just fail immediately. */
267 SDL_AudioFlushCapture_Default(_THIS)
272 SDL_AudioPrepareToClose_Default(_THIS)
277 SDL_AudioCloseDevice_Default(_THIS)
282 SDL_AudioDeinitialize_Default(void)
287 SDL_AudioFreeDeviceHandle_Default(void *handle)
293 SDL_AudioOpenDevice_Default(_THIS, void *handle, const char *devname, int iscapture)
295 return SDL_Unsupported();
298 static SDL_INLINE SDL_bool
299 is_in_audio_device_thread(SDL_AudioDevice * device)
301 /* The device thread locks the same mutex, but not through the public API.
302 This check is in case the application, in the audio callback,
303 tries to lock the thread that we've already locked from the
304 device thread...just in case we only have non-recursive mutexes. */
305 if (device->thread && (SDL_ThreadID() == device->threadid)) {
313 SDL_AudioLockDevice_Default(SDL_AudioDevice * device)
315 if (!is_in_audio_device_thread(device)) {
316 SDL_LockMutex(device->mixer_lock);
321 SDL_AudioUnlockDevice_Default(SDL_AudioDevice * device)
323 if (!is_in_audio_device_thread(device)) {
324 SDL_UnlockMutex(device->mixer_lock);
329 SDL_AudioLockOrUnlockDeviceWithNoMixerLock(SDL_AudioDevice * device)
334 finish_audio_entry_points_init(void)
337 * Fill in stub functions for unused driver entry points. This lets us
338 * blindly call them without having to check for validity first.
341 if (current_audio.impl.SkipMixerLock) {
342 if (current_audio.impl.LockDevice == NULL) {
343 current_audio.impl.LockDevice = SDL_AudioLockOrUnlockDeviceWithNoMixerLock;
345 if (current_audio.impl.UnlockDevice == NULL) {
346 current_audio.impl.UnlockDevice = SDL_AudioLockOrUnlockDeviceWithNoMixerLock;
350 #define FILL_STUB(x) \
351 if (current_audio.impl.x == NULL) { \
352 current_audio.impl.x = SDL_Audio##x##_Default; \
354 FILL_STUB(DetectDevices);
355 FILL_STUB(OpenDevice);
356 FILL_STUB(ThreadInit);
357 FILL_STUB(ThreadDeinit);
358 FILL_STUB(BeginLoopIteration);
359 FILL_STUB(WaitDevice);
360 FILL_STUB(PlayDevice);
361 FILL_STUB(GetPendingBytes);
362 FILL_STUB(GetDeviceBuf);
363 FILL_STUB(CaptureFromDevice);
364 FILL_STUB(FlushCapture);
365 FILL_STUB(PrepareToClose);
366 FILL_STUB(CloseDevice);
367 FILL_STUB(LockDevice);
368 FILL_STUB(UnlockDevice);
369 FILL_STUB(FreeDeviceHandle);
370 FILL_STUB(Deinitialize);
375 /* device hotplug support... */
378 add_audio_device(const char *name, void *handle, SDL_AudioDeviceItem **devices, int *devCount)
381 const size_t size = sizeof (SDL_AudioDeviceItem) + SDL_strlen(name) + 1;
382 SDL_AudioDeviceItem *item = (SDL_AudioDeviceItem *) SDL_malloc(size);
387 SDL_assert(handle != NULL); /* we reserve NULL, audio backends can't use it. */
389 item->handle = handle;
390 SDL_strlcpy(item->name, name, size - sizeof (SDL_AudioDeviceItem));
392 SDL_LockMutex(current_audio.detectionLock);
393 item->next = *devices;
395 retval = (*devCount)++;
396 SDL_UnlockMutex(current_audio.detectionLock);
401 static SDL_INLINE int
402 add_capture_device(const char *name, void *handle)
404 SDL_assert(current_audio.impl.HasCaptureSupport);
405 return add_audio_device(name, handle, ¤t_audio.inputDevices, ¤t_audio.inputDeviceCount);
408 static SDL_INLINE int
409 add_output_device(const char *name, void *handle)
411 return add_audio_device(name, handle, ¤t_audio.outputDevices, ¤t_audio.outputDeviceCount);
415 free_device_list(SDL_AudioDeviceItem **devices, int *devCount)
417 SDL_AudioDeviceItem *item, *next;
418 for (item = *devices; item != NULL; item = next) {
420 if (item->handle != NULL) {
421 current_audio.impl.FreeDeviceHandle(item->handle);
430 /* The audio backends call this when a new device is plugged in. */
432 SDL_AddAudioDevice(const int iscapture, const char *name, void *handle)
434 const int device_index = iscapture ? add_capture_device(name, handle) : add_output_device(name, handle);
435 if (device_index != -1) {
436 /* Post the event, if desired */
437 if (SDL_GetEventState(SDL_AUDIODEVICEADDED) == SDL_ENABLE) {
440 event.adevice.type = SDL_AUDIODEVICEADDED;
441 event.adevice.which = device_index;
442 event.adevice.iscapture = iscapture;
443 SDL_PushEvent(&event);
448 /* The audio backends call this when a currently-opened device is lost. */
449 void SDL_OpenedAudioDeviceDisconnected(SDL_AudioDevice *device)
451 SDL_assert(get_audio_device(device->id) == device);
453 if (!SDL_AtomicGet(&device->enabled)) {
457 /* Ends the audio callback and mark the device as STOPPED, but the
458 app still needs to close the device to free resources. */
459 current_audio.impl.LockDevice(device);
460 SDL_AtomicSet(&device->enabled, 0);
461 current_audio.impl.UnlockDevice(device);
463 /* Post the event, if desired */
464 if (SDL_GetEventState(SDL_AUDIODEVICEREMOVED) == SDL_ENABLE) {
467 event.adevice.type = SDL_AUDIODEVICEREMOVED;
468 event.adevice.which = device->id;
469 event.adevice.iscapture = device->iscapture ? 1 : 0;
470 SDL_PushEvent(&event);
475 mark_device_removed(void *handle, SDL_AudioDeviceItem *devices, SDL_bool *removedFlag)
477 SDL_AudioDeviceItem *item;
478 SDL_assert(handle != NULL);
479 for (item = devices; item != NULL; item = item->next) {
480 if (item->handle == handle) {
482 *removedFlag = SDL_TRUE;
488 /* The audio backends call this when a device is removed from the system. */
490 SDL_RemoveAudioDevice(const int iscapture, void *handle)
493 SDL_AudioDevice *device = NULL;
495 SDL_LockMutex(current_audio.detectionLock);
497 mark_device_removed(handle, current_audio.inputDevices, ¤t_audio.captureDevicesRemoved);
499 mark_device_removed(handle, current_audio.outputDevices, ¤t_audio.outputDevicesRemoved);
501 for (device_index = 0; device_index < SDL_arraysize(open_devices); device_index++)
503 device = open_devices[device_index];
504 if (device != NULL && device->handle == handle)
506 SDL_OpenedAudioDeviceDisconnected(device);
510 SDL_UnlockMutex(current_audio.detectionLock);
512 current_audio.impl.FreeDeviceHandle(handle);
517 /* buffer queueing support... */
520 SDL_BufferQueueDrainCallback(void *userdata, Uint8 *stream, int len)
522 /* this function always holds the mixer lock before being called. */
523 SDL_AudioDevice *device = (SDL_AudioDevice *) userdata;
526 SDL_assert(device != NULL); /* this shouldn't ever happen, right?! */
527 SDL_assert(!device->iscapture); /* this shouldn't ever happen, right?! */
528 SDL_assert(len >= 0); /* this shouldn't ever happen, right?! */
530 dequeued = SDL_ReadFromDataQueue(device->buffer_queue, stream, len);
532 len -= (int) dequeued;
534 if (len > 0) { /* fill any remaining space in the stream with silence. */
535 SDL_assert(SDL_CountDataQueue(device->buffer_queue) == 0);
536 SDL_memset(stream, device->spec.silence, len);
541 SDL_BufferQueueFillCallback(void *userdata, Uint8 *stream, int len)
543 /* this function always holds the mixer lock before being called. */
544 SDL_AudioDevice *device = (SDL_AudioDevice *) userdata;
546 SDL_assert(device != NULL); /* this shouldn't ever happen, right?! */
547 SDL_assert(device->iscapture); /* this shouldn't ever happen, right?! */
548 SDL_assert(len >= 0); /* this shouldn't ever happen, right?! */
550 /* note that if this needs to allocate more space and run out of memory,
551 we have no choice but to quietly drop the data and hope it works out
552 later, but you probably have bigger problems in this case anyhow. */
553 SDL_WriteToDataQueue(device->buffer_queue, stream, len);
557 SDL_QueueAudio(SDL_AudioDeviceID devid, const void *data, Uint32 len)
559 SDL_AudioDevice *device = get_audio_device(devid);
563 return -1; /* get_audio_device() will have set the error state */
564 } else if (device->iscapture) {
565 return SDL_SetError("This is a capture device, queueing not allowed");
566 } else if (device->callbackspec.callback != SDL_BufferQueueDrainCallback) {
567 return SDL_SetError("Audio device has a callback, queueing not allowed");
571 current_audio.impl.LockDevice(device);
572 rc = SDL_WriteToDataQueue(device->buffer_queue, data, len);
573 current_audio.impl.UnlockDevice(device);
580 SDL_DequeueAudio(SDL_AudioDeviceID devid, void *data, Uint32 len)
582 SDL_AudioDevice *device = get_audio_device(devid);
585 if ( (len == 0) || /* nothing to do? */
586 (!device) || /* called with bogus device id */
587 (!device->iscapture) || /* playback devices can't dequeue */
588 (device->callbackspec.callback != SDL_BufferQueueFillCallback) ) { /* not set for queueing */
589 return 0; /* just report zero bytes dequeued. */
592 current_audio.impl.LockDevice(device);
593 rc = (Uint32) SDL_ReadFromDataQueue(device->buffer_queue, data, len);
594 current_audio.impl.UnlockDevice(device);
599 SDL_GetQueuedAudioSize(SDL_AudioDeviceID devid)
602 SDL_AudioDevice *device = get_audio_device(devid);
608 /* Nothing to do unless we're set up for queueing. */
609 if (device->callbackspec.callback == SDL_BufferQueueDrainCallback) {
610 current_audio.impl.LockDevice(device);
611 retval = ((Uint32) SDL_CountDataQueue(device->buffer_queue)) + current_audio.impl.GetPendingBytes(device);
612 current_audio.impl.UnlockDevice(device);
613 } else if (device->callbackspec.callback == SDL_BufferQueueFillCallback) {
614 current_audio.impl.LockDevice(device);
615 retval = (Uint32) SDL_CountDataQueue(device->buffer_queue);
616 current_audio.impl.UnlockDevice(device);
623 SDL_ClearQueuedAudio(SDL_AudioDeviceID devid)
625 SDL_AudioDevice *device = get_audio_device(devid);
628 return; /* nothing to do. */
631 /* Blank out the device and release the mutex. Free it afterwards. */
632 current_audio.impl.LockDevice(device);
634 /* Keep up to two packets in the pool to reduce future malloc pressure. */
635 SDL_ClearDataQueue(device->buffer_queue, SDL_AUDIOBUFFERQUEUE_PACKETLEN * 2);
637 current_audio.impl.UnlockDevice(device);
641 /* The general mixing thread function */
643 SDL_RunAudio(void *devicep)
645 SDL_AudioDevice *device = (SDL_AudioDevice *) devicep;
646 void *udata = device->callbackspec.userdata;
647 SDL_AudioCallback callback = device->callbackspec.callback;
651 SDL_assert(!device->iscapture);
653 /* The audio mixing is always a high priority thread */
654 SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH);
656 /* Perform any thread setup */
657 device->threadid = SDL_ThreadID();
658 current_audio.impl.ThreadInit(device);
660 /* Loop, filling the audio buffers */
661 while (!SDL_AtomicGet(&device->shutdown)) {
662 current_audio.impl.BeginLoopIteration(device);
663 data_len = device->callbackspec.size;
665 /* Fill the current buffer with sound */
666 if (!device->stream && SDL_AtomicGet(&device->enabled)) {
667 SDL_assert(data_len == device->spec.size);
668 data = current_audio.impl.GetDeviceBuf(device);
670 /* if the device isn't enabled, we still write to the
671 work_buffer, so the app's callback will fire with
672 a regular frequency, in case they depend on that
673 for timing or progress. They can use hotplug
674 now to know if the device failed.
675 Streaming playback uses work_buffer, too. */
680 data = device->work_buffer;
683 /* !!! FIXME: this should be LockDevice. */
684 SDL_LockMutex(device->mixer_lock);
685 if (SDL_AtomicGet(&device->paused)) {
686 SDL_memset(data, device->spec.silence, data_len);
688 callback(udata, data, data_len);
690 SDL_UnlockMutex(device->mixer_lock);
692 if (device->stream) {
693 /* Stream available audio to device, converting/resampling. */
694 /* if this fails...oh well. We'll play silence here. */
695 SDL_AudioStreamPut(device->stream, data, data_len);
697 while (SDL_AudioStreamAvailable(device->stream) >= ((int) device->spec.size)) {
699 data = SDL_AtomicGet(&device->enabled) ? current_audio.impl.GetDeviceBuf(device) : NULL;
700 got = SDL_AudioStreamGet(device->stream, data ? data : device->work_buffer, device->spec.size);
701 SDL_assert((got < 0) || (got == device->spec.size));
703 if (data == NULL) { /* device is having issues... */
704 const Uint32 delay = ((device->spec.samples * 1000) / device->spec.freq);
705 SDL_Delay(delay); /* wait for as long as this buffer would have played. Maybe device recovers later? */
707 if (got != device->spec.size) {
708 SDL_memset(data, device->spec.silence, device->spec.size);
710 current_audio.impl.PlayDevice(device);
711 current_audio.impl.WaitDevice(device);
714 } else if (data == device->work_buffer) {
715 /* nothing to do; pause like we queued a buffer to play. */
716 const Uint32 delay = ((device->spec.samples * 1000) / device->spec.freq);
718 } else { /* writing directly to the device. */
719 /* queue this buffer and wait for it to finish playing. */
720 current_audio.impl.PlayDevice(device);
721 current_audio.impl.WaitDevice(device);
725 current_audio.impl.PrepareToClose(device);
727 /* Wait for the audio to drain. */
728 SDL_Delay(((device->spec.samples * 1000) / device->spec.freq) * 2);
730 current_audio.impl.ThreadDeinit(device);
735 /* !!! FIXME: this needs to deal with device spec changes. */
736 /* The general capture thread function */
738 SDL_CaptureAudio(void *devicep)
740 SDL_AudioDevice *device = (SDL_AudioDevice *) devicep;
741 const int silence = (int) device->spec.silence;
742 const Uint32 delay = ((device->spec.samples * 1000) / device->spec.freq);
743 const int data_len = device->spec.size;
745 void *udata = device->callbackspec.userdata;
746 SDL_AudioCallback callback = device->callbackspec.callback;
748 SDL_assert(device->iscapture);
750 /* The audio mixing is always a high priority thread */
751 SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH);
753 /* Perform any thread setup */
754 device->threadid = SDL_ThreadID();
755 current_audio.impl.ThreadInit(device);
757 /* Loop, filling the audio buffers */
758 while (!SDL_AtomicGet(&device->shutdown)) {
762 current_audio.impl.BeginLoopIteration(device);
764 if (SDL_AtomicGet(&device->paused)) {
765 SDL_Delay(delay); /* just so we don't cook the CPU. */
766 if (device->stream) {
767 SDL_AudioStreamClear(device->stream);
769 current_audio.impl.FlushCapture(device); /* dump anything pending. */
773 /* Fill the current buffer with sound */
774 still_need = data_len;
776 /* Use the work_buffer to hold data read from the device. */
777 data = device->work_buffer;
778 SDL_assert(data != NULL);
782 /* We still read from the device when "paused" to keep the state sane,
783 and block when there isn't data so this thread isn't eating CPU.
784 But we don't process it further or call the app's callback. */
786 if (!SDL_AtomicGet(&device->enabled)) {
787 SDL_Delay(delay); /* try to keep callback firing at normal pace. */
789 while (still_need > 0) {
790 const int rc = current_audio.impl.CaptureFromDevice(device, ptr, still_need);
791 SDL_assert(rc <= still_need); /* device should not overflow buffer. :) */
795 } else { /* uhoh, device failed for some reason! */
796 SDL_OpenedAudioDeviceDisconnected(device);
802 if (still_need > 0) {
803 /* Keep any data we already read, silence the rest. */
804 SDL_memset(ptr, silence, still_need);
807 if (device->stream) {
808 /* if this fails...oh well. */
809 SDL_AudioStreamPut(device->stream, data, data_len);
811 while (SDL_AudioStreamAvailable(device->stream) >= ((int) device->callbackspec.size)) {
812 const int got = SDL_AudioStreamGet(device->stream, device->work_buffer, device->callbackspec.size);
813 SDL_assert((got < 0) || (got == device->callbackspec.size));
814 if (got != device->callbackspec.size) {
815 SDL_memset(device->work_buffer, device->spec.silence, device->callbackspec.size);
818 /* !!! FIXME: this should be LockDevice. */
819 SDL_LockMutex(device->mixer_lock);
820 if (!SDL_AtomicGet(&device->paused)) {
821 callback(udata, device->work_buffer, device->callbackspec.size);
823 SDL_UnlockMutex(device->mixer_lock);
825 } else { /* feeding user callback directly without streaming. */
826 /* !!! FIXME: this should be LockDevice. */
827 SDL_LockMutex(device->mixer_lock);
828 if (!SDL_AtomicGet(&device->paused)) {
829 callback(udata, data, device->callbackspec.size);
831 SDL_UnlockMutex(device->mixer_lock);
835 current_audio.impl.FlushCapture(device);
837 current_audio.impl.ThreadDeinit(device);
843 static SDL_AudioFormat
844 SDL_ParseAudioFormat(const char *string)
846 #define CHECK_FMT_STRING(x) if (SDL_strcmp(string, #x) == 0) return AUDIO_##x
847 CHECK_FMT_STRING(U8);
848 CHECK_FMT_STRING(S8);
849 CHECK_FMT_STRING(U16LSB);
850 CHECK_FMT_STRING(S16LSB);
851 CHECK_FMT_STRING(U16MSB);
852 CHECK_FMT_STRING(S16MSB);
853 CHECK_FMT_STRING(U16SYS);
854 CHECK_FMT_STRING(S16SYS);
855 CHECK_FMT_STRING(U16);
856 CHECK_FMT_STRING(S16);
857 CHECK_FMT_STRING(S32LSB);
858 CHECK_FMT_STRING(S32MSB);
859 CHECK_FMT_STRING(S32SYS);
860 CHECK_FMT_STRING(S32);
861 CHECK_FMT_STRING(F32LSB);
862 CHECK_FMT_STRING(F32MSB);
863 CHECK_FMT_STRING(F32SYS);
864 CHECK_FMT_STRING(F32);
865 #undef CHECK_FMT_STRING
870 SDL_GetNumAudioDrivers(void)
872 return SDL_arraysize(bootstrap) - 1;
876 SDL_GetAudioDriver(int index)
878 if (index >= 0 && index < SDL_GetNumAudioDrivers()) {
879 return bootstrap[index]->name;
885 SDL_AudioInit(const char *driver_name)
889 int tried_to_init = 0;
891 if (SDL_WasInit(SDL_INIT_AUDIO)) {
892 SDL_AudioQuit(); /* shutdown driver if already running. */
895 SDL_zero(current_audio);
896 SDL_zero(open_devices);
898 /* Select the proper audio driver */
899 if (driver_name == NULL) {
900 driver_name = SDL_getenv("SDL_AUDIODRIVER");
903 for (i = 0; (!initialized) && (bootstrap[i]); ++i) {
904 /* make sure we should even try this driver before doing so... */
905 const AudioBootStrap *backend = bootstrap[i];
906 if ((driver_name && (SDL_strncasecmp(backend->name, driver_name, SDL_strlen(driver_name)) != 0)) ||
907 (!driver_name && backend->demand_only)) {
912 SDL_zero(current_audio);
913 current_audio.name = backend->name;
914 current_audio.desc = backend->desc;
915 initialized = backend->init(¤t_audio.impl);
919 /* specific drivers will set the error message if they fail... */
920 if (!tried_to_init) {
922 SDL_SetError("Audio target '%s' not available", driver_name);
924 SDL_SetError("No available audio device");
928 SDL_zero(current_audio);
929 return -1; /* No driver was available, so fail. */
932 current_audio.detectionLock = SDL_CreateMutex();
934 finish_audio_entry_points_init();
936 /* Make sure we have a list of devices available at startup. */
937 current_audio.impl.DetectDevices();
939 #ifdef HAVE_LIBSAMPLERATE_H
947 * Get the current audio driver name
950 SDL_GetCurrentAudioDriver()
952 return current_audio.name;
955 /* Clean out devices that we've removed but had to keep around for stability. */
957 clean_out_device_list(SDL_AudioDeviceItem **devices, int *devCount, SDL_bool *removedFlag)
959 SDL_AudioDeviceItem *item = *devices;
960 SDL_AudioDeviceItem *prev = NULL;
964 SDL_AudioDeviceItem *next = item->next;
965 if (item->handle != NULL) {
980 *removedFlag = SDL_FALSE;
985 SDL_GetNumAudioDevices(int iscapture)
989 if (!SDL_WasInit(SDL_INIT_AUDIO)) {
993 SDL_LockMutex(current_audio.detectionLock);
994 if (iscapture && current_audio.captureDevicesRemoved) {
995 clean_out_device_list(¤t_audio.inputDevices, ¤t_audio.inputDeviceCount, ¤t_audio.captureDevicesRemoved);
998 if (!iscapture && current_audio.outputDevicesRemoved) {
999 clean_out_device_list(¤t_audio.outputDevices, ¤t_audio.outputDeviceCount, ¤t_audio.outputDevicesRemoved);
1000 current_audio.outputDevicesRemoved = SDL_FALSE;
1003 retval = iscapture ? current_audio.inputDeviceCount : current_audio.outputDeviceCount;
1004 SDL_UnlockMutex(current_audio.detectionLock);
1012 SDL_GetAudioDeviceName(int index, int iscapture)
1014 const char *retval = NULL;
1016 if (!SDL_WasInit(SDL_INIT_AUDIO)) {
1017 SDL_SetError("Audio subsystem is not initialized");
1021 if ((iscapture) && (!current_audio.impl.HasCaptureSupport)) {
1022 SDL_SetError("No capture support");
1027 SDL_AudioDeviceItem *item;
1030 SDL_LockMutex(current_audio.detectionLock);
1031 item = iscapture ? current_audio.inputDevices : current_audio.outputDevices;
1032 i = iscapture ? current_audio.inputDeviceCount : current_audio.outputDeviceCount;
1034 for (i--; i > index; i--, item = item->next) {
1035 SDL_assert(item != NULL);
1037 SDL_assert(item != NULL);
1038 retval = item->name;
1040 SDL_UnlockMutex(current_audio.detectionLock);
1043 if (retval == NULL) {
1044 SDL_SetError("No such device");
1052 close_audio_device(SDL_AudioDevice * device)
1058 if (device->id > 0) {
1059 SDL_AudioDevice *opendev = open_devices[device->id - 1];
1060 SDL_assert((opendev == device) || (opendev == NULL));
1061 if (opendev == device) {
1062 open_devices[device->id - 1] = NULL;
1066 SDL_AtomicSet(&device->shutdown, 1);
1067 SDL_AtomicSet(&device->enabled, 0);
1068 if (device->thread != NULL) {
1069 SDL_WaitThread(device->thread, NULL);
1071 if (device->mixer_lock != NULL) {
1072 SDL_DestroyMutex(device->mixer_lock);
1075 SDL_free(device->work_buffer);
1076 SDL_FreeAudioStream(device->stream);
1078 if (device->hidden != NULL) {
1079 current_audio.impl.CloseDevice(device);
1082 SDL_FreeDataQueue(device->buffer_queue);
1089 * Sanity check desired AudioSpec for SDL_OpenAudio() in (orig).
1090 * Fills in a sanitized copy in (prepared).
1091 * Returns non-zero if okay, zero on fatal parameters in (orig).
1094 prepare_audiospec(const SDL_AudioSpec * orig, SDL_AudioSpec * prepared)
1096 SDL_memcpy(prepared, orig, sizeof(SDL_AudioSpec));
1098 if (orig->freq == 0) {
1099 const char *env = SDL_getenv("SDL_AUDIO_FREQUENCY");
1100 if ((!env) || ((prepared->freq = SDL_atoi(env)) == 0)) {
1101 prepared->freq = 22050; /* a reasonable default */
1105 if (orig->format == 0) {
1106 const char *env = SDL_getenv("SDL_AUDIO_FORMAT");
1107 if ((!env) || ((prepared->format = SDL_ParseAudioFormat(env)) == 0)) {
1108 prepared->format = AUDIO_S16; /* a reasonable default */
1112 switch (orig->channels) {
1114 const char *env = SDL_getenv("SDL_AUDIO_CHANNELS");
1115 if ((!env) || ((prepared->channels = (Uint8) SDL_atoi(env)) == 0)) {
1116 prepared->channels = 2; /* a reasonable default */
1121 case 2: /* Stereo */
1122 case 4: /* surround */
1123 case 6: /* surround with center and lfe */
1126 SDL_SetError("Unsupported number of audio channels.");
1130 if (orig->samples == 0) {
1131 const char *env = SDL_getenv("SDL_AUDIO_SAMPLES");
1132 if ((!env) || ((prepared->samples = (Uint16) SDL_atoi(env)) == 0)) {
1133 /* Pick a default of ~46 ms at desired frequency */
1134 /* !!! FIXME: remove this when the non-Po2 resampling is in. */
1135 const int samples = (prepared->freq / 1000) * 46;
1137 while (power2 < samples) {
1140 prepared->samples = power2;
1144 /* Calculate the silence and size of the audio specification */
1145 SDL_CalculateAudioSpec(prepared);
1150 static SDL_AudioDeviceID
1151 open_audio_device(const char *devname, int iscapture,
1152 const SDL_AudioSpec * desired, SDL_AudioSpec * obtained,
1153 int allowed_changes, int min_id)
1155 const SDL_bool is_internal_thread = (desired->callback == NULL);
1156 SDL_AudioDeviceID id = 0;
1157 SDL_AudioSpec _obtained;
1158 SDL_AudioDevice *device;
1159 SDL_bool build_stream;
1160 void *handle = NULL;
1163 if (!SDL_WasInit(SDL_INIT_AUDIO)) {
1164 SDL_SetError("Audio subsystem is not initialized");
1168 if ((iscapture) && (!current_audio.impl.HasCaptureSupport)) {
1169 SDL_SetError("No capture support");
1173 /* !!! FIXME: there is a race condition here if two devices open from two threads at once. */
1174 /* Find an available device ID... */
1175 for (id = min_id - 1; id < SDL_arraysize(open_devices); id++) {
1176 if (open_devices[id] == NULL) {
1181 if (id == SDL_arraysize(open_devices)) {
1182 SDL_SetError("Too many open audio devices");
1187 obtained = &_obtained;
1189 if (!prepare_audiospec(desired, obtained)) {
1193 /* If app doesn't care about a specific device, let the user override. */
1194 if (devname == NULL) {
1195 devname = SDL_getenv("SDL_AUDIO_DEVICE_NAME");
1199 * Catch device names at the high level for the simple case...
1200 * This lets us have a basic "device enumeration" for systems that
1201 * don't have multiple devices, but makes sure the device name is
1202 * always NULL when it hits the low level.
1204 * Also make sure that the simple case prevents multiple simultaneous
1205 * opens of the default system device.
1208 if ((iscapture) && (current_audio.impl.OnlyHasDefaultCaptureDevice)) {
1209 if ((devname) && (SDL_strcmp(devname, DEFAULT_INPUT_DEVNAME) != 0)) {
1210 SDL_SetError("No such device");
1215 for (i = 0; i < SDL_arraysize(open_devices); i++) {
1216 if ((open_devices[i]) && (open_devices[i]->iscapture)) {
1217 SDL_SetError("Audio device already open");
1221 } else if ((!iscapture) && (current_audio.impl.OnlyHasDefaultOutputDevice)) {
1222 if ((devname) && (SDL_strcmp(devname, DEFAULT_OUTPUT_DEVNAME) != 0)) {
1223 SDL_SetError("No such device");
1228 for (i = 0; i < SDL_arraysize(open_devices); i++) {
1229 if ((open_devices[i]) && (!open_devices[i]->iscapture)) {
1230 SDL_SetError("Audio device already open");
1234 } else if (devname != NULL) {
1235 /* if the app specifies an exact string, we can pass the backend
1236 an actual device handle thingey, which saves them the effort of
1237 figuring out what device this was (such as, reenumerating
1238 everything again to find the matching human-readable name).
1239 It might still need to open a device based on the string for,
1240 say, a network audio server, but this optimizes some cases. */
1241 SDL_AudioDeviceItem *item;
1242 SDL_LockMutex(current_audio.detectionLock);
1243 for (item = iscapture ? current_audio.inputDevices : current_audio.outputDevices; item; item = item->next) {
1244 if ((item->handle != NULL) && (SDL_strcmp(item->name, devname) == 0)) {
1245 handle = item->handle;
1249 SDL_UnlockMutex(current_audio.detectionLock);
1252 if (!current_audio.impl.AllowsArbitraryDeviceNames) {
1253 /* has to be in our device list, or the default device. */
1254 if ((handle == NULL) && (devname != NULL)) {
1255 SDL_SetError("No such device.");
1260 device = (SDL_AudioDevice *) SDL_calloc(1, sizeof (SDL_AudioDevice));
1261 if (device == NULL) {
1265 device->id = id + 1;
1266 device->spec = *obtained;
1267 device->iscapture = iscapture ? SDL_TRUE : SDL_FALSE;
1268 device->handle = handle;
1270 SDL_AtomicSet(&device->shutdown, 0); /* just in case. */
1271 SDL_AtomicSet(&device->paused, 1);
1272 SDL_AtomicSet(&device->enabled, 1);
1274 /* Create a mutex for locking the sound buffers */
1275 if (!current_audio.impl.SkipMixerLock) {
1276 device->mixer_lock = SDL_CreateMutex();
1277 if (device->mixer_lock == NULL) {
1278 close_audio_device(device);
1279 SDL_SetError("Couldn't create mixer lock");
1284 if (current_audio.impl.OpenDevice(device, handle, devname, iscapture) < 0) {
1285 close_audio_device(device);
1289 /* if your target really doesn't need it, set it to 0x1 or something. */
1290 /* otherwise, close_audio_device() won't call impl.CloseDevice(). */
1291 SDL_assert(device->hidden != NULL);
1293 /* See if we need to do any conversion */
1294 build_stream = SDL_FALSE;
1295 if (obtained->freq != device->spec.freq) {
1296 if (allowed_changes & SDL_AUDIO_ALLOW_FREQUENCY_CHANGE) {
1297 obtained->freq = device->spec.freq;
1299 build_stream = SDL_TRUE;
1302 if (obtained->format != device->spec.format) {
1303 if (allowed_changes & SDL_AUDIO_ALLOW_FORMAT_CHANGE) {
1304 obtained->format = device->spec.format;
1306 build_stream = SDL_TRUE;
1309 if (obtained->channels != device->spec.channels) {
1310 if (allowed_changes & SDL_AUDIO_ALLOW_CHANNELS_CHANGE) {
1311 obtained->channels = device->spec.channels;
1313 build_stream = SDL_TRUE;
1317 /* !!! FIXME in 2.1: add SDL_AUDIO_ALLOW_SAMPLES_CHANGE flag?
1318 As of 2.0.6, we will build a stream to buffer the difference between
1319 what the app wants to feed and the device wants to eat, so everyone
1320 gets their way. In prior releases, SDL would force the callback to
1321 feed at the rate the device requested, adjusted for resampling.
1323 if (device->spec.samples != obtained->samples) {
1324 build_stream = SDL_TRUE;
1327 SDL_CalculateAudioSpec(obtained); /* recalc after possible changes. */
1329 device->callbackspec = *obtained;
1333 device->stream = SDL_NewAudioStream(device->spec.format,
1334 device->spec.channels, device->spec.freq,
1335 obtained->format, obtained->channels, obtained->freq);
1337 device->stream = SDL_NewAudioStream(obtained->format, obtained->channels,
1338 obtained->freq, device->spec.format,
1339 device->spec.channels, device->spec.freq);
1342 if (!device->stream) {
1343 close_audio_device(device);
1348 if (device->spec.callback == NULL) { /* use buffer queueing? */
1349 /* pool a few packets to start. Enough for two callbacks. */
1350 device->buffer_queue = SDL_NewDataQueue(SDL_AUDIOBUFFERQUEUE_PACKETLEN, obtained->size * 2);
1351 if (!device->buffer_queue) {
1352 close_audio_device(device);
1353 SDL_SetError("Couldn't create audio buffer queue");
1356 device->callbackspec.callback = iscapture ? SDL_BufferQueueFillCallback : SDL_BufferQueueDrainCallback;
1357 device->callbackspec.userdata = device;
1360 /* Allocate a scratch audio buffer */
1361 device->work_buffer_len = build_stream ? device->callbackspec.size : 0;
1362 if (device->spec.size > device->work_buffer_len) {
1363 device->work_buffer_len = device->spec.size;
1365 SDL_assert(device->work_buffer_len > 0);
1367 device->work_buffer = (Uint8 *) SDL_malloc(device->work_buffer_len);
1368 if (device->work_buffer == NULL) {
1369 close_audio_device(device);
1374 open_devices[id] = device; /* add it to our list of open devices. */
1376 /* Start the audio thread if necessary */
1377 if (!current_audio.impl.ProvidesOwnCallbackThread) {
1378 /* Start the audio thread */
1379 /* !!! FIXME: we don't force the audio thread stack size here if it calls into user code, but maybe we should? */
1380 /* buffer queueing callback only needs a few bytes, so make the stack tiny. */
1381 const size_t stacksize = is_internal_thread ? 64 * 1024 : 0;
1382 char threadname[64];
1384 SDL_snprintf(threadname, sizeof (threadname), "SDLAudio%c%d", (iscapture) ? 'C' : 'P', (int) device->id);
1385 device->thread = SDL_CreateThreadInternal(iscapture ? SDL_CaptureAudio : SDL_RunAudio, threadname, stacksize, device);
1387 if (device->thread == NULL) {
1388 close_audio_device(device);
1389 SDL_SetError("Couldn't create audio thread");
1399 SDL_OpenAudio(SDL_AudioSpec * desired, SDL_AudioSpec * obtained)
1401 SDL_AudioDeviceID id = 0;
1403 /* Start up the audio driver, if necessary. This is legacy behaviour! */
1404 if (!SDL_WasInit(SDL_INIT_AUDIO)) {
1405 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
1410 /* SDL_OpenAudio() is legacy and can only act on Device ID #1. */
1411 if (open_devices[0] != NULL) {
1412 SDL_SetError("Audio device is already opened");
1417 id = open_audio_device(NULL, 0, desired, obtained,
1418 SDL_AUDIO_ALLOW_ANY_CHANGE, 1);
1420 SDL_AudioSpec _obtained;
1421 SDL_zero(_obtained);
1422 id = open_audio_device(NULL, 0, desired, &_obtained, 0, 1);
1423 /* On successful open, copy calculated values into 'desired'. */
1425 desired->size = _obtained.size;
1426 desired->silence = _obtained.silence;
1430 SDL_assert((id == 0) || (id == 1));
1431 return (id == 0) ? -1 : 0;
1435 SDL_OpenAudioDevice(const char *device, int iscapture,
1436 const SDL_AudioSpec * desired, SDL_AudioSpec * obtained,
1437 int allowed_changes)
1439 return open_audio_device(device, iscapture, desired, obtained,
1440 allowed_changes, 2);
1444 SDL_GetAudioDeviceStatus(SDL_AudioDeviceID devid)
1446 SDL_AudioDevice *device = get_audio_device(devid);
1447 SDL_AudioStatus status = SDL_AUDIO_STOPPED;
1448 if (device && SDL_AtomicGet(&device->enabled)) {
1449 if (SDL_AtomicGet(&device->paused)) {
1450 status = SDL_AUDIO_PAUSED;
1452 status = SDL_AUDIO_PLAYING;
1460 SDL_GetAudioStatus(void)
1462 return SDL_GetAudioDeviceStatus(1);
1466 SDL_PauseAudioDevice(SDL_AudioDeviceID devid, int pause_on)
1468 SDL_AudioDevice *device = get_audio_device(devid);
1470 current_audio.impl.LockDevice(device);
1471 SDL_AtomicSet(&device->paused, pause_on ? 1 : 0);
1472 current_audio.impl.UnlockDevice(device);
1477 SDL_PauseAudio(int pause_on)
1479 SDL_PauseAudioDevice(1, pause_on);
1484 SDL_LockAudioDevice(SDL_AudioDeviceID devid)
1486 /* Obtain a lock on the mixing buffers */
1487 SDL_AudioDevice *device = get_audio_device(devid);
1489 current_audio.impl.LockDevice(device);
1496 SDL_LockAudioDevice(1);
1500 SDL_UnlockAudioDevice(SDL_AudioDeviceID devid)
1502 /* Obtain a lock on the mixing buffers */
1503 SDL_AudioDevice *device = get_audio_device(devid);
1505 current_audio.impl.UnlockDevice(device);
1510 SDL_UnlockAudio(void)
1512 SDL_UnlockAudioDevice(1);
1516 SDL_CloseAudioDevice(SDL_AudioDeviceID devid)
1518 close_audio_device(get_audio_device(devid));
1522 SDL_CloseAudio(void)
1524 SDL_CloseAudioDevice(1);
1530 SDL_AudioDeviceID i;
1532 if (!current_audio.name) { /* not initialized?! */
1536 for (i = 0; i < SDL_arraysize(open_devices); i++) {
1537 close_audio_device(open_devices[i]);
1540 free_device_list(¤t_audio.outputDevices, ¤t_audio.outputDeviceCount);
1541 free_device_list(¤t_audio.inputDevices, ¤t_audio.inputDeviceCount);
1543 /* Free the driver data */
1544 current_audio.impl.Deinitialize();
1546 SDL_DestroyMutex(current_audio.detectionLock);
1548 SDL_zero(current_audio);
1549 SDL_zero(open_devices);
1551 #ifdef HAVE_LIBSAMPLERATE_H
1552 UnloadLibSampleRate();
1555 SDL_FreeResampleFilter();
1558 #define NUM_FORMATS 10
1559 static int format_idx;
1560 static int format_idx_sub;
1561 static SDL_AudioFormat format_list[NUM_FORMATS][NUM_FORMATS] = {
1562 {AUDIO_U8, AUDIO_S8, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB,
1563 AUDIO_U16MSB, AUDIO_S32LSB, AUDIO_S32MSB, AUDIO_F32LSB, AUDIO_F32MSB},
1564 {AUDIO_S8, AUDIO_U8, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB,
1565 AUDIO_U16MSB, AUDIO_S32LSB, AUDIO_S32MSB, AUDIO_F32LSB, AUDIO_F32MSB},
1566 {AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_S32LSB,
1567 AUDIO_S32MSB, AUDIO_F32LSB, AUDIO_F32MSB, AUDIO_U8, AUDIO_S8},
1568 {AUDIO_S16MSB, AUDIO_S16LSB, AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_S32MSB,
1569 AUDIO_S32LSB, AUDIO_F32MSB, AUDIO_F32LSB, AUDIO_U8, AUDIO_S8},
1570 {AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_S32LSB,
1571 AUDIO_S32MSB, AUDIO_F32LSB, AUDIO_F32MSB, AUDIO_U8, AUDIO_S8},
1572 {AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_S16MSB, AUDIO_S16LSB, AUDIO_S32MSB,
1573 AUDIO_S32LSB, AUDIO_F32MSB, AUDIO_F32LSB, AUDIO_U8, AUDIO_S8},
1574 {AUDIO_S32LSB, AUDIO_S32MSB, AUDIO_F32LSB, AUDIO_F32MSB, AUDIO_S16LSB,
1575 AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_U8, AUDIO_S8},
1576 {AUDIO_S32MSB, AUDIO_S32LSB, AUDIO_F32MSB, AUDIO_F32LSB, AUDIO_S16MSB,
1577 AUDIO_S16LSB, AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_U8, AUDIO_S8},
1578 {AUDIO_F32LSB, AUDIO_F32MSB, AUDIO_S32LSB, AUDIO_S32MSB, AUDIO_S16LSB,
1579 AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_U8, AUDIO_S8},
1580 {AUDIO_F32MSB, AUDIO_F32LSB, AUDIO_S32MSB, AUDIO_S32LSB, AUDIO_S16MSB,
1581 AUDIO_S16LSB, AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_U8, AUDIO_S8},
1585 SDL_FirstAudioFormat(SDL_AudioFormat format)
1587 for (format_idx = 0; format_idx < NUM_FORMATS; ++format_idx) {
1588 if (format_list[format_idx][0] == format) {
1593 return SDL_NextAudioFormat();
1597 SDL_NextAudioFormat(void)
1599 if ((format_idx == NUM_FORMATS) || (format_idx_sub == NUM_FORMATS)) {
1602 return format_list[format_idx][format_idx_sub++];
1606 SDL_CalculateAudioSpec(SDL_AudioSpec * spec)
1608 switch (spec->format) {
1610 spec->silence = 0x80;
1613 spec->silence = 0x00;
1616 spec->size = SDL_AUDIO_BITSIZE(spec->format) / 8;
1617 spec->size *= spec->channels;
1618 spec->size *= spec->samples;
1623 * Moved here from SDL_mixer.c, since it relies on internals of an opened
1624 * audio device (and is deprecated, by the way!).
1627 SDL_MixAudio(Uint8 * dst, const Uint8 * src, Uint32 len, int volume)
1629 /* Mix the user-level audio format */
1630 SDL_AudioDevice *device = get_audio_device(1);
1631 if (device != NULL) {
1632 SDL_MixAudioFormat(dst, src, device->callbackspec.format, len, volume);
1636 /* vi: set ts=4 sw=4 expandtab: */