1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
4
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.
8
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:
12
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.
20*/
21#include "SDL_internal.h"
22
23#include "SDL_audio_c.h"
24#include "SDL_sysaudio.h"
25#include "../thread/SDL_systhread.h"
26
27// Available audio drivers
28static const AudioBootStrap *const bootstrap[] = {
29#ifdef SDL_AUDIO_DRIVER_PRIVATE
30 &PRIVATEAUDIO_bootstrap,
31#endif
32#ifdef SDL_AUDIO_DRIVER_PULSEAUDIO
33#ifdef SDL_AUDIO_DRIVER_PIPEWIRE
34 &PIPEWIRE_PREFERRED_bootstrap,
35#endif
36 &PULSEAUDIO_bootstrap,
37#endif
38#ifdef SDL_AUDIO_DRIVER_PIPEWIRE
39 &PIPEWIRE_bootstrap,
40#endif
41#ifdef SDL_AUDIO_DRIVER_ALSA
42 &ALSA_bootstrap,
43#endif
44#ifdef SDL_AUDIO_DRIVER_SNDIO
45 &SNDIO_bootstrap,
46#endif
47#ifdef SDL_AUDIO_DRIVER_NETBSD
48 &NETBSDAUDIO_bootstrap,
49#endif
50#ifdef SDL_AUDIO_DRIVER_WASAPI
51 &WASAPI_bootstrap,
52#endif
53#ifdef SDL_AUDIO_DRIVER_DSOUND
54 &DSOUND_bootstrap,
55#endif
56#ifdef SDL_AUDIO_DRIVER_HAIKU
57 &HAIKUAUDIO_bootstrap,
58#endif
59#ifdef SDL_AUDIO_DRIVER_COREAUDIO
60 &COREAUDIO_bootstrap,
61#endif
62#ifdef SDL_AUDIO_DRIVER_AAUDIO
63 &AAUDIO_bootstrap,
64#endif
65#ifdef SDL_AUDIO_DRIVER_OPENSLES
66 &OPENSLES_bootstrap,
67#endif
68#ifdef SDL_AUDIO_DRIVER_PS2
69 &PS2AUDIO_bootstrap,
70#endif
71#ifdef SDL_AUDIO_DRIVER_PSP
72 &PSPAUDIO_bootstrap,
73#endif
74#ifdef SDL_AUDIO_DRIVER_VITA
75 &VITAAUD_bootstrap,
76#endif
77#ifdef SDL_AUDIO_DRIVER_N3DS
78 &N3DSAUDIO_bootstrap,
79#endif
80#ifdef SDL_AUDIO_DRIVER_EMSCRIPTEN
81 &EMSCRIPTENAUDIO_bootstrap,
82#endif
83#ifdef SDL_AUDIO_DRIVER_JACK
84 &JACK_bootstrap,
85#endif
86#ifdef SDL_AUDIO_DRIVER_OSS
87 &DSP_bootstrap,
88#endif
89#ifdef SDL_AUDIO_DRIVER_QNX
90 &QSAAUDIO_bootstrap,
91#endif
92#ifdef SDL_AUDIO_DRIVER_DISK
93 &DISKAUDIO_bootstrap,
94#endif
95#ifdef SDL_AUDIO_DRIVER_DUMMY
96 &DUMMYAUDIO_bootstrap,
97#endif
98 NULL
99};
100
101static SDL_AudioDriver current_audio;
102
103// Deduplicated list of audio bootstrap drivers.
104static const AudioBootStrap *deduped_bootstrap[SDL_arraysize(bootstrap) - 1];
105
106int SDL_GetNumAudioDrivers(void)
107{
108 static int num_drivers = -1;
109
110 if (num_drivers >= 0) {
111 return num_drivers;
112 }
113
114 num_drivers = 0;
115
116 // Build a list of unique audio drivers.
117 for (int i = 0; bootstrap[i] != NULL; ++i) {
118 bool duplicate = false;
119 for (int j = 0; j < i; ++j) {
120 if (SDL_strcmp(bootstrap[i]->name, bootstrap[j]->name) == 0) {
121 duplicate = true;
122 break;
123 }
124 }
125
126 if (!duplicate) {
127 deduped_bootstrap[num_drivers++] = bootstrap[i];
128 }
129 }
130
131 return num_drivers;
132}
133
134const char *SDL_GetAudioDriver(int index)
135{
136 if (index >= 0 && index < SDL_GetNumAudioDrivers()) {
137 return deduped_bootstrap[index]->name;
138 }
139 SDL_InvalidParamError("index");
140 return NULL;
141}
142
143const char *SDL_GetCurrentAudioDriver(void)
144{
145 return current_audio.name;
146}
147
148int SDL_GetDefaultSampleFramesFromFreq(const int freq)
149{
150 const char *hint = SDL_GetHint(SDL_HINT_AUDIO_DEVICE_SAMPLE_FRAMES);
151 if (hint) {
152 const int val = SDL_atoi(hint);
153 if (val > 0) {
154 return val;
155 }
156 }
157
158 if (freq <= 22050) {
159 return 512;
160 } else if (freq <= 48000) {
161 return 1024;
162 } else if (freq <= 96000) {
163 return 2048;
164 } else {
165 return 4096;
166 }
167}
168
169int *SDL_ChannelMapDup(const int *origchmap, int channels)
170{
171 const size_t chmaplen = sizeof (*origchmap) * channels;
172 int *chmap = (int *)SDL_malloc(chmaplen);
173 if (chmap) {
174 SDL_memcpy(chmap, origchmap, chmaplen);
175 }
176 return chmap;
177}
178
179void OnAudioStreamCreated(SDL_AudioStream *stream)
180{
181 SDL_assert(stream != NULL);
182
183 // NOTE that you can create an audio stream without initializing the audio subsystem,
184 // but it will not be automatically destroyed during a later call to SDL_Quit!
185 // You must explicitly destroy it yourself!
186 if (current_audio.device_hash_lock) {
187 // this isn't really part of the "device list" but it's a convenient lock to use here.
188 SDL_LockRWLockForWriting(current_audio.device_hash_lock);
189 if (current_audio.existing_streams) {
190 current_audio.existing_streams->prev = stream;
191 }
192 stream->prev = NULL;
193 stream->next = current_audio.existing_streams;
194 current_audio.existing_streams = stream;
195 SDL_UnlockRWLock(current_audio.device_hash_lock);
196 }
197}
198
199void OnAudioStreamDestroy(SDL_AudioStream *stream)
200{
201 SDL_assert(stream != NULL);
202
203 // NOTE that you can create an audio stream without initializing the audio subsystem,
204 // but it will not be automatically destroyed during a later call to SDL_Quit!
205 // You must explicitly destroy it yourself!
206 if (current_audio.device_hash_lock) {
207 // this isn't really part of the "device list" but it's a convenient lock to use here.
208 SDL_LockRWLockForWriting(current_audio.device_hash_lock);
209 if (stream->prev) {
210 stream->prev->next = stream->next;
211 }
212 if (stream->next) {
213 stream->next->prev = stream->prev;
214 }
215 if (stream == current_audio.existing_streams) {
216 current_audio.existing_streams = stream->next;
217 }
218 SDL_UnlockRWLock(current_audio.device_hash_lock);
219 }
220}
221
222// device should be locked when calling this.
223static bool AudioDeviceCanUseSimpleCopy(SDL_AudioDevice *device)
224{
225 SDL_assert(device != NULL);
226 return (
227 device->logical_devices && // there's a logical device
228 !device->logical_devices->next && // there's only _ONE_ logical device
229 !device->logical_devices->postmix && // there isn't a postmix callback
230 device->logical_devices->bound_streams && // there's a bound stream
231 !device->logical_devices->bound_streams->next_binding // there's only _ONE_ bound stream.
232 );
233}
234
235// should hold device->lock before calling.
236static void UpdateAudioStreamFormatsPhysical(SDL_AudioDevice *device)
237{
238 if (!device) {
239 return;
240 }
241
242 const bool recording = device->recording;
243 SDL_AudioSpec spec;
244 SDL_copyp(&spec, &device->spec);
245
246 const SDL_AudioFormat devformat = spec.format;
247
248 if (!recording) {
249 const bool simple_copy = AudioDeviceCanUseSimpleCopy(device);
250 device->simple_copy = simple_copy;
251 if (!simple_copy) {
252 spec.format = SDL_AUDIO_F32; // mixing and postbuf operates in float32 format.
253 }
254 }
255
256 for (SDL_LogicalAudioDevice *logdev = device->logical_devices; logdev; logdev = logdev->next) {
257 if (recording) {
258 const bool need_float32 = (logdev->postmix || logdev->gain != 1.0f);
259 spec.format = need_float32 ? SDL_AUDIO_F32 : devformat;
260 }
261
262 for (SDL_AudioStream *stream = logdev->bound_streams; stream; stream = stream->next_binding) {
263 // set the proper end of the stream to the device's format.
264 // SDL_SetAudioStreamFormat does a ton of validation just to memcpy an audiospec.
265 SDL_AudioSpec *streamspec = recording ? &stream->src_spec : &stream->dst_spec;
266 int **streamchmap = recording ? &stream->src_chmap : &stream->dst_chmap;
267 SDL_LockMutex(stream->lock);
268 SDL_copyp(streamspec, &spec);
269 SetAudioStreamChannelMap(stream, streamspec, streamchmap, device->chmap, device->spec.channels, -1); // this should be fast for normal cases, though!
270 SDL_UnlockMutex(stream->lock);
271 }
272 }
273}
274
275bool SDL_AudioSpecsEqual(const SDL_AudioSpec *a, const SDL_AudioSpec *b, const int *channel_map_a, const int *channel_map_b)
276{
277 if ((a->format != b->format) || (a->channels != b->channels) || (a->freq != b->freq) || ((channel_map_a != NULL) != (channel_map_b != NULL))) {
278 return false;
279 } else if (channel_map_a && (SDL_memcmp(channel_map_a, channel_map_b, sizeof (*channel_map_a) * a->channels) != 0)) {
280 return false;
281 }
282 return true;
283}
284
285bool SDL_AudioChannelMapsEqual(int channels, const int *channel_map_a, const int *channel_map_b)
286{
287 if (channel_map_a == channel_map_b) {
288 return true;
289 } else if ((channel_map_a != NULL) != (channel_map_b != NULL)) {
290 return false;
291 } else if (channel_map_a && (SDL_memcmp(channel_map_a, channel_map_b, sizeof (*channel_map_a) * channels) != 0)) {
292 return false;
293 }
294 return true;
295}
296
297
298// Zombie device implementation...
299
300// These get used when a device is disconnected or fails, so audiostreams don't overflow with data that isn't being
301// consumed and apps relying on audio callbacks don't stop making progress.
302static bool ZombieWaitDevice(SDL_AudioDevice *device)
303{
304 if (!SDL_GetAtomicInt(&device->shutdown)) {
305 const int frames = device->buffer_size / SDL_AUDIO_FRAMESIZE(device->spec);
306 SDL_Delay((frames * 1000) / device->spec.freq);
307 }
308 return true;
309}
310
311static bool ZombiePlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
312{
313 return true; // no-op, just throw the audio away.
314}
315
316static Uint8 *ZombieGetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
317{
318 return device->work_buffer;
319}
320
321static int ZombieRecordDevice(SDL_AudioDevice *device, void *buffer, int buflen)
322{
323 // return a full buffer of silence every time.
324 SDL_memset(buffer, device->silence_value, buflen);
325 return buflen;
326}
327
328static void ZombieFlushRecording(SDL_AudioDevice *device)
329{
330 // no-op, this is all imaginary.
331}
332
333
334
335// device management and hotplug...
336
337
338/* SDL_AudioDevice, in SDL3, represents a piece of physical hardware, whether it is in use or not, so these objects exist as long as
339 the system-level device is available.
340
341 Physical devices get destroyed for three reasons:
342 - They were lost to the system (a USB cable is kicked out, etc).
343 - They failed for some other unlikely reason at the API level (which is _also_ probably a USB cable being kicked out).
344 - We are shutting down, so all allocated resources are being freed.
345
346 They are _not_ destroyed because we are done using them (when we "close" a playing device).
347*/
348static void ClosePhysicalAudioDevice(SDL_AudioDevice *device);
349
350
351SDL_COMPILE_TIME_ASSERT(check_lowest_audio_default_value, SDL_AUDIO_DEVICE_DEFAULT_RECORDING < SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK);
352
353static SDL_AtomicInt last_device_instance_id; // increments on each device add to provide unique instance IDs
354static SDL_AudioDeviceID AssignAudioDeviceInstanceId(bool recording, bool islogical)
355{
356 /* Assign an instance id! Start at 2, in case there are things from the SDL2 era that still think 1 is a special value.
357 Also, make sure we don't assign SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, etc. */
358
359 // The bottom two bits of the instance id tells you if it's an playback device (1<<0), and if it's a physical device (1<<1).
360 const SDL_AudioDeviceID flags = (recording ? 0 : (1<<0)) | (islogical ? 0 : (1<<1));
361
362 const SDL_AudioDeviceID instance_id = (((SDL_AudioDeviceID) (SDL_AtomicIncRef(&last_device_instance_id) + 1)) << 2) | flags;
363 SDL_assert( (instance_id >= 2) && (instance_id < SDL_AUDIO_DEVICE_DEFAULT_RECORDING) );
364 return instance_id;
365}
366
367bool SDL_IsAudioDevicePhysical(SDL_AudioDeviceID devid)
368{
369 return (devid & (1 << 1)) != 0;
370}
371
372bool SDL_IsAudioDevicePlayback(SDL_AudioDeviceID devid)
373{
374 return (devid & (1 << 0)) != 0;
375}
376
377static void ObtainPhysicalAudioDeviceObj(SDL_AudioDevice *device) SDL_NO_THREAD_SAFETY_ANALYSIS // !!! FIXMEL SDL_ACQUIRE
378{
379 if (device) {
380 RefPhysicalAudioDevice(device);
381 SDL_LockMutex(device->lock);
382 }
383}
384
385static void ReleaseAudioDevice(SDL_AudioDevice *device) SDL_NO_THREAD_SAFETY_ANALYSIS // !!! FIXME: SDL_RELEASE
386{
387 if (device) {
388 SDL_UnlockMutex(device->lock);
389 UnrefPhysicalAudioDevice(device);
390 }
391}
392
393// If found, this locks _the physical device_ this logical device is associated with, before returning.
394static SDL_LogicalAudioDevice *ObtainLogicalAudioDevice(SDL_AudioDeviceID devid, SDL_AudioDevice **_device) SDL_NO_THREAD_SAFETY_ANALYSIS // !!! FIXME: SDL_ACQUIRE
395{
396 SDL_assert(_device != NULL);
397
398 if (!SDL_GetCurrentAudioDriver()) {
399 SDL_SetError("Audio subsystem is not initialized");
400 *_device = NULL;
401 return NULL;
402 }
403
404 SDL_AudioDevice *device = NULL;
405 SDL_LogicalAudioDevice *logdev = NULL;
406
407 // bit #1 of devid is set for physical devices and unset for logical.
408 const bool islogical = !(devid & (1<<1));
409 if (islogical) { // don't bother looking if it's not a logical device id value.
410 SDL_LockRWLockForReading(current_audio.device_hash_lock);
411 SDL_FindInHashTable(current_audio.device_hash, (const void *) (uintptr_t) devid, (const void **) &logdev);
412 if (logdev) {
413 device = logdev->physical_device;
414 SDL_assert(device != NULL);
415 RefPhysicalAudioDevice(device); // reference it, in case the logical device migrates to a new default.
416 }
417 SDL_UnlockRWLock(current_audio.device_hash_lock);
418
419 if (logdev) {
420 // we have to release the device_hash_lock before we take the device lock, to avoid deadlocks, so do a loop
421 // to make sure the correct physical device gets locked, in case we're in a race with the default changing.
422 while (true) {
423 SDL_LockMutex(device->lock);
424 SDL_AudioDevice *recheck_device = (SDL_AudioDevice *) SDL_GetAtomicPointer((void **) &logdev->physical_device);
425 if (device == recheck_device) {
426 break;
427 }
428
429 // default changed from under us! Try again!
430 RefPhysicalAudioDevice(recheck_device);
431 SDL_UnlockMutex(device->lock);
432 UnrefPhysicalAudioDevice(device);
433 device = recheck_device;
434 }
435 }
436 }
437
438 if (!logdev) {
439 SDL_SetError("Invalid audio device instance ID");
440 }
441
442 *_device = device;
443 return logdev;
444}
445
446
447/* this finds the physical device associated with `devid` and locks it for use.
448 Note that a logical device instance id will return its associated physical device! */
449static SDL_AudioDevice *ObtainPhysicalAudioDevice(SDL_AudioDeviceID devid) // !!! FIXME: SDL_ACQUIRE
450{
451 SDL_AudioDevice *device = NULL;
452
453 // bit #1 of devid is set for physical devices and unset for logical.
454 const bool islogical = !(devid & (1<<1));
455 if (islogical) {
456 ObtainLogicalAudioDevice(devid, &device);
457 } else if (!SDL_GetCurrentAudioDriver()) { // (the `islogical` path, above, checks this in ObtainLogicalAudioDevice.)
458 SDL_SetError("Audio subsystem is not initialized");
459 } else {
460 SDL_LockRWLockForReading(current_audio.device_hash_lock);
461 SDL_FindInHashTable(current_audio.device_hash, (const void *) (uintptr_t) devid, (const void **) &device);
462 SDL_UnlockRWLock(current_audio.device_hash_lock);
463
464 if (!device) {
465 SDL_SetError("Invalid audio device instance ID");
466 } else {
467 ObtainPhysicalAudioDeviceObj(device);
468 }
469 }
470
471 return device;
472}
473
474static SDL_AudioDevice *ObtainPhysicalAudioDeviceDefaultAllowed(SDL_AudioDeviceID devid) // !!! FIXME: SDL_ACQUIRE
475{
476 const bool wants_default = ((devid == SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK) || (devid == SDL_AUDIO_DEVICE_DEFAULT_RECORDING));
477 if (!wants_default) {
478 return ObtainPhysicalAudioDevice(devid);
479 }
480
481 const SDL_AudioDeviceID orig_devid = devid;
482
483 while (true) {
484 SDL_LockRWLockForReading(current_audio.device_hash_lock);
485 if (orig_devid == SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK) {
486 devid = current_audio.default_playback_device_id;
487 } else if (orig_devid == SDL_AUDIO_DEVICE_DEFAULT_RECORDING) {
488 devid = current_audio.default_recording_device_id;
489 }
490 SDL_UnlockRWLock(current_audio.device_hash_lock);
491
492 if (devid == 0) {
493 SDL_SetError("No default audio device available");
494 break;
495 }
496
497 SDL_AudioDevice *device = ObtainPhysicalAudioDevice(devid);
498 if (!device) {
499 break;
500 }
501
502 // make sure the default didn't change while we were waiting for the lock...
503 bool got_it = false;
504 SDL_LockRWLockForReading(current_audio.device_hash_lock);
505 if ((orig_devid == SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK) && (devid == current_audio.default_playback_device_id)) {
506 got_it = true;
507 } else if ((orig_devid == SDL_AUDIO_DEVICE_DEFAULT_RECORDING) && (devid == current_audio.default_recording_device_id)) {
508 got_it = true;
509 }
510 SDL_UnlockRWLock(current_audio.device_hash_lock);
511
512 if (got_it) {
513 return device;
514 }
515
516 ReleaseAudioDevice(device); // let it go and try again.
517 }
518
519 return NULL;
520}
521
522// this assumes you hold the _physical_ device lock for this logical device! This will not unlock the lock or close the physical device!
523// It also will not unref the physical device, since we might be shutting down; SDL_CloseAudioDevice handles the unref.
524static void DestroyLogicalAudioDevice(SDL_LogicalAudioDevice *logdev)
525{
526 // Remove ourselves from the device_hash hashtable.
527 if (current_audio.device_hash) { // will be NULL while shutting down.
528 SDL_LockRWLockForWriting(current_audio.device_hash_lock);
529 SDL_RemoveFromHashTable(current_audio.device_hash, (const void *) (uintptr_t) logdev->instance_id);
530 SDL_UnlockRWLock(current_audio.device_hash_lock);
531 }
532
533 // remove ourselves from the physical device's list of logical devices.
534 if (logdev->next) {
535 logdev->next->prev = logdev->prev;
536 }
537 if (logdev->prev) {
538 logdev->prev->next = logdev->next;
539 }
540 if (logdev->physical_device->logical_devices == logdev) {
541 logdev->physical_device->logical_devices = logdev->next;
542 }
543
544 // unbind any still-bound streams...
545 SDL_AudioStream *next;
546 for (SDL_AudioStream *stream = logdev->bound_streams; stream; stream = next) {
547 SDL_LockMutex(stream->lock);
548 next = stream->next_binding;
549 stream->next_binding = NULL;
550 stream->prev_binding = NULL;
551 stream->bound_device = NULL;
552 SDL_UnlockMutex(stream->lock);
553 }
554
555 UpdateAudioStreamFormatsPhysical(logdev->physical_device);
556 SDL_free(logdev);
557}
558
559// this must not be called while `device` is still in a device list, or while a device's audio thread is still running.
560static void DestroyPhysicalAudioDevice(SDL_AudioDevice *device)
561{
562 if (!device) {
563 return;
564 }
565
566 // Destroy any logical devices that still exist...
567 SDL_LockMutex(device->lock); // don't use ObtainPhysicalAudioDeviceObj because we don't want to change refcounts while destroying.
568 while (device->logical_devices) {
569 DestroyLogicalAudioDevice(device->logical_devices);
570 }
571
572 ClosePhysicalAudioDevice(device);
573
574 current_audio.impl.FreeDeviceHandle(device);
575
576 SDL_UnlockMutex(device->lock); // don't use ReleaseAudioDevice because we don't want to change refcounts while destroying.
577
578 SDL_DestroyMutex(device->lock);
579 SDL_DestroyCondition(device->close_cond);
580 SDL_free(device->work_buffer);
581 SDL_free(device->chmap);
582 SDL_free(device->name);
583 SDL_free(device);
584}
585
586// Don't hold the device lock when calling this, as we may destroy the device!
587void UnrefPhysicalAudioDevice(SDL_AudioDevice *device)
588{
589 if (SDL_AtomicDecRef(&device->refcount)) {
590 // take it out of the device list.
591 SDL_LockRWLockForWriting(current_audio.device_hash_lock);
592 if (SDL_RemoveFromHashTable(current_audio.device_hash, (const void *) (uintptr_t) device->instance_id)) {
593 SDL_AddAtomicInt(device->recording ? &current_audio.recording_device_count : &current_audio.playback_device_count, -1);
594 }
595 SDL_UnlockRWLock(current_audio.device_hash_lock);
596 DestroyPhysicalAudioDevice(device); // ...and nuke it.
597 }
598}
599
600void RefPhysicalAudioDevice(SDL_AudioDevice *device)
601{
602 SDL_AtomicIncRef(&device->refcount);
603}
604
605static SDL_AudioDevice *CreatePhysicalAudioDevice(const char *name, bool recording, const SDL_AudioSpec *spec, void *handle, SDL_AtomicInt *device_count)
606{
607 SDL_assert(name != NULL);
608
609 SDL_LockRWLockForReading(current_audio.device_hash_lock);
610 const int shutting_down = SDL_GetAtomicInt(&current_audio.shutting_down);
611 SDL_UnlockRWLock(current_audio.device_hash_lock);
612 if (shutting_down) {
613 return NULL; // we're shutting down, don't add any devices that are hotplugged at the last possible moment.
614 }
615
616 SDL_AudioDevice *device = (SDL_AudioDevice *)SDL_calloc(1, sizeof(SDL_AudioDevice));
617 if (!device) {
618 return NULL;
619 }
620
621 device->name = SDL_strdup(name);
622 if (!device->name) {
623 SDL_free(device);
624 return NULL;
625 }
626
627 device->lock = SDL_CreateMutex();
628 if (!device->lock) {
629 SDL_free(device->name);
630 SDL_free(device);
631 return NULL;
632 }
633
634 device->close_cond = SDL_CreateCondition();
635 if (!device->close_cond) {
636 SDL_DestroyMutex(device->lock);
637 SDL_free(device->name);
638 SDL_free(device);
639 return NULL;
640 }
641
642 SDL_SetAtomicInt(&device->shutdown, 0);
643 SDL_SetAtomicInt(&device->zombie, 0);
644 device->recording = recording;
645 SDL_copyp(&device->spec, spec);
646 SDL_copyp(&device->default_spec, spec);
647 device->sample_frames = SDL_GetDefaultSampleFramesFromFreq(device->spec.freq);
648 device->silence_value = SDL_GetSilenceValueForFormat(device->spec.format);
649 device->handle = handle;
650
651 device->instance_id = AssignAudioDeviceInstanceId(recording, /*islogical=*/false);
652
653 SDL_LockRWLockForWriting(current_audio.device_hash_lock);
654 if (SDL_InsertIntoHashTable(current_audio.device_hash, (const void *) (uintptr_t) device->instance_id, device, false)) {
655 SDL_AddAtomicInt(device_count, 1);
656 } else {
657 SDL_DestroyCondition(device->close_cond);
658 SDL_DestroyMutex(device->lock);
659 SDL_free(device->name);
660 SDL_free(device);
661 device = NULL;
662 }
663 SDL_UnlockRWLock(current_audio.device_hash_lock);
664
665 RefPhysicalAudioDevice(device); // unref'd on device disconnect.
666 return device;
667}
668
669static SDL_AudioDevice *CreateAudioRecordingDevice(const char *name, const SDL_AudioSpec *spec, void *handle)
670{
671 SDL_assert(current_audio.impl.HasRecordingSupport);
672 return CreatePhysicalAudioDevice(name, true, spec, handle, &current_audio.recording_device_count);
673}
674
675static SDL_AudioDevice *CreateAudioPlaybackDevice(const char *name, const SDL_AudioSpec *spec, void *handle)
676{
677 return CreatePhysicalAudioDevice(name, false, spec, handle, &current_audio.playback_device_count);
678}
679
680// The audio backends call this when a new device is plugged in.
681SDL_AudioDevice *SDL_AddAudioDevice(bool recording, const char *name, const SDL_AudioSpec *inspec, void *handle)
682{
683 // device handles MUST be unique! If the target reuses the same handle for hardware with both recording and playback interfaces, wrap it in a pointer you SDL_malloc'd!
684 SDL_assert(SDL_FindPhysicalAudioDeviceByHandle(handle) == NULL);
685
686 const SDL_AudioFormat default_format = recording ? DEFAULT_AUDIO_RECORDING_FORMAT : DEFAULT_AUDIO_PLAYBACK_FORMAT;
687 const int default_channels = recording ? DEFAULT_AUDIO_RECORDING_CHANNELS : DEFAULT_AUDIO_PLAYBACK_CHANNELS;
688 const int default_freq = recording ? DEFAULT_AUDIO_RECORDING_FREQUENCY : DEFAULT_AUDIO_PLAYBACK_FREQUENCY;
689
690 SDL_AudioSpec spec;
691 SDL_zero(spec);
692 if (!inspec) {
693 spec.format = default_format;
694 spec.channels = default_channels;
695 spec.freq = default_freq;
696 } else {
697 spec.format = (inspec->format != 0) ? inspec->format : default_format;
698 spec.channels = (inspec->channels != 0) ? inspec->channels : default_channels;
699 spec.freq = (inspec->freq != 0) ? inspec->freq : default_freq;
700 }
701
702 SDL_AudioDevice *device = recording ? CreateAudioRecordingDevice(name, &spec, handle) : CreateAudioPlaybackDevice(name, &spec, handle);
703
704 // Add a device add event to the pending list, to be pushed when the event queue is pumped (away from any of our internal threads).
705 if (device) {
706 SDL_PendingAudioDeviceEvent *p = (SDL_PendingAudioDeviceEvent *) SDL_malloc(sizeof (SDL_PendingAudioDeviceEvent));
707 if (p) { // if allocation fails, you won't get an event, but we can't help that.
708 p->type = SDL_EVENT_AUDIO_DEVICE_ADDED;
709 p->devid = device->instance_id;
710 p->next = NULL;
711 SDL_LockRWLockForWriting(current_audio.device_hash_lock);
712 SDL_assert(current_audio.pending_events_tail != NULL);
713 SDL_assert(current_audio.pending_events_tail->next == NULL);
714 current_audio.pending_events_tail->next = p;
715 current_audio.pending_events_tail = p;
716 SDL_UnlockRWLock(current_audio.device_hash_lock);
717 }
718 }
719
720 return device;
721}
722
723// Called when a device is removed from the system, or it fails unexpectedly, from any thread, possibly even the audio device's thread.
724void SDL_AudioDeviceDisconnected(SDL_AudioDevice *device)
725{
726 if (!device) {
727 return;
728 }
729
730 // Save off removal info in a list so we can send events for each, next
731 // time the event queue pumps, in case something tries to close a device
732 // from an event filter, as this would risk deadlocks and other disasters
733 // if done from the device thread.
734 SDL_PendingAudioDeviceEvent pending;
735 pending.next = NULL;
736 SDL_PendingAudioDeviceEvent *pending_tail = &pending;
737
738 ObtainPhysicalAudioDeviceObj(device);
739
740 SDL_LockRWLockForReading(current_audio.device_hash_lock);
741 const SDL_AudioDeviceID devid = device->instance_id;
742 const bool is_default_device = ((devid == current_audio.default_playback_device_id) || (devid == current_audio.default_recording_device_id));
743 SDL_UnlockRWLock(current_audio.device_hash_lock);
744
745 const bool first_disconnect = SDL_CompareAndSwapAtomicInt(&device->zombie, 0, 1);
746 if (first_disconnect) { // if already disconnected this device, don't do it twice.
747 // Swap in "Zombie" versions of the usual platform interfaces, so the device will keep
748 // making progress until the app closes it. Otherwise, streams might continue to
749 // accumulate waste data that never drains, apps that depend on audio callbacks to
750 // progress will freeze, etc.
751 device->WaitDevice = ZombieWaitDevice;
752 device->GetDeviceBuf = ZombieGetDeviceBuf;
753 device->PlayDevice = ZombiePlayDevice;
754 device->WaitRecordingDevice = ZombieWaitDevice;
755 device->RecordDevice = ZombieRecordDevice;
756 device->FlushRecording = ZombieFlushRecording;
757
758 // on default devices, dump any logical devices that explicitly opened this device. Things that opened the system default can stay.
759 // on non-default devices, dump everything.
760 // (by "dump" we mean send a REMOVED event; the zombie will keep consuming audio data for these logical devices until explicitly closed.)
761 for (SDL_LogicalAudioDevice *logdev = device->logical_devices; logdev; logdev = logdev->next) {
762 if (!is_default_device || !logdev->opened_as_default) { // if opened as a default, leave it on the zombie device for later migration.
763 SDL_PendingAudioDeviceEvent *p = (SDL_PendingAudioDeviceEvent *) SDL_malloc(sizeof (SDL_PendingAudioDeviceEvent));
764 if (p) { // if this failed, no event for you, but you have deeper problems anyhow.
765 p->type = SDL_EVENT_AUDIO_DEVICE_REMOVED;
766 p->devid = logdev->instance_id;
767 p->next = NULL;
768 pending_tail->next = p;
769 pending_tail = p;
770 }
771 }
772 }
773
774 SDL_PendingAudioDeviceEvent *p = (SDL_PendingAudioDeviceEvent *) SDL_malloc(sizeof (SDL_PendingAudioDeviceEvent));
775 if (p) { // if this failed, no event for you, but you have deeper problems anyhow.
776 p->type = SDL_EVENT_AUDIO_DEVICE_REMOVED;
777 p->devid = device->instance_id;
778 p->next = NULL;
779 pending_tail->next = p;
780 pending_tail = p;
781 }
782 }
783
784 ReleaseAudioDevice(device);
785
786 if (first_disconnect) {
787 if (pending.next) { // NULL if event is disabled or disaster struck.
788 SDL_LockRWLockForWriting(current_audio.device_hash_lock);
789 SDL_assert(current_audio.pending_events_tail != NULL);
790 SDL_assert(current_audio.pending_events_tail->next == NULL);
791 current_audio.pending_events_tail->next = pending.next;
792 current_audio.pending_events_tail = pending_tail;
793 SDL_UnlockRWLock(current_audio.device_hash_lock);
794 }
795
796 UnrefPhysicalAudioDevice(device);
797 }
798}
799
800
801// stubs for audio drivers that don't need a specific entry point...
802
803static void SDL_AudioThreadDeinit_Default(SDL_AudioDevice *device) { /* no-op. */ }
804static bool SDL_AudioWaitDevice_Default(SDL_AudioDevice *device) { return true; /* no-op. */ }
805static bool SDL_AudioPlayDevice_Default(SDL_AudioDevice *device, const Uint8 *buffer, int buffer_size) { return true; /* no-op. */ }
806static bool SDL_AudioWaitRecordingDevice_Default(SDL_AudioDevice *device) { return true; /* no-op. */ }
807static void SDL_AudioFlushRecording_Default(SDL_AudioDevice *device) { /* no-op. */ }
808static void SDL_AudioCloseDevice_Default(SDL_AudioDevice *device) { /* no-op. */ }
809static void SDL_AudioDeinitializeStart_Default(void) { /* no-op. */ }
810static void SDL_AudioDeinitialize_Default(void) { /* no-op. */ }
811static void SDL_AudioFreeDeviceHandle_Default(SDL_AudioDevice *device) { /* no-op. */ }
812
813static void SDL_AudioThreadInit_Default(SDL_AudioDevice *device)
814{
815 SDL_SetCurrentThreadPriority(device->recording ? SDL_THREAD_PRIORITY_HIGH : SDL_THREAD_PRIORITY_TIME_CRITICAL);
816}
817
818static void SDL_AudioDetectDevices_Default(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording)
819{
820 // you have to write your own implementation if these assertions fail.
821 SDL_assert(current_audio.impl.OnlyHasDefaultPlaybackDevice);
822 SDL_assert(current_audio.impl.OnlyHasDefaultRecordingDevice || !current_audio.impl.HasRecordingSupport);
823
824 *default_playback = SDL_AddAudioDevice(false, DEFAULT_PLAYBACK_DEVNAME, NULL, (void *)((size_t)0x1));
825 if (current_audio.impl.HasRecordingSupport) {
826 *default_recording = SDL_AddAudioDevice(true, DEFAULT_RECORDING_DEVNAME, NULL, (void *)((size_t)0x2));
827 }
828}
829
830static Uint8 *SDL_AudioGetDeviceBuf_Default(SDL_AudioDevice *device, int *buffer_size)
831{
832 *buffer_size = 0;
833 return NULL;
834}
835
836static int SDL_AudioRecordDevice_Default(SDL_AudioDevice *device, void *buffer, int buflen)
837{
838 SDL_Unsupported();
839 return -1;
840}
841
842static bool SDL_AudioOpenDevice_Default(SDL_AudioDevice *device)
843{
844 return SDL_Unsupported();
845}
846
847// Fill in stub functions for unused driver entry points. This lets us blindly call them without having to check for validity first.
848static void CompleteAudioEntryPoints(void)
849{
850 #define FILL_STUB(x) if (!current_audio.impl.x) { current_audio.impl.x = SDL_Audio##x##_Default; }
851 FILL_STUB(DetectDevices);
852 FILL_STUB(OpenDevice);
853 FILL_STUB(ThreadInit);
854 FILL_STUB(ThreadDeinit);
855 FILL_STUB(WaitDevice);
856 FILL_STUB(PlayDevice);
857 FILL_STUB(GetDeviceBuf);
858 FILL_STUB(WaitRecordingDevice);
859 FILL_STUB(RecordDevice);
860 FILL_STUB(FlushRecording);
861 FILL_STUB(CloseDevice);
862 FILL_STUB(FreeDeviceHandle);
863 FILL_STUB(DeinitializeStart);
864 FILL_STUB(Deinitialize);
865 #undef FILL_STUB
866}
867
868typedef struct FindLowestDeviceIDData
869{
870 const bool recording;
871 SDL_AudioDeviceID highest;
872 SDL_AudioDevice *result;
873} FindLowestDeviceIDData;
874
875static bool SDLCALL FindLowestDeviceID(void *userdata, const SDL_HashTable *table, const void *key, const void *value)
876{
877 FindLowestDeviceIDData *data = (FindLowestDeviceIDData *) userdata;
878 const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key;
879 // bit #0 of devid is set for playback devices and unset for recording.
880 // bit #1 of devid is set for physical devices and unset for logical.
881 const bool devid_recording = !(devid & (1 << 0));
882 const bool isphysical = !!(devid & (1 << 1));
883 if (isphysical && (devid_recording == data->recording) && (devid < data->highest)) {
884 data->highest = devid;
885 data->result = (SDL_AudioDevice *) value;
886 }
887 return true; // keep iterating.
888}
889
890static SDL_AudioDevice *GetFirstAddedAudioDevice(const bool recording)
891{
892 const SDL_AudioDeviceID highest = SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK; // According to AssignAudioDeviceInstanceId, nothing can have a value this large.
893
894 // (Device IDs increase as new devices are added, so the first device added has the lowest SDL_AudioDeviceID value.)
895 FindLowestDeviceIDData data = { recording, highest, NULL };
896 SDL_LockRWLockForReading(current_audio.device_hash_lock);
897 SDL_IterateHashTable(current_audio.device_hash, FindLowestDeviceID, &data);
898 SDL_UnlockRWLock(current_audio.device_hash_lock);
899 return data.result;
900}
901
902static Uint32 SDLCALL HashAudioDeviceID(void *userdata, const void *key)
903{
904 // shift right 2, to dump the first two bits, since these are flags
905 // (recording vs playback, logical vs physical) and the rest are unique incrementing integers.
906 return ((Uint32) ((uintptr_t) key)) >> 2;
907}
908
909// !!! FIXME: the video subsystem does SDL_VideoInit, not SDL_InitVideo. Make this match.
910bool SDL_InitAudio(const char *driver_name)
911{
912 if (SDL_GetCurrentAudioDriver()) {
913 SDL_QuitAudio(); // shutdown driver if already running.
914 }
915
916 // make sure device IDs start at 2 (because of SDL2 legacy interface), but don't reset the counter on each init, in case the app is holding an old device ID somewhere.
917 SDL_CompareAndSwapAtomicInt(&last_device_instance_id, 0, 2);
918
919 SDL_ChooseAudioConverters();
920 SDL_SetupAudioResampler();
921
922 SDL_RWLock *device_hash_lock = SDL_CreateRWLock(); // create this early, so if it fails we don't have to tear down the whole audio subsystem.
923 if (!device_hash_lock) {
924 return false;
925 }
926
927 SDL_HashTable *device_hash = SDL_CreateHashTable(0, false, HashAudioDeviceID, SDL_KeyMatchID, NULL, NULL);
928 if (!device_hash) {
929 SDL_DestroyRWLock(device_hash_lock);
930 return false;
931 }
932
933 // Select the proper audio driver
934 if (!driver_name) {
935 driver_name = SDL_GetHint(SDL_HINT_AUDIO_DRIVER);
936 }
937
938 bool initialized = false;
939 bool tried_to_init = false;
940
941 if (driver_name && *driver_name != 0) {
942 char *driver_name_copy = SDL_strdup(driver_name);
943 const char *driver_attempt = driver_name_copy;
944
945 if (!driver_name_copy) {
946 SDL_DestroyRWLock(device_hash_lock);
947 SDL_DestroyHashTable(device_hash);
948 return false;
949 }
950
951 while (driver_attempt && *driver_attempt != 0 && !initialized) {
952 char *driver_attempt_end = SDL_strchr(driver_attempt, ',');
953 if (driver_attempt_end) {
954 *driver_attempt_end = '\0';
955 }
956
957 // SDL 1.2 uses the name "dsound", so we'll support both.
958 if (SDL_strcmp(driver_attempt, "dsound") == 0) {
959 driver_attempt = "directsound";
960 } else if (SDL_strcmp(driver_attempt, "pulse") == 0) { // likewise, "pulse" was renamed to "pulseaudio"
961 driver_attempt = "pulseaudio";
962 }
963
964 for (int i = 0; bootstrap[i]; ++i) {
965 if (!bootstrap[i]->is_preferred && SDL_strcasecmp(bootstrap[i]->name, driver_attempt) == 0) {
966 tried_to_init = true;
967 SDL_zero(current_audio);
968 current_audio.pending_events_tail = &current_audio.pending_events;
969 current_audio.device_hash_lock = device_hash_lock;
970 current_audio.device_hash = device_hash;
971 if (bootstrap[i]->init(&current_audio.impl)) {
972 current_audio.name = bootstrap[i]->name;
973 current_audio.desc = bootstrap[i]->desc;
974 initialized = true;
975 break;
976 }
977 }
978 }
979
980 driver_attempt = (driver_attempt_end) ? (driver_attempt_end + 1) : NULL;
981 }
982
983 SDL_free(driver_name_copy);
984 } else {
985 for (int i = 0; (!initialized) && (bootstrap[i]); ++i) {
986 if (bootstrap[i]->demand_only) {
987 continue;
988 }
989
990 tried_to_init = true;
991 SDL_zero(current_audio);
992 current_audio.pending_events_tail = &current_audio.pending_events;
993 current_audio.device_hash_lock = device_hash_lock;
994 current_audio.device_hash = device_hash;
995 if (bootstrap[i]->init(&current_audio.impl)) {
996 current_audio.name = bootstrap[i]->name;
997 current_audio.desc = bootstrap[i]->desc;
998 initialized = true;
999 }
1000 }
1001 }
1002
1003 if (!initialized) {
1004 // specific drivers will set the error message if they fail, but otherwise we do it here.
1005 if (!tried_to_init) {
1006 if (driver_name) {
1007 SDL_SetError("Audio target '%s' not available", driver_name);
1008 } else {
1009 SDL_SetError("No available audio device");
1010 }
1011 }
1012
1013 SDL_DestroyRWLock(device_hash_lock);
1014 SDL_DestroyHashTable(device_hash);
1015 SDL_zero(current_audio);
1016 return false; // No driver was available, so fail.
1017 }
1018
1019 CompleteAudioEntryPoints();
1020
1021 // Make sure we have a list of devices available at startup...
1022 SDL_AudioDevice *default_playback = NULL;
1023 SDL_AudioDevice *default_recording = NULL;
1024 current_audio.impl.DetectDevices(&default_playback, &default_recording);
1025
1026 // If no default was _ever_ specified, just take the first device we see, if any.
1027 if (!default_playback) {
1028 default_playback = GetFirstAddedAudioDevice(/*recording=*/false);
1029 }
1030
1031 if (!default_recording) {
1032 default_recording = GetFirstAddedAudioDevice(/*recording=*/true);
1033 }
1034
1035 if (default_playback) {
1036 current_audio.default_playback_device_id = default_playback->instance_id;
1037 RefPhysicalAudioDevice(default_playback); // extra ref on default devices.
1038 }
1039
1040 if (default_recording) {
1041 current_audio.default_recording_device_id = default_recording->instance_id;
1042 RefPhysicalAudioDevice(default_recording); // extra ref on default devices.
1043 }
1044
1045 return true;
1046}
1047
1048static bool SDLCALL DestroyOnePhysicalAudioDevice(void *userdata, const SDL_HashTable *table, const void *key, const void *value)
1049{
1050 // bit #1 of devid is set for physical devices and unset for logical.
1051 const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key;
1052 const bool isphysical = !!(devid & (1<<1));
1053 if (isphysical) {
1054 DestroyPhysicalAudioDevice((SDL_AudioDevice *) value);
1055 }
1056 return true; // keep iterating.
1057}
1058
1059void SDL_QuitAudio(void)
1060{
1061 if (!current_audio.name) { // not initialized?!
1062 return;
1063 }
1064
1065 current_audio.impl.DeinitializeStart();
1066
1067 // Destroy any audio streams that still exist...
1068 while (current_audio.existing_streams) {
1069 SDL_DestroyAudioStream(current_audio.existing_streams);
1070 }
1071
1072 SDL_LockRWLockForWriting(current_audio.device_hash_lock);
1073 SDL_SetAtomicInt(&current_audio.shutting_down, 1);
1074 SDL_HashTable *device_hash = current_audio.device_hash;
1075 current_audio.device_hash = NULL;
1076 SDL_PendingAudioDeviceEvent *pending_events = current_audio.pending_events.next;
1077 current_audio.pending_events.next = NULL;
1078 SDL_SetAtomicInt(&current_audio.playback_device_count, 0);
1079 SDL_SetAtomicInt(&current_audio.recording_device_count, 0);
1080 SDL_UnlockRWLock(current_audio.device_hash_lock);
1081
1082 SDL_PendingAudioDeviceEvent *pending_next = NULL;
1083 for (SDL_PendingAudioDeviceEvent *i = pending_events; i; i = pending_next) {
1084 pending_next = i->next;
1085 SDL_free(i);
1086 }
1087
1088 SDL_IterateHashTable(device_hash, DestroyOnePhysicalAudioDevice, NULL);
1089
1090 // Free the driver data
1091 current_audio.impl.Deinitialize();
1092
1093 SDL_DestroyRWLock(current_audio.device_hash_lock);
1094 SDL_DestroyHashTable(device_hash);
1095
1096 SDL_zero(current_audio);
1097}
1098
1099
1100void SDL_AudioThreadFinalize(SDL_AudioDevice *device)
1101{
1102}
1103
1104static void MixFloat32Audio(float *dst, const float *src, const int buffer_size)
1105{
1106 if (!SDL_MixAudio((Uint8 *) dst, (const Uint8 *) src, SDL_AUDIO_F32, buffer_size, 1.0f)) {
1107 SDL_assert(!"This shouldn't happen.");
1108 }
1109}
1110
1111
1112// Playback device thread. This is split into chunks, so backends that need to control this directly can use the pieces they need without duplicating effort.
1113
1114void SDL_PlaybackAudioThreadSetup(SDL_AudioDevice *device)
1115{
1116 SDL_assert(!device->recording);
1117 current_audio.impl.ThreadInit(device);
1118}
1119
1120bool SDL_PlaybackAudioThreadIterate(SDL_AudioDevice *device)
1121{
1122 SDL_assert(!device->recording);
1123
1124 SDL_LockMutex(device->lock);
1125
1126 if (SDL_GetAtomicInt(&device->shutdown)) {
1127 SDL_UnlockMutex(device->lock);
1128 return false; // we're done, shut it down.
1129 }
1130
1131 bool failed = false;
1132 int buffer_size = device->buffer_size;
1133 Uint8 *device_buffer = device->GetDeviceBuf(device, &buffer_size);
1134 if (buffer_size == 0) {
1135 // WASAPI (maybe others, later) does this to say "just abandon this iteration and try again next time."
1136 } else if (!device_buffer) {
1137 failed = true;
1138 } else {
1139 SDL_assert(buffer_size <= device->buffer_size); // you can ask for less, but not more.
1140 SDL_assert(AudioDeviceCanUseSimpleCopy(device) == device->simple_copy); // make sure this hasn't gotten out of sync.
1141
1142 // can we do a basic copy without silencing/mixing the buffer? This is an extremely likely scenario, so we special-case it.
1143 if (device->simple_copy) {
1144 SDL_LogicalAudioDevice *logdev = device->logical_devices;
1145 SDL_AudioStream *stream = logdev->bound_streams;
1146
1147 // We should have updated this elsewhere if the format changed!
1148 SDL_assert(SDL_AudioSpecsEqual(&stream->dst_spec, &device->spec, NULL, NULL));
1149
1150 const int br = SDL_GetAtomicInt(&logdev->paused) ? 0 : SDL_GetAudioStreamDataAdjustGain(stream, device_buffer, buffer_size, logdev->gain);
1151 if (br < 0) { // Probably OOM. Kill the audio device; the whole thing is likely dying soon anyhow.
1152 failed = true;
1153 SDL_memset(device_buffer, device->silence_value, buffer_size); // just supply silence to the device before we die.
1154 } else if (br < buffer_size) {
1155 SDL_memset(device_buffer + br, device->silence_value, buffer_size - br); // silence whatever we didn't write to.
1156 }
1157
1158 // generally channel maps will line up, but if the audio stream's chmap has been explicitly changed, do a final swizzle to device layout.
1159 if ((br > 0) && (!SDL_AudioChannelMapsEqual(device->spec.channels, stream->dst_chmap, device->chmap))) {
1160 ConvertAudio(br / SDL_AUDIO_FRAMESIZE(device->spec), device_buffer, device->spec.format, device->spec.channels, NULL,
1161 device_buffer, device->spec.format, device->spec.channels, device->chmap, NULL, 1.0f);
1162 }
1163 } else { // need to actually mix (or silence the buffer)
1164 float *final_mix_buffer = (float *) ((device->spec.format == SDL_AUDIO_F32) ? device_buffer : device->mix_buffer);
1165 const int needed_samples = buffer_size / SDL_AUDIO_BYTESIZE(device->spec.format);
1166 const int work_buffer_size = needed_samples * sizeof (float);
1167 SDL_AudioSpec outspec;
1168
1169 SDL_assert(work_buffer_size <= device->work_buffer_size);
1170
1171 SDL_copyp(&outspec, &device->spec);
1172 outspec.format = SDL_AUDIO_F32;
1173
1174 SDL_memset(final_mix_buffer, '\0', work_buffer_size); // start with silence.
1175
1176 for (SDL_LogicalAudioDevice *logdev = device->logical_devices; logdev; logdev = logdev->next) {
1177 if (SDL_GetAtomicInt(&logdev->paused)) {
1178 continue; // paused? Skip this logical device.
1179 }
1180
1181 const SDL_AudioPostmixCallback postmix = logdev->postmix;
1182 float *mix_buffer = final_mix_buffer;
1183 if (postmix) {
1184 mix_buffer = device->postmix_buffer;
1185 SDL_memset(mix_buffer, '\0', work_buffer_size); // start with silence.
1186 }
1187
1188 for (SDL_AudioStream *stream = logdev->bound_streams; stream; stream = stream->next_binding) {
1189 // We should have updated this elsewhere if the format changed!
1190 SDL_assert(SDL_AudioSpecsEqual(&stream->dst_spec, &outspec, NULL, NULL));
1191
1192 /* this will hold a lock on `stream` while getting. We don't explicitly lock the streams
1193 for iterating here because the binding linked list can only change while the device lock is held.
1194 (we _do_ lock the stream during binding/unbinding to make sure that two threads can't try to bind
1195 the same stream to different devices at the same time, though.) */
1196 const int br = SDL_GetAudioStreamDataAdjustGain(stream, device->work_buffer, work_buffer_size, logdev->gain);
1197 if (br < 0) { // Probably OOM. Kill the audio device; the whole thing is likely dying soon anyhow.
1198 failed = true;
1199 break;
1200 } else if (br > 0) { // it's okay if we get less than requested, we mix what we have.
1201 // generally channel maps will line up, but if the audio stream's chmap has been explicitly changed, do a final swizzle to device layout.
1202 if (!SDL_AudioChannelMapsEqual(device->spec.channels, stream->dst_chmap, device->chmap)) {
1203 ConvertAudio(br / SDL_AUDIO_FRAMESIZE(device->spec), device->work_buffer, device->spec.format, device->spec.channels, NULL,
1204 device->work_buffer, device->spec.format, device->spec.channels, device->chmap, NULL, 1.0f);
1205 }
1206 MixFloat32Audio(mix_buffer, (float *) device->work_buffer, br);
1207 }
1208 }
1209
1210 if (postmix) {
1211 SDL_assert(mix_buffer == device->postmix_buffer);
1212 postmix(logdev->postmix_userdata, &outspec, mix_buffer, work_buffer_size);
1213 MixFloat32Audio(final_mix_buffer, mix_buffer, work_buffer_size);
1214 }
1215 }
1216
1217 if (((Uint8 *) final_mix_buffer) != device_buffer) {
1218 // !!! FIXME: we can't promise the device buf is aligned/padded for SIMD.
1219 //ConvertAudio(needed_samples / device->spec.channels, final_mix_buffer, SDL_AUDIO_F32, device->spec.channels, NULL, device_buffer, device->spec.format, device->spec.channels, NULL, NULL, 1.0f);
1220 ConvertAudio(needed_samples / device->spec.channels, final_mix_buffer, SDL_AUDIO_F32, device->spec.channels, NULL, device->work_buffer, device->spec.format, device->spec.channels, NULL, NULL, 1.0f);
1221 SDL_memcpy(device_buffer, device->work_buffer, buffer_size);
1222 }
1223 }
1224
1225 // PlayDevice SHOULD NOT BLOCK, as we are holding a lock right now. Block in WaitDevice instead!
1226 if (!device->PlayDevice(device, device_buffer, buffer_size)) {
1227 failed = true;
1228 }
1229 }
1230
1231 SDL_UnlockMutex(device->lock);
1232
1233 if (failed) {
1234 SDL_AudioDeviceDisconnected(device); // doh.
1235 }
1236
1237 return true; // always go on if not shutting down, even if device failed.
1238}
1239
1240void SDL_PlaybackAudioThreadShutdown(SDL_AudioDevice *device)
1241{
1242 SDL_assert(!device->recording);
1243 const int frames = device->buffer_size / SDL_AUDIO_FRAMESIZE(device->spec);
1244 // Wait for the audio to drain if device didn't die.
1245 if (!SDL_GetAtomicInt(&device->zombie)) {
1246 SDL_Delay(((frames * 1000) / device->spec.freq) * 2);
1247 }
1248 current_audio.impl.ThreadDeinit(device);
1249 SDL_AudioThreadFinalize(device);
1250}
1251
1252static int SDLCALL PlaybackAudioThread(void *devicep) // thread entry point
1253{
1254 SDL_AudioDevice *device = (SDL_AudioDevice *)devicep;
1255 SDL_assert(device != NULL);
1256 SDL_assert(!device->recording);
1257 SDL_PlaybackAudioThreadSetup(device);
1258
1259 do {
1260 if (!device->WaitDevice(device)) {
1261 SDL_AudioDeviceDisconnected(device); // doh. (but don't break out of the loop, just be a zombie for now!)
1262 }
1263 } while (SDL_PlaybackAudioThreadIterate(device));
1264
1265 SDL_PlaybackAudioThreadShutdown(device);
1266 return 0;
1267}
1268
1269
1270
1271// Recording device thread. This is split into chunks, so backends that need to control this directly can use the pieces they need without duplicating effort.
1272
1273void SDL_RecordingAudioThreadSetup(SDL_AudioDevice *device)
1274{
1275 SDL_assert(device->recording);
1276 current_audio.impl.ThreadInit(device);
1277}
1278
1279bool SDL_RecordingAudioThreadIterate(SDL_AudioDevice *device)
1280{
1281 SDL_assert(device->recording);
1282
1283 SDL_LockMutex(device->lock);
1284
1285 if (SDL_GetAtomicInt(&device->shutdown)) {
1286 SDL_UnlockMutex(device->lock);
1287 return false; // we're done, shut it down.
1288 }
1289
1290 bool failed = false;
1291
1292 if (!device->logical_devices) {
1293 device->FlushRecording(device); // nothing wants data, dump anything pending.
1294 } else {
1295 // this SHOULD NOT BLOCK, as we are holding a lock right now. Block in WaitRecordingDevice!
1296 int br = device->RecordDevice(device, device->work_buffer, device->buffer_size);
1297 if (br < 0) { // uhoh, device failed for some reason!
1298 failed = true;
1299 } else if (br > 0) { // queue the new data to each bound stream.
1300 for (SDL_LogicalAudioDevice *logdev = device->logical_devices; logdev; logdev = logdev->next) {
1301 if (SDL_GetAtomicInt(&logdev->paused)) {
1302 continue; // paused? Skip this logical device.
1303 }
1304
1305 void *output_buffer = device->work_buffer;
1306
1307 // I don't know why someone would want a postmix on a recording device, but we offer it for API consistency.
1308 if (logdev->postmix || (logdev->gain != 1.0f)) {
1309 // move to float format.
1310 SDL_AudioSpec outspec;
1311 SDL_copyp(&outspec, &device->spec);
1312 outspec.format = SDL_AUDIO_F32;
1313 output_buffer = device->postmix_buffer;
1314 const int frames = br / SDL_AUDIO_FRAMESIZE(device->spec);
1315 br = frames * SDL_AUDIO_FRAMESIZE(outspec);
1316 ConvertAudio(frames, device->work_buffer, device->spec.format, outspec.channels, NULL, device->postmix_buffer, SDL_AUDIO_F32, outspec.channels, NULL, NULL, logdev->gain);
1317 if (logdev->postmix) {
1318 logdev->postmix(logdev->postmix_userdata, &outspec, device->postmix_buffer, br);
1319 }
1320 }
1321
1322 for (SDL_AudioStream *stream = logdev->bound_streams; stream; stream = stream->next_binding) {
1323 // We should have updated this elsewhere if the format changed!
1324 SDL_assert(stream->src_spec.format == ((logdev->postmix || (logdev->gain != 1.0f)) ? SDL_AUDIO_F32 : device->spec.format));
1325 SDL_assert(stream->src_spec.channels == device->spec.channels);
1326 SDL_assert(stream->src_spec.freq == device->spec.freq);
1327
1328 void *final_buf = output_buffer;
1329
1330 // generally channel maps will line up, but if the audio stream's chmap has been explicitly changed, do a final swizzle to stream layout.
1331 if (!SDL_AudioChannelMapsEqual(device->spec.channels, stream->src_chmap, device->chmap)) {
1332 final_buf = device->mix_buffer; // this is otherwise unused on recording devices, so it makes convenient scratch space here.
1333 ConvertAudio(br / SDL_AUDIO_FRAMESIZE(device->spec), output_buffer, device->spec.format, device->spec.channels, NULL,
1334 final_buf, device->spec.format, device->spec.channels, stream->src_chmap, NULL, 1.0f);
1335 }
1336
1337 /* this will hold a lock on `stream` while putting. We don't explicitly lock the streams
1338 for iterating here because the binding linked list can only change while the device lock is held.
1339 (we _do_ lock the stream during binding/unbinding to make sure that two threads can't try to bind
1340 the same stream to different devices at the same time, though.) */
1341 if (!SDL_PutAudioStreamData(stream, final_buf, br)) {
1342 // oh crud, we probably ran out of memory. This is possibly an overreaction to kill the audio device, but it's likely the whole thing is going down in a moment anyhow.
1343 failed = true;
1344 break;
1345 }
1346 }
1347 }
1348 }
1349 }
1350
1351 SDL_UnlockMutex(device->lock);
1352
1353 if (failed) {
1354 SDL_AudioDeviceDisconnected(device); // doh.
1355 }
1356
1357 return true; // always go on if not shutting down, even if device failed.
1358}
1359
1360void SDL_RecordingAudioThreadShutdown(SDL_AudioDevice *device)
1361{
1362 SDL_assert(device->recording);
1363 device->FlushRecording(device);
1364 current_audio.impl.ThreadDeinit(device);
1365 SDL_AudioThreadFinalize(device);
1366}
1367
1368static int SDLCALL RecordingAudioThread(void *devicep) // thread entry point
1369{
1370 SDL_AudioDevice *device = (SDL_AudioDevice *)devicep;
1371 SDL_assert(device != NULL);
1372 SDL_assert(device->recording);
1373 SDL_RecordingAudioThreadSetup(device);
1374
1375 do {
1376 if (!device->WaitRecordingDevice(device)) {
1377 SDL_AudioDeviceDisconnected(device); // doh. (but don't break out of the loop, just be a zombie for now!)
1378 }
1379 } while (SDL_RecordingAudioThreadIterate(device));
1380
1381 SDL_RecordingAudioThreadShutdown(device);
1382 return 0;
1383}
1384
1385typedef struct CountAudioDevicesData
1386{
1387 int devs_seen;
1388 const int num_devices;
1389 SDL_AudioDeviceID *result;
1390 const bool recording;
1391} CountAudioDevicesData;
1392
1393static bool SDLCALL CountAudioDevices(void *userdata, const SDL_HashTable *table, const void *key, const void *value)
1394{
1395 CountAudioDevicesData *data = (CountAudioDevicesData *) userdata;
1396 const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key;
1397 // bit #0 of devid is set for playback devices and unset for recording.
1398 // bit #1 of devid is set for physical devices and unset for logical.
1399 const bool devid_recording = !(devid & (1<<0));
1400 const bool isphysical = !!(devid & (1<<1));
1401 if (isphysical && (devid_recording == data->recording)) {
1402 SDL_assert(data->devs_seen < data->num_devices);
1403 data->result[data->devs_seen++] = devid;
1404 }
1405 return true; // keep iterating.
1406}
1407
1408static SDL_AudioDeviceID *GetAudioDevices(int *count, bool recording)
1409{
1410 SDL_AudioDeviceID *result = NULL;
1411 int num_devices = 0;
1412
1413 if (SDL_GetCurrentAudioDriver()) {
1414 SDL_LockRWLockForReading(current_audio.device_hash_lock);
1415 {
1416 num_devices = SDL_GetAtomicInt(recording ? &current_audio.recording_device_count : &current_audio.playback_device_count);
1417 result = (SDL_AudioDeviceID *) SDL_malloc((num_devices + 1) * sizeof (SDL_AudioDeviceID));
1418 if (result) {
1419 CountAudioDevicesData data = { 0, num_devices, result, recording };
1420 SDL_IterateHashTable(current_audio.device_hash, CountAudioDevices, &data);
1421 SDL_assert(data.devs_seen == num_devices);
1422 result[data.devs_seen] = 0; // null-terminated.
1423 }
1424 }
1425 SDL_UnlockRWLock(current_audio.device_hash_lock);
1426 } else {
1427 SDL_SetError("Audio subsystem is not initialized");
1428 }
1429
1430 if (count) {
1431 if (result) {
1432 *count = num_devices;
1433 } else {
1434 *count = 0;
1435 }
1436 }
1437 return result;
1438}
1439
1440SDL_AudioDeviceID *SDL_GetAudioPlaybackDevices(int *count)
1441{
1442 return GetAudioDevices(count, false);
1443}
1444
1445SDL_AudioDeviceID *SDL_GetAudioRecordingDevices(int *count)
1446{
1447 return GetAudioDevices(count, true);
1448}
1449
1450typedef struct FindAudioDeviceByCallbackData
1451{
1452 bool (*callback)(SDL_AudioDevice *device, void *userdata);
1453 void *userdata;
1454 SDL_AudioDevice *retval;
1455} FindAudioDeviceByCallbackData;
1456
1457static bool SDLCALL FindAudioDeviceByCallback(void *userdata, const SDL_HashTable *table, const void *key, const void *value)
1458{
1459 FindAudioDeviceByCallbackData *data = (FindAudioDeviceByCallbackData *) userdata;
1460 const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key;
1461 // bit #1 of devid is set for physical devices and unset for logical.
1462 const bool isphysical = !!(devid & (1<<1));
1463 if (isphysical) {
1464 SDL_AudioDevice *device = (SDL_AudioDevice *) value;
1465 if (data->callback(device, data->userdata)) { // found it?
1466 data->retval = device;
1467 return false; // stop iterating, we found it.
1468 }
1469 }
1470 return true; // keep iterating.
1471}
1472
1473// !!! FIXME: SDL convention is for userdata to come first in the callback's params. Fix this at some point.
1474SDL_AudioDevice *SDL_FindPhysicalAudioDeviceByCallback(bool (*callback)(SDL_AudioDevice *device, void *userdata), void *userdata)
1475{
1476 if (!SDL_GetCurrentAudioDriver()) {
1477 SDL_SetError("Audio subsystem is not initialized");
1478 return NULL;
1479 }
1480
1481 FindAudioDeviceByCallbackData data = { callback, userdata, NULL };
1482 SDL_LockRWLockForReading(current_audio.device_hash_lock);
1483 SDL_IterateHashTable(current_audio.device_hash, FindAudioDeviceByCallback, &data);
1484 SDL_UnlockRWLock(current_audio.device_hash_lock);
1485
1486 if (!data.retval) {
1487 SDL_SetError("Device not found");
1488 }
1489
1490 return data.retval;
1491}
1492
1493static bool TestDeviceHandleCallback(SDL_AudioDevice *device, void *handle)
1494{
1495 return device->handle == handle;
1496}
1497
1498SDL_AudioDevice *SDL_FindPhysicalAudioDeviceByHandle(void *handle)
1499{
1500 return SDL_FindPhysicalAudioDeviceByCallback(TestDeviceHandleCallback, handle);
1501}
1502
1503const char *SDL_GetAudioDeviceName(SDL_AudioDeviceID devid)
1504{
1505 const char *result = NULL;
1506 SDL_AudioDevice *device = ObtainPhysicalAudioDevice(devid);
1507 if (device) {
1508 result = SDL_GetPersistentString(device->name);
1509 }
1510 ReleaseAudioDevice(device);
1511
1512 return result;
1513}
1514
1515bool SDL_GetAudioDeviceFormat(SDL_AudioDeviceID devid, SDL_AudioSpec *spec, int *sample_frames)
1516{
1517 if (!spec) {
1518 return SDL_InvalidParamError("spec");
1519 }
1520
1521 bool result = false;
1522 SDL_AudioDevice *device = ObtainPhysicalAudioDeviceDefaultAllowed(devid);
1523 if (device) {
1524 SDL_copyp(spec, &device->spec);
1525 if (sample_frames) {
1526 *sample_frames = device->sample_frames;
1527 }
1528 result = true;
1529 }
1530 ReleaseAudioDevice(device);
1531
1532 return result;
1533}
1534
1535int *SDL_GetAudioDeviceChannelMap(SDL_AudioDeviceID devid, int *count)
1536{
1537 int *result = NULL;
1538 int channels = 0;
1539 SDL_AudioDevice *device = ObtainPhysicalAudioDeviceDefaultAllowed(devid);
1540 if (device) {
1541 channels = device->spec.channels;
1542 result = SDL_ChannelMapDup(device->chmap, channels);
1543 }
1544 ReleaseAudioDevice(device);
1545
1546 if (count) {
1547 *count = channels;
1548 }
1549
1550 return result;
1551}
1552
1553
1554// this is awkward, but this makes sure we can release the device lock
1555// so the device thread can terminate but also not have two things
1556// race to close or open the device while the lock is unprotected.
1557// you hold the lock when calling this, it will release the lock and
1558// wait while the shutdown flag is set.
1559// BE CAREFUL WITH THIS.
1560static void SerializePhysicalDeviceClose(SDL_AudioDevice *device)
1561{
1562 while (SDL_GetAtomicInt(&device->shutdown)) {
1563 SDL_WaitCondition(device->close_cond, device->lock);
1564 }
1565}
1566
1567// this expects the device lock to be held.
1568static void ClosePhysicalAudioDevice(SDL_AudioDevice *device)
1569{
1570 SerializePhysicalDeviceClose(device);
1571
1572 SDL_SetAtomicInt(&device->shutdown, 1);
1573
1574 // YOU MUST PROTECT KEY POINTS WITH SerializePhysicalDeviceClose() WHILE THE THREAD JOINS
1575 SDL_UnlockMutex(device->lock);
1576
1577 if (device->thread) {
1578 SDL_WaitThread(device->thread, NULL);
1579 device->thread = NULL;
1580 }
1581
1582 if (device->currently_opened) {
1583 current_audio.impl.CloseDevice(device); // if ProvidesOwnCallbackThread, this must join on any existing device thread before returning!
1584 device->currently_opened = false;
1585 device->hidden = NULL; // just in case.
1586 }
1587
1588 SDL_LockMutex(device->lock);
1589 SDL_SetAtomicInt(&device->shutdown, 0); // ready to go again.
1590 SDL_BroadcastCondition(device->close_cond); // release anyone waiting in SerializePhysicalDeviceClose; they'll still block until we release device->lock, though.
1591
1592 SDL_aligned_free(device->work_buffer);
1593 device->work_buffer = NULL;
1594
1595 SDL_aligned_free(device->mix_buffer);
1596 device->mix_buffer = NULL;
1597
1598 SDL_aligned_free(device->postmix_buffer);
1599 device->postmix_buffer = NULL;
1600
1601 SDL_copyp(&device->spec, &device->default_spec);
1602 device->sample_frames = 0;
1603 device->silence_value = SDL_GetSilenceValueForFormat(device->spec.format);
1604}
1605
1606void SDL_CloseAudioDevice(SDL_AudioDeviceID devid)
1607{
1608 SDL_AudioDevice *device = NULL;
1609 SDL_LogicalAudioDevice *logdev = ObtainLogicalAudioDevice(devid, &device);
1610 if (logdev) {
1611 DestroyLogicalAudioDevice(logdev);
1612 }
1613
1614 if (device) {
1615 if (!device->logical_devices) { // no more logical devices? Close the physical device, too.
1616 ClosePhysicalAudioDevice(device);
1617 }
1618 UnrefPhysicalAudioDevice(device); // one reference for each logical device.
1619 }
1620
1621 ReleaseAudioDevice(device);
1622}
1623
1624
1625static SDL_AudioFormat ParseAudioFormatString(const char *string)
1626{
1627 if (string) {
1628 #define CHECK_FMT_STRING(x) if (SDL_strcmp(string, #x) == 0) { return SDL_AUDIO_##x; }
1629 CHECK_FMT_STRING(U8);
1630 CHECK_FMT_STRING(S8);
1631 CHECK_FMT_STRING(S16LE);
1632 CHECK_FMT_STRING(S16BE);
1633 CHECK_FMT_STRING(S16);
1634 CHECK_FMT_STRING(S32LE);
1635 CHECK_FMT_STRING(S32BE);
1636 CHECK_FMT_STRING(S32);
1637 CHECK_FMT_STRING(F32LE);
1638 CHECK_FMT_STRING(F32BE);
1639 CHECK_FMT_STRING(F32);
1640 #undef CHECK_FMT_STRING
1641 }
1642 return SDL_AUDIO_UNKNOWN;
1643}
1644
1645static void PrepareAudioFormat(bool recording, SDL_AudioSpec *spec)
1646{
1647 if (spec->freq == 0) {
1648 spec->freq = recording ? DEFAULT_AUDIO_RECORDING_FREQUENCY : DEFAULT_AUDIO_PLAYBACK_FREQUENCY;
1649
1650 const char *hint = SDL_GetHint(SDL_HINT_AUDIO_FREQUENCY);
1651 if (hint) {
1652 const int val = SDL_atoi(hint);
1653 if (val > 0) {
1654 spec->freq = val;
1655 }
1656 }
1657 }
1658
1659 if (spec->channels == 0) {
1660 spec->channels = recording ? DEFAULT_AUDIO_RECORDING_CHANNELS : DEFAULT_AUDIO_PLAYBACK_CHANNELS;
1661
1662 const char *hint = SDL_GetHint(SDL_HINT_AUDIO_CHANNELS);
1663 if (hint) {
1664 const int val = SDL_atoi(hint);
1665 if (val > 0) {
1666 spec->channels = val;
1667 }
1668 }
1669 }
1670
1671 if (spec->format == 0) {
1672 const SDL_AudioFormat val = ParseAudioFormatString(SDL_GetHint(SDL_HINT_AUDIO_FORMAT));
1673 spec->format = (val != SDL_AUDIO_UNKNOWN) ? val : (recording ? DEFAULT_AUDIO_RECORDING_FORMAT : DEFAULT_AUDIO_PLAYBACK_FORMAT);
1674 }
1675}
1676
1677void SDL_UpdatedAudioDeviceFormat(SDL_AudioDevice *device)
1678{
1679 device->silence_value = SDL_GetSilenceValueForFormat(device->spec.format);
1680 device->buffer_size = device->sample_frames * SDL_AUDIO_FRAMESIZE(device->spec);
1681 device->work_buffer_size = device->sample_frames * sizeof (float) * device->spec.channels;
1682 device->work_buffer_size = SDL_max(device->buffer_size, device->work_buffer_size); // just in case we end up with a 64-bit audio format at some point.
1683}
1684
1685char *SDL_GetAudioThreadName(SDL_AudioDevice *device, char *buf, size_t buflen)
1686{
1687 (void)SDL_snprintf(buf, buflen, "SDLAudio%c%d", (device->recording) ? 'C' : 'P', (int) device->instance_id);
1688 return buf;
1689}
1690
1691
1692// this expects the device lock to be held.
1693static bool OpenPhysicalAudioDevice(SDL_AudioDevice *device, const SDL_AudioSpec *inspec)
1694{
1695 SerializePhysicalDeviceClose(device); // make sure another thread that's closing didn't release the lock to let the device thread join...
1696
1697 if (device->currently_opened) {
1698 return true; // we're already good.
1699 }
1700
1701 // Just pretend to open a zombie device. It can still collect logical devices on a default device under the assumption they will all migrate when the default device is officially changed.
1702 if (SDL_GetAtomicInt(&device->zombie)) {
1703 return true; // Braaaaaaaaains.
1704 }
1705
1706 // These start with the backend's implementation, but we might swap them out with zombie versions later.
1707 device->WaitDevice = current_audio.impl.WaitDevice;
1708 device->PlayDevice = current_audio.impl.PlayDevice;
1709 device->GetDeviceBuf = current_audio.impl.GetDeviceBuf;
1710 device->WaitRecordingDevice = current_audio.impl.WaitRecordingDevice;
1711 device->RecordDevice = current_audio.impl.RecordDevice;
1712 device->FlushRecording = current_audio.impl.FlushRecording;
1713
1714 SDL_AudioSpec spec;
1715 SDL_copyp(&spec, inspec ? inspec : &device->default_spec);
1716 PrepareAudioFormat(device->recording, &spec);
1717
1718 /* We allow the device format to change if it's better than the current settings (by various definitions of "better"). This prevents
1719 something low quality, like an old game using S8/8000Hz audio, from ruining a music thing playing at CD quality that tries to open later.
1720 (or some VoIP library that opens for mono output ruining your surround-sound game because it got there first).
1721 These are just requests! The backend may change any of these values during OpenDevice method! */
1722 device->spec.format = (SDL_AUDIO_BITSIZE(device->default_spec.format) >= SDL_AUDIO_BITSIZE(spec.format)) ? device->default_spec.format : spec.format;
1723 device->spec.freq = SDL_max(device->default_spec.freq, spec.freq);
1724 device->spec.channels = SDL_max(device->default_spec.channels, spec.channels);
1725 device->sample_frames = SDL_GetDefaultSampleFramesFromFreq(device->spec.freq);
1726 SDL_UpdatedAudioDeviceFormat(device); // start this off sane.
1727
1728 device->currently_opened = true; // mark this true even if impl.OpenDevice fails, so we know to clean up.
1729 if (!current_audio.impl.OpenDevice(device)) {
1730 ClosePhysicalAudioDevice(device); // clean up anything the backend left half-initialized.
1731 return false;
1732 }
1733
1734 SDL_UpdatedAudioDeviceFormat(device); // in case the backend changed things and forgot to call this.
1735
1736 // Allocate a scratch audio buffer
1737 device->work_buffer = (Uint8 *)SDL_aligned_alloc(SDL_GetSIMDAlignment(), device->work_buffer_size);
1738 if (!device->work_buffer) {
1739 ClosePhysicalAudioDevice(device);
1740 return false;
1741 }
1742
1743 if (device->spec.format != SDL_AUDIO_F32) {
1744 device->mix_buffer = (Uint8 *)SDL_aligned_alloc(SDL_GetSIMDAlignment(), device->work_buffer_size);
1745 if (!device->mix_buffer) {
1746 ClosePhysicalAudioDevice(device);
1747 return false;
1748 }
1749 }
1750
1751 // Start the audio thread if necessary
1752 if (!current_audio.impl.ProvidesOwnCallbackThread) {
1753 char threadname[64];
1754 SDL_GetAudioThreadName(device, threadname, sizeof (threadname));
1755 device->thread = SDL_CreateThread(device->recording ? RecordingAudioThread : PlaybackAudioThread, threadname, device);
1756
1757 if (!device->thread) {
1758 ClosePhysicalAudioDevice(device);
1759 return SDL_SetError("Couldn't create audio thread");
1760 }
1761 }
1762
1763 return true;
1764}
1765
1766SDL_AudioDeviceID SDL_OpenAudioDevice(SDL_AudioDeviceID devid, const SDL_AudioSpec *spec)
1767{
1768 if (!SDL_GetCurrentAudioDriver()) {
1769 SDL_SetError("Audio subsystem is not initialized");
1770 return 0;
1771 }
1772
1773 bool wants_default = ((devid == SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK) || (devid == SDL_AUDIO_DEVICE_DEFAULT_RECORDING));
1774
1775 // this will let you use a logical device to make a new logical device on the parent physical device. Could be useful?
1776 SDL_AudioDevice *device = NULL;
1777 const bool islogical = (!wants_default && !(devid & (1<<1)));
1778 if (!islogical) {
1779 device = ObtainPhysicalAudioDeviceDefaultAllowed(devid);
1780 } else {
1781 SDL_LogicalAudioDevice *logdev = ObtainLogicalAudioDevice(devid, &device);
1782 if (logdev) {
1783 wants_default = logdev->opened_as_default; // was the original logical device meant to be a default? Make this one, too.
1784 }
1785 }
1786
1787 SDL_AudioDeviceID result = 0;
1788
1789 if (device) {
1790 SDL_LogicalAudioDevice *logdev = NULL;
1791 if (!wants_default && SDL_GetAtomicInt(&device->zombie)) {
1792 // uhoh, this device is undead, and just waiting to be cleaned up. Refuse explicit opens.
1793 SDL_SetError("Device was already lost and can't accept new opens");
1794 } else if ((logdev = (SDL_LogicalAudioDevice *) SDL_calloc(1, sizeof (SDL_LogicalAudioDevice))) == NULL) {
1795 // SDL_calloc already called SDL_OutOfMemory
1796 } else if (!OpenPhysicalAudioDevice(device, spec)) { // if this is the first thing using this physical device, open at the OS level if necessary...
1797 SDL_free(logdev);
1798 } else {
1799 RefPhysicalAudioDevice(device); // unref'd on successful SDL_CloseAudioDevice
1800 SDL_SetAtomicInt(&logdev->paused, 0);
1801 result = logdev->instance_id = AssignAudioDeviceInstanceId(device->recording, /*islogical=*/true);
1802 logdev->physical_device = device;
1803 logdev->gain = 1.0f;
1804 logdev->opened_as_default = wants_default;
1805 logdev->next = device->logical_devices;
1806 if (device->logical_devices) {
1807 device->logical_devices->prev = logdev;
1808 }
1809 device->logical_devices = logdev;
1810 UpdateAudioStreamFormatsPhysical(device);
1811 }
1812 ReleaseAudioDevice(device);
1813
1814 if (result) {
1815 SDL_LockRWLockForWriting(current_audio.device_hash_lock);
1816 const bool inserted = SDL_InsertIntoHashTable(current_audio.device_hash, (const void *) (uintptr_t) result, logdev, false);
1817 SDL_UnlockRWLock(current_audio.device_hash_lock);
1818 if (!inserted) {
1819 SDL_CloseAudioDevice(result);
1820 result = 0;
1821 }
1822 }
1823 }
1824
1825 return result;
1826}
1827
1828static bool SetLogicalAudioDevicePauseState(SDL_AudioDeviceID devid, int value)
1829{
1830 SDL_AudioDevice *device = NULL;
1831 SDL_LogicalAudioDevice *logdev = ObtainLogicalAudioDevice(devid, &device);
1832 if (logdev) {
1833 SDL_SetAtomicInt(&logdev->paused, value);
1834 }
1835 ReleaseAudioDevice(device);
1836 return logdev ? true : false; // ObtainLogicalAudioDevice will have set an error.
1837}
1838
1839bool SDL_PauseAudioDevice(SDL_AudioDeviceID devid)
1840{
1841 return SetLogicalAudioDevicePauseState(devid, 1);
1842}
1843
1844bool SDLCALL SDL_ResumeAudioDevice(SDL_AudioDeviceID devid)
1845{
1846 return SetLogicalAudioDevicePauseState(devid, 0);
1847}
1848
1849bool SDL_AudioDevicePaused(SDL_AudioDeviceID devid)
1850{
1851 SDL_AudioDevice *device = NULL;
1852 SDL_LogicalAudioDevice *logdev = ObtainLogicalAudioDevice(devid, &device);
1853 bool result = false;
1854 if (logdev && SDL_GetAtomicInt(&logdev->paused)) {
1855 result = true;
1856 }
1857 ReleaseAudioDevice(device);
1858 return result;
1859}
1860
1861float SDL_GetAudioDeviceGain(SDL_AudioDeviceID devid)
1862{
1863 SDL_AudioDevice *device = NULL;
1864 SDL_LogicalAudioDevice *logdev = ObtainLogicalAudioDevice(devid, &device);
1865 const float result = logdev ? logdev->gain : -1.0f;
1866 ReleaseAudioDevice(device);
1867 return result;
1868}
1869
1870bool SDL_SetAudioDeviceGain(SDL_AudioDeviceID devid, float gain)
1871{
1872 if (gain < 0.0f) {
1873 return SDL_InvalidParamError("gain");
1874 }
1875
1876 SDL_AudioDevice *device = NULL;
1877 SDL_LogicalAudioDevice *logdev = ObtainLogicalAudioDevice(devid, &device);
1878 bool result = false;
1879 if (logdev) {
1880 logdev->gain = gain;
1881 UpdateAudioStreamFormatsPhysical(device);
1882 result = true;
1883 }
1884 ReleaseAudioDevice(device);
1885 return result;
1886}
1887
1888bool SDL_SetAudioPostmixCallback(SDL_AudioDeviceID devid, SDL_AudioPostmixCallback callback, void *userdata)
1889{
1890 SDL_AudioDevice *device = NULL;
1891 SDL_LogicalAudioDevice *logdev = ObtainLogicalAudioDevice(devid, &device);
1892 bool result = true;
1893 if (logdev) {
1894 if (callback && !device->postmix_buffer) {
1895 device->postmix_buffer = (float *)SDL_aligned_alloc(SDL_GetSIMDAlignment(), device->work_buffer_size);
1896 if (!device->postmix_buffer) {
1897 result = false;
1898 }
1899 }
1900
1901 if (result) {
1902 logdev->postmix = callback;
1903 logdev->postmix_userdata = userdata;
1904 }
1905
1906 UpdateAudioStreamFormatsPhysical(device);
1907 }
1908 ReleaseAudioDevice(device);
1909 return result;
1910}
1911
1912bool SDL_BindAudioStreams(SDL_AudioDeviceID devid, SDL_AudioStream * const *streams, int num_streams)
1913{
1914 const bool islogical = !(devid & (1<<1));
1915 SDL_AudioDevice *device = NULL;
1916 SDL_LogicalAudioDevice *logdev = NULL;
1917 bool result = true;
1918
1919 if (num_streams == 0) {
1920 return true; // nothing to do
1921 } else if (num_streams < 0) {
1922 return SDL_InvalidParamError("num_streams");
1923 } else if (!streams) {
1924 return SDL_InvalidParamError("streams");
1925 } else if (!islogical) {
1926 return SDL_SetError("Audio streams are bound to device ids from SDL_OpenAudioDevice, not raw physical devices");
1927 }
1928
1929 logdev = ObtainLogicalAudioDevice(devid, &device);
1930 if (!logdev) {
1931 result = false; // ObtainLogicalAudioDevice set the error string.
1932 } else if (logdev->simplified) {
1933 result = SDL_SetError("Cannot change stream bindings on device opened with SDL_OpenAudioDeviceStream");
1934 } else {
1935
1936 // !!! FIXME: We'll set the device's side's format below, but maybe we should refuse to bind a stream if the app's side doesn't have a format set yet.
1937 // !!! FIXME: Actually, why do we allow there to be an invalid format, again?
1938
1939 // make sure start of list is sane.
1940 SDL_assert(!logdev->bound_streams || (logdev->bound_streams->prev_binding == NULL));
1941
1942 // lock all the streams upfront, so we can verify they aren't bound elsewhere and add them all in one block, as this is intended to add everything or nothing.
1943 for (int i = 0; i < num_streams; i++) {
1944 SDL_AudioStream *stream = streams[i];
1945 if (!stream) {
1946 SDL_SetError("Stream #%d is NULL", i);
1947 result = false; // to pacify the static analyzer, that doesn't realize SDL_SetError() always returns false.
1948 } else {
1949 SDL_LockMutex(stream->lock);
1950 SDL_assert((stream->bound_device == NULL) == ((stream->prev_binding == NULL) || (stream->next_binding == NULL)));
1951 if (stream->bound_device) {
1952 result = SDL_SetError("Stream #%d is already bound to a device", i);
1953 } else if (stream->simplified) { // You can get here if you closed the device instead of destroying the stream.
1954 result = SDL_SetError("Cannot change binding on a stream created with SDL_OpenAudioDeviceStream");
1955 }
1956 }
1957
1958 if (!result) {
1959 int j;
1960 for (j = 0; j < i; j++) {
1961 SDL_UnlockMutex(streams[j]->lock);
1962 }
1963 if (stream) {
1964 SDL_UnlockMutex(stream->lock);
1965 }
1966 break;
1967 }
1968 }
1969 }
1970
1971 if (result) {
1972 // Now that everything is verified, chain everything together.
1973 for (int i = 0; i < num_streams; i++) {
1974 SDL_AudioStream *stream = streams[i];
1975 if (stream) { // shouldn't be NULL, but just in case...
1976 stream->bound_device = logdev;
1977 stream->prev_binding = NULL;
1978 stream->next_binding = logdev->bound_streams;
1979 if (logdev->bound_streams) {
1980 logdev->bound_streams->prev_binding = stream;
1981 }
1982 logdev->bound_streams = stream;
1983 SDL_UnlockMutex(stream->lock);
1984 }
1985 }
1986 }
1987
1988 UpdateAudioStreamFormatsPhysical(device);
1989
1990 ReleaseAudioDevice(device);
1991
1992 return result;
1993}
1994
1995bool SDL_BindAudioStream(SDL_AudioDeviceID devid, SDL_AudioStream *stream)
1996{
1997 return SDL_BindAudioStreams(devid, &stream, 1);
1998}
1999
2000// !!! FIXME: this and BindAudioStreams are mutex nightmares. :/
2001void SDL_UnbindAudioStreams(SDL_AudioStream * const *streams, int num_streams)
2002{
2003 if (num_streams <= 0 || !streams) {
2004 return; // nothing to do
2005 }
2006
2007 /* to prevent deadlock when holding both locks, we _must_ lock the device first, and the stream second, as that is the order the audio thread will do it.
2008 But this means we have an unlikely, pathological case where a stream could change its binding between when we lookup its bound device and when we lock everything,
2009 so we double-check here. */
2010 for (int i = 0; i < num_streams; i++) {
2011 SDL_AudioStream *stream = streams[i];
2012 if (!stream) {
2013 continue; // nothing to do, it's a NULL stream.
2014 }
2015
2016 while (true) {
2017 SDL_LockMutex(stream->lock); // lock to check this and then release it, in case the device isn't locked yet.
2018 SDL_LogicalAudioDevice *bounddev = stream->bound_device;
2019 SDL_UnlockMutex(stream->lock);
2020
2021 // lock in correct order.
2022 if (bounddev) {
2023 SDL_LockMutex(bounddev->physical_device->lock); // this requires recursive mutexes, since we're likely locking the same device multiple times.
2024 }
2025 SDL_LockMutex(stream->lock);
2026
2027 if (bounddev == stream->bound_device) {
2028 break; // the binding didn't change in the small window where it could, so we're good.
2029 } else {
2030 SDL_UnlockMutex(stream->lock); // it changed bindings! Try again.
2031 if (bounddev) {
2032 SDL_UnlockMutex(bounddev->physical_device->lock);
2033 }
2034 }
2035 }
2036 }
2037
2038 // everything is locked, start unbinding streams.
2039 for (int i = 0; i < num_streams; i++) {
2040 SDL_AudioStream *stream = streams[i];
2041 // don't allow unbinding from "simplified" devices (opened with SDL_OpenAudioDeviceStream). Just ignore them.
2042 if (stream && stream->bound_device && !stream->bound_device->simplified) {
2043 if (stream->bound_device->bound_streams == stream) {
2044 SDL_assert(!stream->prev_binding);
2045 stream->bound_device->bound_streams = stream->next_binding;
2046 }
2047 if (stream->prev_binding) {
2048 stream->prev_binding->next_binding = stream->next_binding;
2049 }
2050 if (stream->next_binding) {
2051 stream->next_binding->prev_binding = stream->prev_binding;
2052 }
2053 stream->prev_binding = stream->next_binding = NULL;
2054 }
2055 }
2056
2057 // Finalize and unlock everything.
2058 for (int i = 0; i < num_streams; i++) {
2059 SDL_AudioStream *stream = streams[i];
2060 if (stream) {
2061 SDL_LogicalAudioDevice *logdev = stream->bound_device;
2062 stream->bound_device = NULL;
2063 SDL_UnlockMutex(stream->lock);
2064 if (logdev) {
2065 UpdateAudioStreamFormatsPhysical(logdev->physical_device);
2066 SDL_UnlockMutex(logdev->physical_device->lock);
2067 }
2068 }
2069 }
2070}
2071
2072void SDL_UnbindAudioStream(SDL_AudioStream *stream)
2073{
2074 SDL_UnbindAudioStreams(&stream, 1);
2075}
2076
2077SDL_AudioDeviceID SDL_GetAudioStreamDevice(SDL_AudioStream *stream)
2078{
2079 SDL_AudioDeviceID result = 0;
2080
2081 if (!stream) {
2082 SDL_InvalidParamError("stream");
2083 return 0;
2084 }
2085
2086 SDL_LockMutex(stream->lock);
2087 if (stream->bound_device) {
2088 result = stream->bound_device->instance_id;
2089 } else {
2090 SDL_SetError("Audio stream not bound to an audio device");
2091 }
2092 SDL_UnlockMutex(stream->lock);
2093
2094 return result;
2095}
2096
2097SDL_AudioStream *SDL_OpenAudioDeviceStream(SDL_AudioDeviceID devid, const SDL_AudioSpec *spec, SDL_AudioStreamCallback callback, void *userdata)
2098{
2099 SDL_AudioDeviceID logdevid = SDL_OpenAudioDevice(devid, spec);
2100 if (!logdevid) {
2101 return NULL; // error string should already be set.
2102 }
2103
2104 bool failed = false;
2105 SDL_AudioStream *stream = NULL;
2106 SDL_AudioDevice *device = NULL;
2107 SDL_LogicalAudioDevice *logdev = ObtainLogicalAudioDevice(logdevid, &device);
2108 if (!logdev) { // this shouldn't happen, but just in case.
2109 failed = true;
2110 } else {
2111 SDL_SetAtomicInt(&logdev->paused, 1); // start the device paused, to match SDL2.
2112
2113 SDL_assert(device != NULL);
2114 const bool recording = device->recording;
2115
2116 // if the app didn't request a format _at all_, just make a stream that does no conversion; they can query for it later.
2117 SDL_AudioSpec tmpspec;
2118 if (!spec) {
2119 SDL_copyp(&tmpspec, &device->spec);
2120 spec = &tmpspec;
2121 }
2122
2123 if (recording) {
2124 stream = SDL_CreateAudioStream(&device->spec, spec);
2125 } else {
2126 stream = SDL_CreateAudioStream(spec, &device->spec);
2127 }
2128
2129 if (!stream) {
2130 failed = true;
2131 } else {
2132 // don't do all the complicated validation and locking of SDL_BindAudioStream just to set a few fields here.
2133 logdev->bound_streams = stream;
2134 logdev->simplified = true; // forbid further binding changes on this logical device.
2135
2136 stream->bound_device = logdev;
2137 stream->simplified = true; // so we know to close the audio device when this is destroyed.
2138
2139 UpdateAudioStreamFormatsPhysical(device);
2140
2141 if (callback) {
2142 bool rc;
2143 if (recording) {
2144 rc = SDL_SetAudioStreamPutCallback(stream, callback, userdata);
2145 } else {
2146 rc = SDL_SetAudioStreamGetCallback(stream, callback, userdata);
2147 }
2148 SDL_assert(rc); // should only fail if stream==NULL atm.
2149 }
2150 }
2151 }
2152
2153 ReleaseAudioDevice(device);
2154
2155 if (failed) {
2156 SDL_DestroyAudioStream(stream);
2157 SDL_CloseAudioDevice(logdevid);
2158 stream = NULL;
2159 }
2160
2161 return stream;
2162}
2163
2164bool SDL_PauseAudioStreamDevice(SDL_AudioStream *stream)
2165{
2166 SDL_AudioDeviceID devid = SDL_GetAudioStreamDevice(stream);
2167 if (!devid) {
2168 return false;
2169 }
2170
2171 return SDL_PauseAudioDevice(devid);
2172}
2173
2174bool SDL_ResumeAudioStreamDevice(SDL_AudioStream *stream)
2175{
2176 SDL_AudioDeviceID devid = SDL_GetAudioStreamDevice(stream);
2177 if (!devid) {
2178 return false;
2179 }
2180
2181 return SDL_ResumeAudioDevice(devid);
2182}
2183
2184bool SDL_AudioStreamDevicePaused(SDL_AudioStream *stream)
2185{
2186 SDL_AudioDeviceID devid = SDL_GetAudioStreamDevice(stream);
2187 if (!devid) {
2188 return false;
2189 }
2190
2191 return SDL_AudioDevicePaused(devid);
2192}
2193
2194#if SDL_BYTEORDER == SDL_LIL_ENDIAN
2195#define NATIVE(type) SDL_AUDIO_##type##LE
2196#define SWAPPED(type) SDL_AUDIO_##type##BE
2197#else
2198#define NATIVE(type) SDL_AUDIO_##type##BE
2199#define SWAPPED(type) SDL_AUDIO_##type##LE
2200#endif
2201
2202#define NUM_FORMATS 8
2203// always favor Float32 in native byte order, since we're probably going to convert to that for processing anyhow.
2204static const SDL_AudioFormat format_list[NUM_FORMATS][NUM_FORMATS + 1] = {
2205 { SDL_AUDIO_U8, NATIVE(F32), SWAPPED(F32), SDL_AUDIO_S8, NATIVE(S16), SWAPPED(S16), NATIVE(S32), SWAPPED(S32), SDL_AUDIO_UNKNOWN },
2206 { SDL_AUDIO_S8, NATIVE(F32), SWAPPED(F32), SDL_AUDIO_U8, NATIVE(S16), SWAPPED(S16), NATIVE(S32), SWAPPED(S32), SDL_AUDIO_UNKNOWN },
2207 { NATIVE(S16), NATIVE(F32), SWAPPED(F32), SWAPPED(S16), NATIVE(S32), SWAPPED(S32), SDL_AUDIO_U8, SDL_AUDIO_S8, SDL_AUDIO_UNKNOWN },
2208 { SWAPPED(S16), NATIVE(F32), SWAPPED(F32), NATIVE(S16), SWAPPED(S32), NATIVE(S32), SDL_AUDIO_U8, SDL_AUDIO_S8, SDL_AUDIO_UNKNOWN },
2209 { NATIVE(S32), NATIVE(F32), SWAPPED(F32), SWAPPED(S32), NATIVE(S16), SWAPPED(S16), SDL_AUDIO_U8, SDL_AUDIO_S8, SDL_AUDIO_UNKNOWN },
2210 { SWAPPED(S32), NATIVE(F32), SWAPPED(F32), NATIVE(S32), SWAPPED(S16), NATIVE(S16), SDL_AUDIO_U8, SDL_AUDIO_S8, SDL_AUDIO_UNKNOWN },
2211 { NATIVE(F32), SWAPPED(F32), NATIVE(S32), SWAPPED(S32), NATIVE(S16), SWAPPED(S16), SDL_AUDIO_U8, SDL_AUDIO_S8, SDL_AUDIO_UNKNOWN },
2212 { SWAPPED(F32), NATIVE(F32), SWAPPED(S32), NATIVE(S32), SWAPPED(S16), NATIVE(S16), SDL_AUDIO_U8, SDL_AUDIO_S8, SDL_AUDIO_UNKNOWN },
2213};
2214
2215#undef NATIVE
2216#undef SWAPPED
2217
2218const SDL_AudioFormat *SDL_ClosestAudioFormats(SDL_AudioFormat format)
2219{
2220 for (int i = 0; i < NUM_FORMATS; i++) {
2221 if (format_list[i][0] == format) {
2222 return &format_list[i][0];
2223 }
2224 }
2225 return &format_list[0][NUM_FORMATS]; // not found; return what looks like a list with only a zero in it.
2226}
2227
2228const char *SDL_GetAudioFormatName(SDL_AudioFormat format)
2229{
2230 switch (format) {
2231#define CASE(X) \
2232 case X: return #X;
2233 CASE(SDL_AUDIO_U8)
2234 CASE(SDL_AUDIO_S8)
2235 CASE(SDL_AUDIO_S16LE)
2236 CASE(SDL_AUDIO_S16BE)
2237 CASE(SDL_AUDIO_S32LE)
2238 CASE(SDL_AUDIO_S32BE)
2239 CASE(SDL_AUDIO_F32LE)
2240 CASE(SDL_AUDIO_F32BE)
2241#undef CASE
2242 default:
2243 return "SDL_AUDIO_UNKNOWN";
2244 }
2245}
2246
2247int SDL_GetSilenceValueForFormat(SDL_AudioFormat format)
2248{
2249 return (format == SDL_AUDIO_U8) ? 0x80 : 0x00;
2250}
2251
2252// called internally by backends when the system default device changes.
2253void SDL_DefaultAudioDeviceChanged(SDL_AudioDevice *new_default_device)
2254{
2255 if (!new_default_device) { // !!! FIXME: what should we do in this case? Maybe all devices are lost, so there _isn't_ a default?
2256 return; // uhoh.
2257 }
2258
2259 const bool recording = new_default_device->recording;
2260
2261 // change the official default over right away, so new opens will go to the new device.
2262 SDL_LockRWLockForWriting(current_audio.device_hash_lock);
2263 const SDL_AudioDeviceID current_devid = recording ? current_audio.default_recording_device_id : current_audio.default_playback_device_id;
2264 const bool is_already_default = (new_default_device->instance_id == current_devid);
2265 if (!is_already_default) {
2266 if (recording) {
2267 current_audio.default_recording_device_id = new_default_device->instance_id;
2268 } else {
2269 current_audio.default_playback_device_id = new_default_device->instance_id;
2270 }
2271 }
2272 SDL_UnlockRWLock(current_audio.device_hash_lock);
2273
2274 if (is_already_default) {
2275 return; // this is already the default.
2276 }
2277
2278 // Queue up events to push to the queue next time it pumps (presumably
2279 // in a safer thread).
2280 // !!! FIXME: this duplicates some code we could probably refactor.
2281 SDL_PendingAudioDeviceEvent pending;
2282 pending.next = NULL;
2283 SDL_PendingAudioDeviceEvent *pending_tail = &pending;
2284
2285 // Default device gets an extra ref, so it lives until a new default replaces it, even if disconnected.
2286 RefPhysicalAudioDevice(new_default_device);
2287
2288 ObtainPhysicalAudioDeviceObj(new_default_device);
2289
2290 SDL_AudioDevice *current_default_device = ObtainPhysicalAudioDevice(current_devid);
2291
2292 if (current_default_device) {
2293 // migrate any logical devices that were opened as a default to the new physical device...
2294
2295 SDL_assert(current_default_device->recording == recording);
2296
2297 // See if we have to open the new physical device, and if so, find the best audiospec for it.
2298 SDL_AudioSpec spec;
2299 bool needs_migration = false;
2300 SDL_zero(spec);
2301
2302 for (SDL_LogicalAudioDevice *logdev = current_default_device->logical_devices; logdev; logdev = logdev->next) {
2303 if (logdev->opened_as_default) {
2304 needs_migration = true;
2305 for (SDL_AudioStream *stream = logdev->bound_streams; stream; stream = stream->next_binding) {
2306 const SDL_AudioSpec *streamspec = recording ? &stream->dst_spec : &stream->src_spec;
2307 if (SDL_AUDIO_BITSIZE(streamspec->format) > SDL_AUDIO_BITSIZE(spec.format)) {
2308 spec.format = streamspec->format;
2309 }
2310 if (streamspec->channels > spec.channels) {
2311 spec.channels = streamspec->channels;
2312 }
2313 if (streamspec->freq > spec.freq) {
2314 spec.freq = streamspec->freq;
2315 }
2316 }
2317 }
2318 }
2319
2320 if (needs_migration) {
2321 // New default physical device not been opened yet? Open at the OS level...
2322 if (!OpenPhysicalAudioDevice(new_default_device, &spec)) {
2323 needs_migration = false; // uhoh, just leave everything on the old default, nothing to be done.
2324 }
2325 }
2326
2327 if (needs_migration) {
2328 // we don't currently report channel map changes, so we'll leave them as NULL for now.
2329 const bool spec_changed = !SDL_AudioSpecsEqual(&current_default_device->spec, &new_default_device->spec, NULL, NULL);
2330 SDL_LogicalAudioDevice *next = NULL;
2331 for (SDL_LogicalAudioDevice *logdev = current_default_device->logical_devices; logdev; logdev = next) {
2332 next = logdev->next;
2333
2334 if (!logdev->opened_as_default) {
2335 continue; // not opened as a default, leave it on the current physical device.
2336 }
2337
2338 // now migrate the logical device. Hold device_hash_lock so ObtainLogicalAudioDevice doesn't get a device in the middle of transition.
2339 SDL_LockRWLockForWriting(current_audio.device_hash_lock);
2340 if (logdev->next) {
2341 logdev->next->prev = logdev->prev;
2342 }
2343 if (logdev->prev) {
2344 logdev->prev->next = logdev->next;
2345 }
2346 if (current_default_device->logical_devices == logdev) {
2347 current_default_device->logical_devices = logdev->next;
2348 }
2349
2350 logdev->physical_device = new_default_device;
2351 logdev->prev = NULL;
2352 logdev->next = new_default_device->logical_devices;
2353 new_default_device->logical_devices = logdev;
2354 SDL_UnlockRWLock(current_audio.device_hash_lock);
2355
2356 SDL_assert(SDL_GetAtomicInt(&current_default_device->refcount) > 1); // we should hold at least one extra reference to this device, beyond logical devices, during this phase...
2357 RefPhysicalAudioDevice(new_default_device);
2358 UnrefPhysicalAudioDevice(current_default_device);
2359
2360 SDL_SetAudioPostmixCallback(logdev->instance_id, logdev->postmix, logdev->postmix_userdata);
2361
2362 SDL_PendingAudioDeviceEvent *p;
2363
2364 // Queue an event for each logical device we moved.
2365 if (spec_changed) {
2366 p = (SDL_PendingAudioDeviceEvent *)SDL_malloc(sizeof(SDL_PendingAudioDeviceEvent));
2367 if (p) { // if this failed, no event for you, but you have deeper problems anyhow.
2368 p->type = SDL_EVENT_AUDIO_DEVICE_FORMAT_CHANGED;
2369 p->devid = logdev->instance_id;
2370 p->next = NULL;
2371 pending_tail->next = p;
2372 pending_tail = p;
2373 }
2374 }
2375 }
2376
2377 UpdateAudioStreamFormatsPhysical(current_default_device);
2378 UpdateAudioStreamFormatsPhysical(new_default_device);
2379
2380 if (!current_default_device->logical_devices) { // nothing left on the current physical device, close it.
2381 ClosePhysicalAudioDevice(current_default_device);
2382 }
2383 }
2384
2385 ReleaseAudioDevice(current_default_device);
2386 }
2387
2388 ReleaseAudioDevice(new_default_device);
2389
2390 // Default device gets an extra ref, so it lives until a new default replaces it, even if disconnected.
2391 if (current_default_device) { // (despite the name, it's no longer current at this point)
2392 UnrefPhysicalAudioDevice(current_default_device);
2393 }
2394
2395 if (pending.next) {
2396 SDL_LockRWLockForWriting(current_audio.device_hash_lock);
2397 SDL_assert(current_audio.pending_events_tail != NULL);
2398 SDL_assert(current_audio.pending_events_tail->next == NULL);
2399 current_audio.pending_events_tail->next = pending.next;
2400 current_audio.pending_events_tail = pending_tail;
2401 SDL_UnlockRWLock(current_audio.device_hash_lock);
2402 }
2403}
2404
2405bool SDL_AudioDeviceFormatChangedAlreadyLocked(SDL_AudioDevice *device, const SDL_AudioSpec *newspec, int new_sample_frames)
2406{
2407 const int orig_work_buffer_size = device->work_buffer_size;
2408
2409 // we don't currently have any place where channel maps change from under you, but we can check that if necessary later.
2410 if (SDL_AudioSpecsEqual(&device->spec, newspec, NULL, NULL) && (new_sample_frames == device->sample_frames)) {
2411 return true; // we're already in that format.
2412 }
2413
2414 SDL_copyp(&device->spec, newspec);
2415 UpdateAudioStreamFormatsPhysical(device);
2416
2417 bool kill_device = false;
2418
2419 device->sample_frames = new_sample_frames;
2420 SDL_UpdatedAudioDeviceFormat(device);
2421 if (device->work_buffer && (device->work_buffer_size > orig_work_buffer_size)) {
2422 SDL_aligned_free(device->work_buffer);
2423 device->work_buffer = (Uint8 *)SDL_aligned_alloc(SDL_GetSIMDAlignment(), device->work_buffer_size);
2424 if (!device->work_buffer) {
2425 kill_device = true;
2426 }
2427
2428 if (device->postmix_buffer) {
2429 SDL_aligned_free(device->postmix_buffer);
2430 device->postmix_buffer = (float *)SDL_aligned_alloc(SDL_GetSIMDAlignment(), device->work_buffer_size);
2431 if (!device->postmix_buffer) {
2432 kill_device = true;
2433 }
2434 }
2435
2436 SDL_aligned_free(device->mix_buffer);
2437 device->mix_buffer = NULL;
2438 if (device->spec.format != SDL_AUDIO_F32) {
2439 device->mix_buffer = (Uint8 *)SDL_aligned_alloc(SDL_GetSIMDAlignment(), device->work_buffer_size);
2440 if (!device->mix_buffer) {
2441 kill_device = true;
2442 }
2443 }
2444 }
2445
2446 // Post an event for the physical device, and each logical device on this physical device.
2447 if (!kill_device) {
2448 // Queue up events to push to the queue next time it pumps (presumably
2449 // in a safer thread).
2450 // !!! FIXME: this duplicates some code we could probably refactor.
2451 SDL_PendingAudioDeviceEvent pending;
2452 pending.next = NULL;
2453 SDL_PendingAudioDeviceEvent *pending_tail = &pending;
2454
2455 SDL_PendingAudioDeviceEvent *p;
2456
2457 p = (SDL_PendingAudioDeviceEvent *)SDL_malloc(sizeof(SDL_PendingAudioDeviceEvent));
2458 if (p) { // if this failed, no event for you, but you have deeper problems anyhow.
2459 p->type = SDL_EVENT_AUDIO_DEVICE_FORMAT_CHANGED;
2460 p->devid = device->instance_id;
2461 p->next = NULL;
2462 pending_tail->next = p;
2463 pending_tail = p;
2464 }
2465
2466 for (SDL_LogicalAudioDevice *logdev = device->logical_devices; logdev; logdev = logdev->next) {
2467 p = (SDL_PendingAudioDeviceEvent *)SDL_malloc(sizeof(SDL_PendingAudioDeviceEvent));
2468 if (p) { // if this failed, no event for you, but you have deeper problems anyhow.
2469 p->type = SDL_EVENT_AUDIO_DEVICE_FORMAT_CHANGED;
2470 p->devid = logdev->instance_id;
2471 p->next = NULL;
2472 pending_tail->next = p;
2473 pending_tail = p;
2474 }
2475 }
2476
2477 if (pending.next) {
2478 SDL_LockRWLockForWriting(current_audio.device_hash_lock);
2479 SDL_assert(current_audio.pending_events_tail != NULL);
2480 SDL_assert(current_audio.pending_events_tail->next == NULL);
2481 current_audio.pending_events_tail->next = pending.next;
2482 current_audio.pending_events_tail = pending_tail;
2483 SDL_UnlockRWLock(current_audio.device_hash_lock);
2484 }
2485 }
2486
2487 if (kill_device) {
2488 return false;
2489 }
2490 return true;
2491}
2492
2493bool SDL_AudioDeviceFormatChanged(SDL_AudioDevice *device, const SDL_AudioSpec *newspec, int new_sample_frames)
2494{
2495 ObtainPhysicalAudioDeviceObj(device);
2496 const bool result = SDL_AudioDeviceFormatChangedAlreadyLocked(device, newspec, new_sample_frames);
2497 ReleaseAudioDevice(device);
2498 return result;
2499}
2500
2501// This is an internal function, so SDL_PumpEvents() can check for pending audio device events.
2502// ("UpdateSubsystem" is the same naming that the other things that hook into PumpEvents use.)
2503void SDL_UpdateAudio(void)
2504{
2505 SDL_LockRWLockForReading(current_audio.device_hash_lock);
2506 SDL_PendingAudioDeviceEvent *pending_events = current_audio.pending_events.next;
2507 SDL_UnlockRWLock(current_audio.device_hash_lock);
2508
2509 if (!pending_events) {
2510 return; // nothing to do, check next time.
2511 }
2512
2513 // okay, let's take this whole list of events so we can dump the lock, and new ones can queue up for a later update.
2514 SDL_LockRWLockForWriting(current_audio.device_hash_lock);
2515 pending_events = current_audio.pending_events.next; // in case this changed...
2516 current_audio.pending_events.next = NULL;
2517 current_audio.pending_events_tail = &current_audio.pending_events;
2518 SDL_UnlockRWLock(current_audio.device_hash_lock);
2519
2520 SDL_PendingAudioDeviceEvent *pending_next = NULL;
2521 for (SDL_PendingAudioDeviceEvent *i = pending_events; i; i = pending_next) {
2522 pending_next = i->next;
2523 if (SDL_EventEnabled(i->type)) {
2524 SDL_Event event;
2525 SDL_zero(event);
2526 event.type = i->type;
2527 event.adevice.which = (Uint32) i->devid;
2528 event.adevice.recording = ((i->devid & (1<<0)) == 0); // bit #0 of devid is set for playback devices and unset for recording.
2529 SDL_PushEvent(&event);
2530 }
2531 SDL_free(i);
2532 }
2533}
2534
2535