From 40893821f2b9e9826ec12e7c879cfb2d14ac5068 Mon Sep 17 00:00:00 2001
From: Jarod Hillman <[EMAIL REDACTED]>
Date: Thu, 29 Sep 2022 10:33:07 -0400
Subject: [PATCH] coreaudio: Add support for SDL_GetDefaultAudioInfo (#6277)
Co-authored-by: Ethan Lee <flibitijibibo@gmail.com>
Co-authored-by: Ozkan Sezer <sezeroz@gmail.com>
---
src/audio/coreaudio/SDL_coreaudio.m | 136 ++++++++++++++++++++++++++++
test/testaudioinfo.c | 23 +++++
2 files changed, 159 insertions(+)
diff --git a/src/audio/coreaudio/SDL_coreaudio.m b/src/audio/coreaudio/SDL_coreaudio.m
index de8f72106190..1a6871904d8f 100644
--- a/src/audio/coreaudio/SDL_coreaudio.m
+++ b/src/audio/coreaudio/SDL_coreaudio.m
@@ -1151,6 +1151,141 @@ output device (in which case we'll try again). */
return (this->hidden->thread != NULL) ? 0 : -1;
}
+#if !MACOSX_COREAUDIO
+static int
+COREAUDIO_GetDefaultAudioInfo(char **name, SDL_AudioSpec *spec, int iscapture)
+{
+ AVAudioSession* session = [AVAudioSession sharedInstance];
+
+ if (name != NULL) {
+ *name = NULL;
+ }
+ SDL_zerop(spec);
+ spec->freq = [session sampleRate];
+ spec->channels = [session outputNumberOfChannels];
+ return 0;
+}
+#else /* MACOSX_COREAUDIO */
+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");
+ }
+
+ if (name != NULL) {
+ /* 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';
+ }
+ *name = devname;
+ }
+
+ /* Uses the Device ID to get the spec */
+ SDL_zerop(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;
+}
+#endif /* MACOSX_COREAUDIO */
+
static void
COREAUDIO_Deinitialize(void)
{
@@ -1168,6 +1303,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/testaudioinfo.c b/test/testaudioinfo.c
index d22aed270285..6f1e0c75dbf8 100644
--- a/test/testaudioinfo.c
+++ b/test/testaudioinfo.c
@@ -40,6 +40,8 @@ print_devices(int iscapture)
int
main(int argc, char **argv)
{
+ char *deviceName;
+ SDL_AudioSpec spec;
int n;
/* Enable standard application logging */
@@ -69,6 +71,27 @@ main(int argc, char **argv)
print_devices(0);
print_devices(1);
+ if (SDL_GetDefaultAudioInfo(&deviceName, &spec, 0) < 0) {
+ SDL_Log("Error when calling SDL_GetDefaultAudioInfo: %s\n", SDL_GetError());
+ } else {
+ SDL_Log("Default Output Name: %s\n", deviceName != NULL ? deviceName : "unknown");
+ SDL_free(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);
+ }
+
+ if (SDL_GetDefaultAudioInfo(&deviceName, &spec, 1) < 0) {
+ SDL_Log("Error when calling SDL_GetDefaultAudioInfo: %s\n", SDL_GetError());
+ } else {
+ SDL_Log("Default Capture Name: %s\n", deviceName != NULL ? deviceName : "unknown");
+ SDL_free(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_Quit();
return 0;
}