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