From 52534bb800bd726564c26fc3308634756a53dadf Mon Sep 17 00:00:00 2001
From: Jarod Hillman <[EMAIL REDACTED]>
Date: Fri, 23 Sep 2022 16:16:28 -0400
Subject: [PATCH] Add macOS coreaudio support for SDL_GetDefaultAudioInfo
---
src/audio/coreaudio/SDL_coreaudio.m | 126 ++++++++++++++++++++++++++++
test/testsurround.c | 24 ++++++
2 files changed, 150 insertions(+)
diff --git a/src/audio/coreaudio/SDL_coreaudio.m b/src/audio/coreaudio/SDL_coreaudio.m
index 4d35756579d4..34a0a18afb30 100644
--- a/src/audio/coreaudio/SDL_coreaudio.m
+++ b/src/audio/coreaudio/SDL_coreaudio.m
@@ -1145,6 +1145,131 @@ output device (in which case we'll try again). */
return (this->hidden->thread != NULL) ? 0 : -1;
}
+static int
+COREAUDIO_GetDefaultAudioInfo(char **name, SDL_AudioSpec *spec, int iscapture)
+{
+ AudioDeviceID devid;
+ AudioBufferList *buflist;
+ OSStatus result;
+ UInt32 size;
+ CFStringRef cfstr;
+ char *devname;
+ int usable;
+ double sampleRate;
+
+ AudioObjectPropertyAddress addr = {
+ iscapture ? kAudioHardwarePropertyDefaultInputDevice
+ : kAudioHardwarePropertyDefaultOutputDevice,
+ iscapture ? kAudioDevicePropertyScopeInput
+ : kAudioDevicePropertyScopeOutput,
+ kAudioObjectPropertyElementMaster
+ };
+
+ AudioObjectPropertyAddress nameaddr = {
+ kAudioObjectPropertyName,
+ iscapture ? kAudioDevicePropertyScopeInput
+ : kAudioDevicePropertyScopeOutput,
+ kAudioObjectPropertyElementMaster
+ };
+
+ AudioObjectPropertyAddress freqaddr = {
+ kAudioDevicePropertyNominalSampleRate,
+ iscapture ? kAudioDevicePropertyScopeInput
+ : kAudioDevicePropertyScopeOutput,
+ kAudioObjectPropertyElementMaster
+ };
+
+ AudioObjectPropertyAddress bufaddr = {
+ kAudioDevicePropertyStreamConfiguration,
+ iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
+ kAudioObjectPropertyElementMaster
+ };
+
+ // Get the Device ID
+ cfstr = NULL;
+ size = sizeof (AudioDeviceID);
+ result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr,
+ 0, NULL, &size, &devid);
+
+ if (result != noErr) {
+ return SDL_SetError("%s: Default Device ID not found", "coreaudio");
+ }
+
+
+ // Use the Device ID to get the name
+ size = sizeof (CFStringRef);
+ result = AudioObjectGetPropertyData(devid, &nameaddr, 0, NULL, &size, &cfstr);
+
+ if (result != noErr) {
+ return SDL_SetError("%s: Default Device Name not found", "coreaudio");
+ }
+
+ CFIndex len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfstr),
+ kCFStringEncodingUTF8);
+
+ devname = (char *) SDL_malloc(len + 1);
+ usable = ((devname != NULL) &&
+ (CFStringGetCString(cfstr, devname, len + 1, kCFStringEncodingUTF8)));
+ CFRelease(cfstr);
+
+ if (usable) {
+ usable = 0;
+ len = strlen(devname);
+ /* Some devices have whitespace at the end...trim it. */
+ while ((len > 0) && (devname[len - 1] == ' ')) {
+ len--;
+ usable = len;
+ }
+ }
+
+ if (usable) {
+ devname[len] = '\0';
+ }
+
+ if (name) {
+ *name = devname;
+ }
+
+ // Uses the Device ID to get the spec
+ SDL_zero(*spec);
+
+ sampleRate = 0;
+ size = sizeof(sampleRate);
+ result = AudioObjectGetPropertyData(devid, &freqaddr, 0, NULL, &size, &sampleRate);
+
+ if (result != noErr) {
+ return SDL_SetError("%s: Default Device Sample Rate not found", "coreaudio");
+ }
+
+ spec->freq = (int) sampleRate;
+
+ result = AudioObjectGetPropertyDataSize(devid, &bufaddr, 0, NULL, &size);
+ if (result != noErr)
+ return SDL_SetError("%s: Default Device Data Size not found", "coreaudio");
+
+ buflist = (AudioBufferList *) SDL_malloc(size);
+ if (buflist == NULL)
+ return SDL_SetError("%s: Default Device Buffer List not found", "coreaudio");
+
+ result = AudioObjectGetPropertyData(devid, &bufaddr, 0, NULL,
+ &size, buflist);
+
+ if (result == noErr) {
+ UInt32 j;
+ for (j = 0; j < buflist->mNumberBuffers; j++) {
+ spec->channels += buflist->mBuffers[j].mNumberChannels;
+ }
+ }
+
+ SDL_free(buflist);
+
+ if (spec->channels == 0) {
+ return SDL_SetError("%s: Default Device has no channels!", "coreaudio");
+ }
+
+ return 0;
+}
+
static void
COREAUDIO_Deinitialize(void)
{
@@ -1162,6 +1287,7 @@ output device (in which case we'll try again). */
impl->OpenDevice = COREAUDIO_OpenDevice;
impl->CloseDevice = COREAUDIO_CloseDevice;
impl->Deinitialize = COREAUDIO_Deinitialize;
+ impl->GetDefaultAudioInfo = COREAUDIO_GetDefaultAudioInfo;
#if MACOSX_COREAUDIO
impl->DetectDevices = COREAUDIO_DetectDevices;
diff --git a/test/testsurround.c b/test/testsurround.c
index 1537b35fe223..ff55af7b34ba 100644
--- a/test/testsurround.c
+++ b/test/testsurround.c
@@ -135,6 +135,8 @@ fill_buffer(void* unused, Uint8* stream, int len)
int
main(int argc, char *argv[])
{
+ char *deviceName;
+ SDL_AudioSpec spec;
int i;
/* Enable standard application logging */
@@ -199,6 +201,28 @@ main(int argc, char *argv[])
SDL_CloseAudioDevice(dev);
}
+ if (SDL_GetDefaultAudioInfo(&deviceName, &spec, 0)) {
+ SDL_Log("Error when calling SDL_GetDefaultAudioInfo: %s\n", SDL_GetError());
+ } else {
+ SDL_Log("Default audio output info found!\n");
+ SDL_Log("Name: %s\n", deviceName);
+ SDL_Log("Sampling Rate: %d\n", spec.freq);
+ SDL_Log("Number of Channels: %d\n", spec.channels);
+ SDL_Log("Audio Format: %d\n", spec.format);
+ SDL_free(deviceName);
+ }
+
+ if (SDL_GetDefaultAudioInfo(&deviceName, &spec, 1)) {
+ SDL_Log("Error when calling SDL_GetDefaultAudioInfo: %s\n", SDL_GetError());
+ } else {
+ SDL_Log("Default audio capture info found!\n");
+ SDL_Log("Name: %s\n", deviceName);
+ SDL_Log("Sampling Rate: %d\n", spec.freq);
+ SDL_Log("Number of Channels: %d\n", spec.channels);
+ SDL_Log("Audio Format: %d\n", spec.format);
+ SDL_free(deviceName);
+ }
+
SDL_Quit();
return 0;
}