From 40893821f2b9e9826ec12e7c879cfb2d14ac5068 Mon Sep 17 00:00:00 2001 From: Jarod Hillman Date: Thu, 29 Sep 2022 10:33:07 -0400 Subject: [PATCH] coreaudio: Add support for SDL_GetDefaultAudioInfo (#6277) Co-authored-by: Ethan Lee Co-authored-by: Ozkan Sezer --- 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 de8f72106..1a6871904 100644 --- a/src/audio/coreaudio/SDL_coreaudio.m +++ b/src/audio/coreaudio/SDL_coreaudio.m @@ -1151,6 +1151,141 @@ COREAUDIO_OpenDevice(_THIS, const char *devname) 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 @@ COREAUDIO_Init(SDL_AudioDriverImpl * impl) 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 d22aed270..6f1e0c75d 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; }