Atlas - SDL_sysaudio.h
Home / ext / SDL / src / audio Lines: 1 | Size: 17602 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21 22#include "SDL_internal.h" 23 24#ifndef SDL_sysaudio_h_ 25#define SDL_sysaudio_h_ 26 27#define DEBUG_AUDIOSTREAM 0 28#define DEBUG_AUDIO_CONVERT 0 29 30#if DEBUG_AUDIO_CONVERT 31#define LOG_DEBUG_AUDIO_CONVERT(from, to) SDL_Log("SDL_AUDIO_CONVERT: Converting %s to %s.", from, to); 32#else 33#define LOG_DEBUG_AUDIO_CONVERT(from, to) 34#endif 35 36// !!! FIXME: These are wordy and unlocalized... 37#define DEFAULT_PLAYBACK_DEVNAME "System audio playback device" 38#define DEFAULT_RECORDING_DEVNAME "System audio recording device" 39 40// these are used when no better specifics are known. We default to CD audio quality. 41#define DEFAULT_AUDIO_PLAYBACK_FORMAT SDL_AUDIO_S16 42#define DEFAULT_AUDIO_PLAYBACK_CHANNELS 2 43#define DEFAULT_AUDIO_PLAYBACK_FREQUENCY 44100 44 45#define DEFAULT_AUDIO_RECORDING_FORMAT SDL_AUDIO_S16 46#define DEFAULT_AUDIO_RECORDING_CHANNELS 1 47#define DEFAULT_AUDIO_RECORDING_FREQUENCY 44100 48 49#define SDL_MAX_CHANNELMAP_CHANNELS 8 // !!! FIXME: if SDL ever supports more channels, clean this out and make those parts dynamic. 50 51typedef struct SDL_AudioDevice SDL_AudioDevice; 52typedef struct SDL_LogicalAudioDevice SDL_LogicalAudioDevice; 53 54// Used by src/SDL.c to initialize a particular audio driver. 55extern bool SDL_InitAudio(const char *driver_name); 56 57// Used by src/SDL.c to shut down previously-initialized audio. 58extern void SDL_QuitAudio(void); 59 60// Function to get a list of audio formats, ordered most similar to `format` to least, 0-terminated. Don't free results. 61const SDL_AudioFormat *SDL_ClosestAudioFormats(SDL_AudioFormat format); 62 63// Must be called at least once before using converters. 64extern void SDL_ChooseAudioConverters(void); 65extern void SDL_SetupAudioResampler(void); 66 67/* Backends should call this as devices are added to the system (such as 68 a USB headset being plugged in), and should also be called for 69 for every device found during DetectDevices(). */ 70extern SDL_AudioDevice *SDL_AddAudioDevice(bool recording, const char *name, const SDL_AudioSpec *spec, void *handle); 71 72/* Backends should call this if an opened audio device is lost. 73 This can happen due to i/o errors, or a device being unplugged, etc. */ 74extern void SDL_AudioDeviceDisconnected(SDL_AudioDevice *device); 75 76// Backends should call this if the system default device changes. 77extern void SDL_DefaultAudioDeviceChanged(SDL_AudioDevice *new_default_device); 78 79// Backends should call this if a device's format is changing (opened or not); SDL will update state and carry on with the new format. 80extern bool SDL_AudioDeviceFormatChanged(SDL_AudioDevice *device, const SDL_AudioSpec *newspec, int new_sample_frames); 81 82// Same as above, but assume the device is already locked. 83extern bool SDL_AudioDeviceFormatChangedAlreadyLocked(SDL_AudioDevice *device, const SDL_AudioSpec *newspec, int new_sample_frames); 84 85// Find the SDL_AudioDevice associated with the handle supplied to SDL_AddAudioDevice. NULL if not found. DOES NOT LOCK THE DEVICE. 86extern SDL_AudioDevice *SDL_FindPhysicalAudioDeviceByHandle(void *handle); 87 88// Find an SDL_AudioDevice, selected by a callback. NULL if not found. DOES NOT LOCK THE DEVICE. 89extern SDL_AudioDevice *SDL_FindPhysicalAudioDeviceByCallback(bool (*callback)(SDL_AudioDevice *device, void *userdata), void *userdata); 90 91// Backends should call this if they change the device format, channels, freq, or sample_frames to keep other state correct. 92extern void SDL_UpdatedAudioDeviceFormat(SDL_AudioDevice *device); 93 94// Backends can call this to get a reasonable default sample frame count for a device's sample rate. 95int SDL_GetDefaultSampleFramesFromFreq(const int freq); 96 97// Backends can call this to get a standardized name for a thread to power a specific audio device. 98extern char *SDL_GetAudioThreadName(SDL_AudioDevice *device, char *buf, size_t buflen); 99 100// Backends can call these to change a device's refcount. 101extern void RefPhysicalAudioDevice(SDL_AudioDevice *device); 102extern void UnrefPhysicalAudioDevice(SDL_AudioDevice *device); 103 104// These functions are the heart of the audio threads. Backends can call them directly if they aren't using the SDL-provided thread. 105extern void SDL_PlaybackAudioThreadSetup(SDL_AudioDevice *device); 106extern bool SDL_PlaybackAudioThreadIterate(SDL_AudioDevice *device); 107extern void SDL_PlaybackAudioThreadShutdown(SDL_AudioDevice *device); 108extern void SDL_RecordingAudioThreadSetup(SDL_AudioDevice *device); 109extern bool SDL_RecordingAudioThreadIterate(SDL_AudioDevice *device); 110extern void SDL_RecordingAudioThreadShutdown(SDL_AudioDevice *device); 111extern void SDL_AudioThreadFinalize(SDL_AudioDevice *device); 112 113extern void ConvertAudioToFloat(float *dst, const void *src, int num_samples, SDL_AudioFormat src_fmt); 114extern void ConvertAudioFromFloat(void *dst, const float *src, int num_samples, SDL_AudioFormat dst_fmt); 115extern void ConvertAudioSwapEndian(void *dst, const void *src, int num_samples, int bitsize); 116 117extern bool SDL_ChannelMapIsDefault(const int *map, int channels); 118extern bool SDL_ChannelMapIsBogus(const int *map, int channels); 119 120// this gets used from the audio device threads. It has rules, don't use this if you don't know how to use it! 121extern void ConvertAudio(int num_frames, 122 const void *src, SDL_AudioFormat src_format, int src_channels, const int *src_map, 123 void *dst, SDL_AudioFormat dst_format, int dst_channels, const int *dst_map, 124 void *scratch, float gain); 125 126// Compare two SDL_AudioSpecs, return true if they match exactly. 127// Using SDL_memcmp directly isn't safe, since potential padding might not be initialized. 128// either channel map can be NULL for the default (and both should be if you don't care about them). 129extern bool SDL_AudioSpecsEqual(const SDL_AudioSpec *a, const SDL_AudioSpec *b, const int *channel_map_a, const int *channel_map_b); 130 131// See if two channel maps match 132// either channel map can be NULL for the default (and both should be if you don't care about them). 133extern bool SDL_AudioChannelMapsEqual(int channels, const int *channel_map_a, const int *channel_map_b); 134 135// allocate+copy a channel map. 136extern int *SDL_ChannelMapDup(const int *origchmap, int channels); 137 138// Special case to let something in SDL_audiocvt.c access something in SDL_audio.c. Don't use this. 139extern void OnAudioStreamCreated(SDL_AudioStream *stream); 140extern void OnAudioStreamDestroy(SDL_AudioStream *stream); 141 142// This just lets audio playback apply logical device gain at the same time as audiostream gain, so it's one multiplication instead of thousands. 143extern int SDL_GetAudioStreamDataAdjustGain(SDL_AudioStream *stream, void *voidbuf, int len, float extra_gain); 144 145// This is the bulk of `SDL_SetAudioStream*putChannelMap`'s work, but it lets you skip the check about changing the device end of a stream if isinput==-1. 146extern bool SetAudioStreamChannelMap(SDL_AudioStream *stream, const SDL_AudioSpec *spec, int **stream_chmap, const int *chmap, int channels, int isinput); 147 148 149typedef struct SDL_AudioDriverImpl 150{ 151 void (*DetectDevices)(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording); 152 bool (*OpenDevice)(SDL_AudioDevice *device); 153 void (*ThreadInit)(SDL_AudioDevice *device); // Called by audio thread at start 154 void (*ThreadDeinit)(SDL_AudioDevice *device); // Called by audio thread at end 155 bool (*WaitDevice)(SDL_AudioDevice *device); 156 bool (*PlayDevice)(SDL_AudioDevice *device, const Uint8 *buffer, int buflen); // buffer and buflen are always from GetDeviceBuf, passed here for convenience. 157 Uint8 *(*GetDeviceBuf)(SDL_AudioDevice *device, int *buffer_size); 158 bool (*WaitRecordingDevice)(SDL_AudioDevice *device); 159 int (*RecordDevice)(SDL_AudioDevice *device, void *buffer, int buflen); 160 void (*FlushRecording)(SDL_AudioDevice *device); 161 void (*CloseDevice)(SDL_AudioDevice *device); 162 void (*FreeDeviceHandle)(SDL_AudioDevice *device); // SDL is done with this device; free the handle from SDL_AddAudioDevice() 163 void (*DeinitializeStart)(void); // SDL calls this, then starts destroying objects, then calls Deinitialize. This is a good place to stop hotplug detection. 164 void (*Deinitialize)(void); 165 166 // Some flags to push duplicate code into the core and reduce #ifdefs. 167 bool ProvidesOwnCallbackThread; // !!! FIXME: rename this, it's not a callback thread anymore. 168 bool HasRecordingSupport; 169 bool OnlyHasDefaultPlaybackDevice; 170 bool OnlyHasDefaultRecordingDevice; // !!! FIXME: is there ever a time where you'd have a default playback and not a default recording (or vice versa)? 171} SDL_AudioDriverImpl; 172 173 174typedef struct SDL_PendingAudioDeviceEvent 175{ 176 Uint32 type; 177 SDL_AudioDeviceID devid; 178 struct SDL_PendingAudioDeviceEvent *next; 179} SDL_PendingAudioDeviceEvent; 180 181typedef struct SDL_AudioDriver 182{ 183 const char *name; // The name of this audio driver 184 const char *desc; // The description of this audio driver 185 SDL_AudioDriverImpl impl; // the backend's interface 186 SDL_RWLock *subsystem_rwlock; // A rwlock that protects several things in the audio subsystem (device hashtables, etc). 187 SDL_HashTable *device_hash_physical; // the collection of currently-available audio devices (recording and playback), for mapping SDL_AudioDeviceID to an SDL_AudioDevice*. 188 SDL_HashTable *device_hash_logical; // the collection of currently-available audio devices (recording and playback), for mapping SDL_AudioDeviceID to an SDL_LogicalAudioDevice*. 189 SDL_AudioStream *existing_streams; // a list of all existing SDL_AudioStreams. 190 SDL_AudioDeviceID default_playback_device_id; 191 SDL_AudioDeviceID default_recording_device_id; 192 SDL_PendingAudioDeviceEvent pending_events; 193 SDL_PendingAudioDeviceEvent *pending_events_tail; 194 195 // !!! FIXME: most (all?) of these don't have to be atomic. 196 SDL_AtomicInt playback_device_count; 197 SDL_AtomicInt recording_device_count; 198 SDL_AtomicInt shutting_down; // non-zero during SDL_Quit, so we known not to accept any last-minute device hotplugs. 199} SDL_AudioDriver; 200 201struct SDL_AudioQueue; // forward decl. 202 203struct SDL_AudioStream 204{ 205 SDL_Mutex *lock; 206 207 SDL_PropertiesID props; 208 209 SDL_AudioStreamCallback get_callback; 210 void *get_callback_userdata; 211 SDL_AudioStreamCallback put_callback; 212 void *put_callback_userdata; 213 214 SDL_AudioSpec src_spec; 215 SDL_AudioSpec dst_spec; 216 int *src_chmap; 217 int *dst_chmap; 218 float freq_ratio; 219 float gain; 220 221 struct SDL_AudioQueue *queue; 222 223 SDL_AudioSpec input_spec; // The spec of input data currently being processed 224 int *input_chmap; 225 int input_chmap_storage[SDL_MAX_CHANNELMAP_CHANNELS]; // !!! FIXME: this needs to grow if SDL ever supports more channels. But if it grows, we should probably be more clever about allocations. 226 Sint64 resample_offset; 227 228 Uint8 *work_buffer; // used for scratch space during data conversion/resampling. 229 size_t work_buffer_allocation; 230 231 bool simplified; // true if created via SDL_OpenAudioDeviceStream 232 233 SDL_LogicalAudioDevice *bound_device; 234 SDL_AudioStream *next_binding; 235 SDL_AudioStream *prev_binding; 236 237 SDL_AudioStream *prev; // linked list of all existing streams (so we can free them on shutdown). 238 SDL_AudioStream *next; // linked list of all existing streams (so we can free them on shutdown). 239}; 240 241/* Logical devices are an abstraction in SDL3; you can open the same physical 242 device multiple times, and each will result in an object with its own set 243 of bound audio streams, etc, even though internally these are all processed 244 as a group when mixing the final output for the physical device. */ 245struct SDL_LogicalAudioDevice 246{ 247 // the unique instance ID of this device. 248 SDL_AudioDeviceID instance_id; 249 250 // The physical device associated with this opened device. 251 SDL_AudioDevice *physical_device; 252 253 // If whole logical device is paused (process no streams bound to this device). 254 SDL_AtomicInt paused; 255 256 // Volume of the device output. 257 float gain; 258 259 // double-linked list of all audio streams currently bound to this opened device. 260 SDL_AudioStream *bound_streams; 261 262 // true if this was opened as a default device. 263 bool opened_as_default; 264 265 // true if device was opened with SDL_OpenAudioDeviceStream (so it forbids binding changes, etc). 266 bool simplified; 267 268 // If non-NULL, callback into the app that lets them access the final postmix buffer. 269 SDL_AudioPostmixCallback postmix; 270 271 // App-supplied pointer for postmix callback. 272 void *postmix_userdata; 273 274 // double-linked list of opened devices on the same physical device. 275 SDL_LogicalAudioDevice *next; 276 SDL_LogicalAudioDevice *prev; 277}; 278 279struct SDL_AudioDevice 280{ 281 // A mutex for locking access to this struct 282 SDL_Mutex *lock; 283 284 // A condition variable to protect device close, where we can't hold the device lock forever. 285 SDL_Condition *close_cond; 286 287 // Reference count of the device; logical devices, device threads, etc, add to this. 288 SDL_AtomicInt refcount; 289 290 // These are, initially, set from current_audio, but we might swap them out with Zombie versions on disconnect/failure. 291 bool (*WaitDevice)(SDL_AudioDevice *device); 292 bool (*PlayDevice)(SDL_AudioDevice *device, const Uint8 *buffer, int buflen); 293 Uint8 *(*GetDeviceBuf)(SDL_AudioDevice *device, int *buffer_size); 294 bool (*WaitRecordingDevice)(SDL_AudioDevice *device); 295 int (*RecordDevice)(SDL_AudioDevice *device, void *buffer, int buflen); 296 void (*FlushRecording)(SDL_AudioDevice *device); 297 298 // human-readable name of the device. ("SoundBlaster Pro 16") 299 char *name; 300 301 // the unique instance ID of this device. 302 SDL_AudioDeviceID instance_id; 303 304 // a way for the backend to identify this device _when not opened_ 305 void *handle; 306 307 // The device's current audio specification 308 SDL_AudioSpec spec; 309 310 // The size, in bytes, of the device's playback/recording buffer. 311 int buffer_size; 312 313 // The device's channel map, or NULL for SDL default layout. 314 int *chmap; 315 316 // The device's default audio specification 317 SDL_AudioSpec default_spec; 318 319 // Number of sample frames the devices wants per-buffer. 320 int sample_frames; 321 322 // Value to use for SDL_memset to silence a buffer in this device's format 323 int silence_value; 324 325 // non-zero if we are signaling the audio thread to end. 326 SDL_AtomicInt shutdown; 327 328 // non-zero if this was a disconnected device and we're waiting for it to be decommissioned. 329 SDL_AtomicInt zombie; 330 331 // true if this is a recording device instead of an playback device 332 bool recording; 333 334 // true if audio thread can skip silence/mix/convert stages and just do a basic memcpy. 335 bool simple_copy; 336 337 // Scratch buffers used for mixing. 338 Uint8 *work_buffer; 339 Uint8 *mix_buffer; 340 float *postmix_buffer; 341 342 // Size of work_buffer (and mix_buffer) in bytes. 343 int work_buffer_size; 344 345 // A thread to feed the audio device 346 SDL_Thread *thread; 347 348 // true if this physical device is currently opened by the backend. 349 bool currently_opened; 350 351 // Data private to this driver 352 struct SDL_PrivateAudioData *hidden; 353 354 // All logical devices associated with this physical device. 355 SDL_LogicalAudioDevice *logical_devices; 356}; 357 358typedef struct AudioBootStrap 359{ 360 const char *name; 361 const char *desc; 362 bool (*init)(SDL_AudioDriverImpl *impl); 363 bool demand_only; // if true: request explicitly, or it won't be available. 364 bool is_preferred; 365} AudioBootStrap; 366 367// Not all of these are available in a given build. Use #ifdefs, etc. 368extern AudioBootStrap PRIVATEAUDIO_bootstrap; 369extern AudioBootStrap PIPEWIRE_PREFERRED_bootstrap; 370extern AudioBootStrap PIPEWIRE_bootstrap; 371extern AudioBootStrap PULSEAUDIO_bootstrap; 372extern AudioBootStrap ALSA_bootstrap; 373extern AudioBootStrap JACK_bootstrap; 374extern AudioBootStrap SNDIO_bootstrap; 375extern AudioBootStrap NETBSDAUDIO_bootstrap; 376extern AudioBootStrap DSP_bootstrap; 377extern AudioBootStrap WASAPI_bootstrap; 378extern AudioBootStrap DSOUND_bootstrap; 379extern AudioBootStrap WINMM_bootstrap; 380extern AudioBootStrap HAIKUAUDIO_bootstrap; 381extern AudioBootStrap COREAUDIO_bootstrap; 382extern AudioBootStrap DISKAUDIO_bootstrap; 383extern AudioBootStrap DUMMYAUDIO_bootstrap; 384extern AudioBootStrap AAUDIO_bootstrap; 385extern AudioBootStrap OPENSLES_bootstrap; 386extern AudioBootStrap PS2AUDIO_bootstrap; 387extern AudioBootStrap PSPAUDIO_bootstrap; 388extern AudioBootStrap VITAAUD_bootstrap; 389extern AudioBootStrap N3DSAUDIO_bootstrap; 390extern AudioBootStrap NGAGEAUDIO_bootstrap; 391extern AudioBootStrap EMSCRIPTENAUDIO_bootstrap; 392extern AudioBootStrap QSAAUDIO_bootstrap; 393 394#endif // SDL_sysaudio_h_ 395[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.