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