Skip to content

Commit 67e8522

Browse files
flibitijibiboslouken
authored andcommitted
Add SDL_GetAudioDeviceSpec.
This API is supported by pipewire, pulseaudio, coreaudio, wasapi, and disk.
1 parent 00fabdd commit 67e8522

File tree

19 files changed

+256
-67
lines changed

19 files changed

+256
-67
lines changed

include/SDL_audio.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,25 @@ extern DECLSPEC int SDLCALL SDL_GetNumAudioDevices(int iscapture);
359359
extern DECLSPEC const char *SDLCALL SDL_GetAudioDeviceName(int index,
360360
int iscapture);
361361

362+
/**
363+
* Get the audio format of a specific audio device.
364+
* Must be a value between 0 and (number of audio devices-1).
365+
* Only valid after a successfully initializing the audio subsystem.
366+
* The values returned by this function reflect the latest call to
367+
* SDL_GetNumAudioDevices(); recall that function to redetect available
368+
* hardware.
369+
*
370+
* The spec will be filled with the sample rate, sample format, and channel
371+
* count. All other values in the structure are filled with 0. When the
372+
* supported struct members are 0, SDL was unable to get the property from the
373+
* backend.
374+
*
375+
* \return 0 on success, nonzero on error
376+
*/
377+
extern DECLSPEC int SDLCALL SDL_GetAudioDeviceSpec(int index,
378+
int iscapture,
379+
SDL_AudioSpec *spec);
380+
362381

363382
/**
364383
* Open a specific audio device. Passing in a device name of NULL requests

src/audio/SDL_audio.c

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -223,9 +223,9 @@ SDL_AudioDetectDevices_Default(void)
223223
SDL_assert(current_audio.impl.OnlyHasDefaultOutputDevice);
224224
SDL_assert(current_audio.impl.OnlyHasDefaultCaptureDevice || !current_audio.impl.HasCaptureSupport);
225225

226-
SDL_AddAudioDevice(SDL_FALSE, DEFAULT_OUTPUT_DEVNAME, (void *) ((size_t) 0x1));
226+
SDL_AddAudioDevice(SDL_FALSE, DEFAULT_OUTPUT_DEVNAME, NULL, (void *) ((size_t) 0x1));
227227
if (current_audio.impl.HasCaptureSupport) {
228-
SDL_AddAudioDevice(SDL_TRUE, DEFAULT_INPUT_DEVNAME, (void *) ((size_t) 0x2));
228+
SDL_AddAudioDevice(SDL_TRUE, DEFAULT_INPUT_DEVNAME, NULL, (void *) ((size_t) 0x2));
229229
}
230230
}
231231

@@ -377,7 +377,7 @@ finish_audio_entry_points_init(void)
377377
/* device hotplug support... */
378378

379379
static int
380-
add_audio_device(const char *name, void *handle, SDL_AudioDeviceItem **devices, int *devCount)
380+
add_audio_device(const char *name, SDL_AudioSpec *spec, void *handle, SDL_AudioDeviceItem **devices, int *devCount)
381381
{
382382
int retval = -1;
383383
SDL_AudioDeviceItem *item;
@@ -400,6 +400,11 @@ add_audio_device(const char *name, void *handle, SDL_AudioDeviceItem **devices,
400400

401401
item->dupenum = 0;
402402
item->name = item->original_name;
403+
if (spec != NULL) {
404+
SDL_memcpy(&item->spec, spec, sizeof(SDL_AudioSpec));
405+
} else {
406+
SDL_zero(item->spec);
407+
}
403408
item->handle = handle;
404409

405410
SDL_LockMutex(current_audio.detectionLock);
@@ -437,16 +442,16 @@ add_audio_device(const char *name, void *handle, SDL_AudioDeviceItem **devices,
437442
}
438443

439444
static SDL_INLINE int
440-
add_capture_device(const char *name, void *handle)
445+
add_capture_device(const char *name, SDL_AudioSpec *spec, void *handle)
441446
{
442447
SDL_assert(current_audio.impl.HasCaptureSupport);
443-
return add_audio_device(name, handle, &current_audio.inputDevices, &current_audio.inputDeviceCount);
448+
return add_audio_device(name, spec, handle, &current_audio.inputDevices, &current_audio.inputDeviceCount);
444449
}
445450

446451
static SDL_INLINE int
447-
add_output_device(const char *name, void *handle)
452+
add_output_device(const char *name, SDL_AudioSpec *spec, void *handle)
448453
{
449-
return add_audio_device(name, handle, &current_audio.outputDevices, &current_audio.outputDeviceCount);
454+
return add_audio_device(name, spec, handle, &current_audio.outputDevices, &current_audio.outputDeviceCount);
450455
}
451456

452457
static void
@@ -472,9 +477,9 @@ free_device_list(SDL_AudioDeviceItem **devices, int *devCount)
472477

473478
/* The audio backends call this when a new device is plugged in. */
474479
void
475-
SDL_AddAudioDevice(const int iscapture, const char *name, void *handle)
480+
SDL_AddAudioDevice(const int iscapture, const char *name, SDL_AudioSpec *spec, void *handle)
476481
{
477-
const int device_index = iscapture ? add_capture_device(name, handle) : add_output_device(name, handle);
482+
const int device_index = iscapture ? add_capture_device(name, spec, handle) : add_output_device(name, spec, handle);
478483
if (device_index != -1) {
479484
/* Post the event, if desired */
480485
if (SDL_GetEventState(SDL_AUDIODEVICEADDED) == SDL_ENABLE) {
@@ -1112,6 +1117,44 @@ SDL_GetAudioDeviceName(int index, int iscapture)
11121117
}
11131118

11141119

1120+
int
1121+
SDL_GetAudioDeviceSpec(int index, int iscapture, SDL_AudioSpec *spec)
1122+
{
1123+
if (spec == NULL) {
1124+
return SDL_InvalidParamError("spec");
1125+
}
1126+
1127+
SDL_zerop(spec);
1128+
1129+
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
1130+
return SDL_SetError("Audio subsystem is not initialized");
1131+
}
1132+
1133+
if (iscapture && !current_audio.impl.HasCaptureSupport) {
1134+
return SDL_SetError("No capture support");
1135+
}
1136+
1137+
if (index >= 0) {
1138+
SDL_AudioDeviceItem *item;
1139+
int i;
1140+
1141+
SDL_LockMutex(current_audio.detectionLock);
1142+
item = iscapture ? current_audio.inputDevices : current_audio.outputDevices;
1143+
i = iscapture ? current_audio.inputDeviceCount : current_audio.outputDeviceCount;
1144+
if (index < i) {
1145+
for (i--; i > index; i--, item = item->next) {
1146+
SDL_assert(item != NULL);
1147+
}
1148+
SDL_assert(item != NULL);
1149+
SDL_memcpy(spec, &item->spec, sizeof(SDL_AudioSpec));
1150+
}
1151+
SDL_UnlockMutex(current_audio.detectionLock);
1152+
}
1153+
1154+
return 0;
1155+
}
1156+
1157+
11151158
static void
11161159
close_audio_device(SDL_AudioDevice * device)
11171160
{

src/audio/SDL_audiodev.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,13 @@ test_device(const int iscapture, const char *fname, int flags, int (*test) (int
5959
static size_t dummyhandle = 0;
6060
dummyhandle++;
6161
SDL_assert(dummyhandle != 0);
62-
SDL_AddAudioDevice(iscapture, fname, (void *) dummyhandle);
62+
63+
/* Note that spec is NULL; while we are opening the device
64+
* endpoint here, the endpoint does not provide any mix format
65+
* information, making this information inaccessible at
66+
* enumeration time
67+
*/
68+
SDL_AddAudioDevice(iscapture, fname, NULL, (void *) dummyhandle);
6369
}
6470
}
6571
}

src/audio/SDL_sysaudio.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ typedef struct SDL_AudioDevice SDL_AudioDevice;
3939
/* Audio targets should call this as devices are added to the system (such as
4040
a USB headset being plugged in), and should also be called for
4141
for every device found during DetectDevices(). */
42-
extern void SDL_AddAudioDevice(const int iscapture, const char *name, void *handle);
42+
extern void SDL_AddAudioDevice(const int iscapture, const char *name, SDL_AudioSpec *spec, void *handle);
4343

4444
/* Audio targets should call this as devices are removed, so SDL can update
4545
its list of available devices. */
@@ -99,6 +99,7 @@ typedef struct SDL_AudioDeviceItem
9999
void *handle;
100100
char *name;
101101
char *original_name;
102+
SDL_AudioSpec spec;
102103
int dupenum;
103104
struct SDL_AudioDeviceItem *next;
104105
} SDL_AudioDeviceItem;

src/audio/alsa/SDL_alsa_audio.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -765,7 +765,11 @@ add_device(const int iscapture, const char *name, void *hint, ALSA_Device **pSee
765765
return;
766766
}
767767

768-
SDL_AddAudioDevice(iscapture, desc, handle);
768+
/* Note that spec is NULL, because we are required to open the device before
769+
* acquiring the mix format, making this information inaccessible at
770+
* enumeration time
771+
*/
772+
SDL_AddAudioDevice(iscapture, desc, NULL, handle);
769773
if (hint)
770774
free(desc);
771775
dev->name = handle;

src/audio/coreaudio/SDL_coreaudio.m

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
kAudioObjectPropertyElementMaster
5757
};
5858

59-
typedef void (*addDevFn)(const char *name, const int iscapture, AudioDeviceID devId, void *data);
59+
typedef void (*addDevFn)(const char *name, SDL_AudioSpec *spec, const int iscapture, AudioDeviceID devId, void *data);
6060

6161
typedef struct AudioDeviceList
6262
{
@@ -88,10 +88,10 @@
8888
}
8989

9090
static void
91-
addToDevList(const char *name, const int iscapture, AudioDeviceID devId, void *data)
91+
addToDevList(const char *name, SDL_AudioSpec *spec, const int iscapture, AudioDeviceID devId, void *data)
9292
{
9393
if (add_to_internal_dev_list(iscapture, devId)) {
94-
SDL_AddAudioDevice(iscapture, name, (void *) ((size_t) devId));
94+
SDL_AddAudioDevice(iscapture, name, spec, (void *) ((size_t) devId));
9595
}
9696
}
9797

@@ -126,17 +126,23 @@
126126
AudioBufferList *buflist = NULL;
127127
int usable = 0;
128128
CFIndex len = 0;
129+
double sampleRate = 0;
130+
SDL_AudioSpec spec;
129131
const AudioObjectPropertyAddress addr = {
130132
kAudioDevicePropertyStreamConfiguration,
131133
iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
132134
kAudioObjectPropertyElementMaster
133135
};
134-
135136
const AudioObjectPropertyAddress nameaddr = {
136137
kAudioObjectPropertyName,
137138
iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
138139
kAudioObjectPropertyElementMaster
139140
};
141+
const AudioObjectPropertyAddress freqaddr = {
142+
kAudioDevicePropertyNominalSampleRate,
143+
iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
144+
kAudioObjectPropertyElementMaster
145+
};
140146

141147
result = AudioObjectGetPropertyDataSize(dev, &addr, 0, NULL, &size);
142148
if (result != noErr)
@@ -149,21 +155,24 @@
149155
result = AudioObjectGetPropertyData(dev, &addr, 0, NULL,
150156
&size, buflist);
151157

158+
SDL_zero(spec);
152159
if (result == noErr) {
153160
UInt32 j;
154161
for (j = 0; j < buflist->mNumberBuffers; j++) {
155-
if (buflist->mBuffers[j].mNumberChannels > 0) {
156-
usable = 1;
157-
break;
158-
}
162+
spec.channels += buflist->mBuffers[j].mNumberChannels;
159163
}
160164
}
161165

162166
SDL_free(buflist);
163167

164-
if (!usable)
168+
if (spec.channels == 0)
165169
continue;
166170

171+
size = sizeof (sampleRate);
172+
result = AudioObjectGetPropertyData(dev, &freqaddr, 0, NULL, &size, &sampleRate);
173+
if (result == noErr) {
174+
spec.freq = (int) sampleRate;
175+
}
167176

168177
size = sizeof (CFStringRef);
169178
result = AudioObjectGetPropertyData(dev, &nameaddr, 0, NULL, &size, &cfstr);
@@ -197,7 +206,7 @@
197206
((iscapture) ? "capture" : "output"),
198207
(int) i, ptr, (int) dev);
199208
#endif
200-
addfn(ptr, iscapture, dev, addfndata);
209+
addfn(ptr, &spec, iscapture, dev, addfndata);
201210
}
202211
SDL_free(ptr); /* addfn() would have copied the string. */
203212
}
@@ -223,7 +232,7 @@
223232
}
224233

225234
static void
226-
build_device_change_list(const char *name, const int iscapture, AudioDeviceID devId, void *data)
235+
build_device_change_list(const char *name, SDL_AudioSpec *spec, const int iscapture, AudioDeviceID devId, void *data)
227236
{
228237
AudioDeviceList **list = (AudioDeviceList **) data;
229238
AudioDeviceList *item;
@@ -235,7 +244,7 @@
235244
}
236245

237246
add_to_internal_dev_list(iscapture, devId); /* new device, add it. */
238-
SDL_AddAudioDevice(iscapture, name, (void *) ((size_t) devId));
247+
SDL_AddAudioDevice(iscapture, name, spec, (void *) ((size_t) devId));
239248
}
240249

241250
static void

src/audio/directsound/SDL_directsound.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,12 @@ FindAllDevs(LPGUID guid, LPCWSTR desc, LPCWSTR module, LPVOID data)
163163
if (str != NULL) {
164164
LPGUID cpyguid = (LPGUID) SDL_malloc(sizeof (GUID));
165165
SDL_memcpy(cpyguid, guid, sizeof (GUID));
166-
SDL_AddAudioDevice(iscapture, str, cpyguid);
166+
167+
/* Note that spec is NULL, because we are required to connect to the
168+
* device before getting the channel mask and output format, making
169+
* this information inaccessible at enumeration time
170+
*/
171+
SDL_AddAudioDevice(iscapture, str, NULL, cpyguid);
167172
SDL_free(str); /* addfn() makes a copy of this string. */
168173
}
169174
}

src/audio/disk/SDL_diskaudio.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,8 @@ DISKAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
173173
static void
174174
DISKAUDIO_DetectDevices(void)
175175
{
176-
SDL_AddAudioDevice(SDL_FALSE, DEFAULT_OUTPUT_DEVNAME, (void *) 0x1);
177-
SDL_AddAudioDevice(SDL_TRUE, DEFAULT_INPUT_DEVNAME, (void *) 0x2);
176+
SDL_AddAudioDevice(SDL_FALSE, DEFAULT_OUTPUT_DEVNAME, NULL, (void *) 0x1);
177+
SDL_AddAudioDevice(SDL_TRUE, DEFAULT_INPUT_DEVNAME, NULL, (void *) 0x2);
178178
}
179179

180180
static int

src/audio/os2/SDL_os2audio.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,9 +160,9 @@ static void OS2_DetectDevices(void)
160160
}
161161

162162
ulHandle++;
163-
SDL_AddAudioDevice(0, stLogDevice.szProductInfo, (void *)(ulHandle));
163+
SDL_AddAudioDevice(0, stLogDevice.szProductInfo, NULL, (void *)(ulHandle));
164164
ulHandle++;
165-
SDL_AddAudioDevice(1, stLogDevice.szProductInfo, (void *)(ulHandle));
165+
SDL_AddAudioDevice(1, stLogDevice.szProductInfo, NULL, (void *)(ulHandle));
166166
}
167167
}
168168

src/audio/pipewire/SDL_pipewire.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ io_list_check_add(struct io_node *node)
266266
spa_list_append(&hotplug_io_list, &node->link);
267267

268268
if (SDL_AtomicGet(&hotplug_events_enabled)) {
269-
SDL_AddAudioDevice(node->is_capture, node->name, PW_ID_TO_HANDLE(node->id));
269+
SDL_AddAudioDevice(node->is_capture, node->name, &node->spec, PW_ID_TO_HANDLE(node->id));
270270
}
271271

272272
dup_found:
@@ -768,7 +768,7 @@ PIPEWIRE_DetectDevices()
768768
io_list_sort();
769769

770770
spa_list_for_each (io, &hotplug_io_list, link) {
771-
SDL_AddAudioDevice(io->is_capture, io->name, PW_ID_TO_HANDLE(io->id));
771+
SDL_AddAudioDevice(io->is_capture, io->name, &io->spec, PW_ID_TO_HANDLE(io->id));
772772
}
773773

774774
SDL_AtomicSet(&hotplug_events_enabled, 1);

0 commit comments

Comments
 (0)