1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21
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 *device_hash_lock; // A rwlock that protects `device_hash`
187 SDL_HashTable *device_hash; // the collection of currently-available audio devices (recording, playback, logical and physical!)
188 SDL_AudioStream *existing_streams; // a list of all existing SDL_AudioStreams.
189 SDL_AudioDeviceID default_playback_device_id;
190 SDL_AudioDeviceID default_recording_device_id;
191 SDL_PendingAudioDeviceEvent pending_events;
192 SDL_PendingAudioDeviceEvent *pending_events_tail;
193
194 // !!! FIXME: most (all?) of these don't have to be atomic.
195 SDL_AtomicInt playback_device_count;
196 SDL_AtomicInt recording_device_count;
197 SDL_AtomicInt shutting_down; // non-zero during SDL_Quit, so we known not to accept any last-minute device hotplugs.
198} SDL_AudioDriver;
199
200struct SDL_AudioQueue; // forward decl.
201
202struct SDL_AudioStream
203{
204 SDL_Mutex* lock;
205
206 SDL_PropertiesID props;
207
208 SDL_AudioStreamCallback get_callback;
209 void *get_callback_userdata;
210 SDL_AudioStreamCallback put_callback;
211 void *put_callback_userdata;
212
213 SDL_AudioSpec src_spec;
214 SDL_AudioSpec dst_spec;
215 int *src_chmap;
216 int *dst_chmap;
217 float freq_ratio;
218 float gain;
219
220 struct SDL_AudioQueue* queue;
221
222 SDL_AudioSpec input_spec; // The spec of input data currently being processed
223 int *input_chmap;
224 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.
225 Sint64 resample_offset;
226
227 Uint8 *work_buffer; // used for scratch space during data conversion/resampling.
228 size_t work_buffer_allocation;
229
230 bool simplified; // true if created via SDL_OpenAudioDeviceStream
231
232 SDL_LogicalAudioDevice *bound_device;
233 SDL_AudioStream *next_binding;
234 SDL_AudioStream *prev_binding;
235
236 SDL_AudioStream *prev; // linked list of all existing streams (so we can free them on shutdown).
237 SDL_AudioStream *next; // linked list of all existing streams (so we can free them on shutdown).
238};
239
240/* Logical devices are an abstraction in SDL3; you can open the same physical
241 device multiple times, and each will result in an object with its own set
242 of bound audio streams, etc, even though internally these are all processed
243 as a group when mixing the final output for the physical device. */
244struct SDL_LogicalAudioDevice
245{
246 // the unique instance ID of this device.
247 SDL_AudioDeviceID instance_id;
248
249 // The physical device associated with this opened device.
250 SDL_AudioDevice *physical_device;
251
252 // If whole logical device is paused (process no streams bound to this device).
253 SDL_AtomicInt paused;
254
255 // Volume of the device output.
256 float gain;
257
258 // double-linked list of all audio streams currently bound to this opened device.
259 SDL_AudioStream *bound_streams;
260
261 // true if this was opened as a default device.
262 bool opened_as_default;
263
264 // true if device was opened with SDL_OpenAudioDeviceStream (so it forbids binding changes, etc).
265 bool simplified;
266
267 // If non-NULL, callback into the app that lets them access the final postmix buffer.
268 SDL_AudioPostmixCallback postmix;
269
270 // App-supplied pointer for postmix callback.
271 void *postmix_userdata;
272
273 // double-linked list of opened devices on the same physical device.
274 SDL_LogicalAudioDevice *next;
275 SDL_LogicalAudioDevice *prev;
276};
277
278struct SDL_AudioDevice
279{
280 // A mutex for locking access to this struct
281 SDL_Mutex *lock;
282
283 // A condition variable to protect device close, where we can't hold the device lock forever.
284 SDL_Condition *close_cond;
285
286 // Reference count of the device; logical devices, device threads, etc, add to this.
287 SDL_AtomicInt refcount;
288
289 // These are, initially, set from current_audio, but we might swap them out with Zombie versions on disconnect/failure.
290 bool (*WaitDevice)(SDL_AudioDevice *device);
291 bool (*PlayDevice)(SDL_AudioDevice *device, const Uint8 *buffer, int buflen);
292 Uint8 *(*GetDeviceBuf)(SDL_AudioDevice *device, int *buffer_size);
293 bool (*WaitRecordingDevice)(SDL_AudioDevice *device);
294 int (*RecordDevice)(SDL_AudioDevice *device, void *buffer, int buflen);
295 void (*FlushRecording)(SDL_AudioDevice *device);
296
297 // human-readable name of the device. ("SoundBlaster Pro 16")
298 char *name;
299
300 // the unique instance ID of this device.
301 SDL_AudioDeviceID instance_id;
302
303 // a way for the backend to identify this device _when not opened_
304 void *handle;
305
306 // The device's current audio specification
307 SDL_AudioSpec spec;
308
309 // The size, in bytes, of the device's playback/recording buffer.
310 int buffer_size;
311
312 // The device's channel map, or NULL for SDL default layout.
313 int *chmap;
314
315 // The device's default audio specification
316 SDL_AudioSpec default_spec;
317
318 // Number of sample frames the devices wants per-buffer.
319 int sample_frames;
320
321 // Value to use for SDL_memset to silence a buffer in this device's format
322 int silence_value;
323
324 // non-zero if we are signaling the audio thread to end.
325 SDL_AtomicInt shutdown;
326
327 // non-zero if this was a disconnected device and we're waiting for it to be decommissioned.
328 SDL_AtomicInt zombie;
329
330 // true if this is a recording device instead of an playback device
331 bool recording;
332
333 // true if audio thread can skip silence/mix/convert stages and just do a basic memcpy.
334 bool simple_copy;
335
336 // Scratch buffers used for mixing.
337 Uint8 *work_buffer;
338 Uint8 *mix_buffer;
339 float *postmix_buffer;
340
341 // Size of work_buffer (and mix_buffer) in bytes.
342 int work_buffer_size;
343
344 // A thread to feed the audio device
345 SDL_Thread *thread;
346
347 // true if this physical device is currently opened by the backend.
348 bool currently_opened;
349
350 // Data private to this driver
351 struct SDL_PrivateAudioData *hidden;
352
353 // All logical devices associated with this physical device.
354 SDL_LogicalAudioDevice *logical_devices;
355};
356
357typedef struct AudioBootStrap
358{
359 const char *name;
360 const char *desc;
361 bool (*init)(SDL_AudioDriverImpl *impl);
362 bool demand_only; // if true: request explicitly, or it won't be available.
363 bool is_preferred;
364} AudioBootStrap;
365
366// Not all of these are available in a given build. Use #ifdefs, etc.
367extern AudioBootStrap PRIVATEAUDIO_bootstrap;
368extern AudioBootStrap PIPEWIRE_PREFERRED_bootstrap;
369extern AudioBootStrap PIPEWIRE_bootstrap;
370extern AudioBootStrap PULSEAUDIO_bootstrap;
371extern AudioBootStrap ALSA_bootstrap;
372extern AudioBootStrap JACK_bootstrap;
373extern AudioBootStrap SNDIO_bootstrap;
374extern AudioBootStrap NETBSDAUDIO_bootstrap;
375extern AudioBootStrap DSP_bootstrap;
376extern AudioBootStrap WASAPI_bootstrap;
377extern AudioBootStrap DSOUND_bootstrap;
378extern AudioBootStrap WINMM_bootstrap;
379extern AudioBootStrap HAIKUAUDIO_bootstrap;
380extern AudioBootStrap COREAUDIO_bootstrap;
381extern AudioBootStrap DISKAUDIO_bootstrap;
382extern AudioBootStrap DUMMYAUDIO_bootstrap;
383extern AudioBootStrap AAUDIO_bootstrap;
384extern AudioBootStrap OPENSLES_bootstrap;
385extern AudioBootStrap PS2AUDIO_bootstrap;
386extern AudioBootStrap PSPAUDIO_bootstrap;
387extern AudioBootStrap VITAAUD_bootstrap;
388extern AudioBootStrap N3DSAUDIO_bootstrap;
389extern AudioBootStrap EMSCRIPTENAUDIO_bootstrap;
390extern AudioBootStrap QSAAUDIO_bootstrap;
391
392#endif // SDL_sysaudio_h_
393