From c653e57768aa78ac93d58e380b98d1706dd0d355 Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Mon, 3 Jul 2023 22:00:58 -0400
Subject: [PATCH] coreaudio: rewritten for SDL3 audio redesign!
---
src/audio/coreaudio/SDL_coreaudio.h | 5 +-
src/audio/coreaudio/SDL_coreaudio.m | 1048 +++++++++------------------
2 files changed, 350 insertions(+), 703 deletions(-)
diff --git a/src/audio/coreaudio/SDL_coreaudio.h b/src/audio/coreaudio/SDL_coreaudio.h
index 989ed61d2316..4b7f81bf0671 100644
--- a/src/audio/coreaudio/SDL_coreaudio.h
+++ b/src/audio/coreaudio/SDL_coreaudio.h
@@ -53,15 +53,12 @@ struct SDL_PrivateAudioData
AudioQueueRef audioQueue;
int numAudioBuffers;
AudioQueueBufferRef *audioBuffer;
- void *buffer;
- UInt32 bufferOffset;
- UInt32 bufferSize;
+ AudioQueueBufferRef current_buffer;
AudioStreamBasicDescription strdesc;
SDL_Semaphore *ready_semaphore;
char *thread_error;
#ifdef MACOSX_COREAUDIO
AudioDeviceID deviceID;
- SDL_AtomicInt device_change_flag;
#else
SDL_bool interrupted;
CFTypeRef interruption_listener;
diff --git a/src/audio/coreaudio/SDL_coreaudio.m b/src/audio/coreaudio/SDL_coreaudio.m
index 20ac3bf5df7c..bd05c1a10ced 100644
--- a/src/audio/coreaudio/SDL_coreaudio.m
+++ b/src/audio/coreaudio/SDL_coreaudio.m
@@ -22,28 +22,24 @@
#ifdef SDL_AUDIO_DRIVER_COREAUDIO
-/* !!! FIXME: clean out some of the macro salsa in here. */
-
#include "../SDL_audio_c.h"
#include "../SDL_sysaudio.h"
#include "SDL_coreaudio.h"
#include "../../thread/SDL_systhread.h"
-#define DEBUG_COREAUDIO 0
+#define DEBUG_COREAUDIO 1
#if DEBUG_COREAUDIO
-#define CHECK_RESULT(msg) \
- if (result != noErr) { \
- printf("COREAUDIO: Got error %d from '%s'!\n", (int)result, msg); \
- SDL_SetError("CoreAudio error (%s): %d", msg, (int)result); \
- return 0; \
- }
+ #define CHECK_RESULT(msg) \
+ if (result != noErr) { \
+ SDL_Log("COREAUDIO: Got error %d from '%s'!\n", (int)result, msg); \
+ return SDL_SetError("CoreAudio error (%s): %d", msg, (int)result); \
+ }
#else
-#define CHECK_RESULT(msg) \
- if (result != noErr) { \
- SDL_SetError("CoreAudio error (%s): %d", msg, (int)result); \
- return 0; \
- }
+ #define CHECK_RESULT(msg) \
+ if (result != noErr) { \
+ return SDL_SetError("CoreAudio error (%s): %d", msg, (int)result); \
+ }
#endif
#ifdef MACOSX_COREAUDIO
@@ -53,78 +49,84 @@
kAudioObjectPropertyElementMain
};
-typedef void (*addDevFn)(const char *name, SDL_AudioSpec *spec, const int iscapture, AudioDeviceID devId, void *data);
+static const AudioObjectPropertyAddress default_output_device_address = {
+ kAudioHardwarePropertyDefaultOutputDevice,
+ kAudioObjectPropertyScopeGlobal,
+ kAudioObjectPropertyElementMain
+};
-typedef struct AudioDeviceList
-{
- AudioDeviceID devid;
- SDL_bool alive;
- struct AudioDeviceList *next;
-} AudioDeviceList;
+static const AudioObjectPropertyAddress default_input_device_address = {
+ kAudioHardwarePropertyDefaultInputDevice,
+ kAudioObjectPropertyScopeGlobal,
+ kAudioObjectPropertyElementMain
+};
+
+static const AudioObjectPropertyAddress alive_address = {
+ kAudioDevicePropertyDeviceIsAlive,
+ kAudioObjectPropertyScopeGlobal,
+ kAudioObjectPropertyElementMain
+};
-static AudioDeviceList *output_devs = NULL;
-static AudioDeviceList *capture_devs = NULL;
-static SDL_bool add_to_internal_dev_list(const int iscapture, AudioDeviceID devId)
+static OSStatus DeviceAliveNotification(AudioObjectID devid, UInt32 num_addr, const AudioObjectPropertyAddress *addrs, void *data)
{
- AudioDeviceList *item = (AudioDeviceList *)SDL_malloc(sizeof(AudioDeviceList));
- if (item == NULL) {
- return SDL_FALSE;
+ SDL_AudioDevice *device = (SDL_AudioDevice *)data;
+ SDL_assert(((AudioObjectID)(size_t)device->handle) == devid);
+
+ UInt32 alive = 1;
+ UInt32 size = sizeof(alive);
+ const OSStatus error = AudioObjectGetPropertyData(devid, addrs, 0, NULL, &size, &alive);
+
+ SDL_bool dead = SDL_FALSE;
+ if (error == kAudioHardwareBadDeviceError) {
+ dead = SDL_TRUE; /* device was unplugged. */
+ } else if ((error == kAudioHardwareNoError) && (!alive)) {
+ dead = SDL_TRUE; /* device died in some other way. */
}
- item->devid = devId;
- item->alive = SDL_TRUE;
- item->next = iscapture ? capture_devs : output_devs;
- if (iscapture) {
- capture_devs = item;
- } else {
- output_devs = item;
+
+ if (dead) {
+ #if DEBUG_COREAUDIO
+ SDL_Log("COREAUDIO: device '%s' is lost!", device->name);
+ #endif
+ SDL_AudioDeviceDisconnected(device);
}
- return SDL_TRUE;
+ return noErr;
}
-static void addToDevList(const char *name, SDL_AudioSpec *spec, const int iscapture, AudioDeviceID devId, void *data)
+static void COREAUDIO_FreeDeviceHandle(SDL_AudioDevice *device)
{
- if (add_to_internal_dev_list(iscapture, devId)) {
- SDL_AddAudioDevice(iscapture, name, spec, (void *)((size_t)devId));
- }
+ const AudioDeviceID devid = (AudioDeviceID)(size_t)device->handle;
+ AudioObjectRemovePropertyListener(devid, &alive_address, DeviceAliveNotification, device);
}
-static void build_device_list(int iscapture, addDevFn addfn, void *addfndata)
+// This only _adds_ new devices. Removal is handled by devices triggering kAudioDevicePropertyDeviceIsAlive property changes.
+static void RefreshPhysicalDevices(void)
{
- OSStatus result = noErr;
UInt32 size = 0;
AudioDeviceID *devs = NULL;
- UInt32 i = 0;
- UInt32 max = 0;
+ SDL_bool isstack;
- result = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject,
- &devlist_address, 0, NULL, &size);
- if (result != kAudioHardwareNoError) {
+ if (AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &devlist_address, 0, NULL, &size) != kAudioHardwareNoError) {
return;
- }
-
- devs = (AudioDeviceID *)alloca(size);
- if (devs == NULL) {
+ } else if ((devs = (AudioDeviceID *) SDL_small_alloc(Uint8, size, &isstack)) == NULL) {
+ return;
+ } else if (AudioObjectGetPropertyData(kAudioObjectSystemObject, &devlist_address, 0, NULL, &size, devs) != kAudioHardwareNoError) {
+ SDL_small_free(devs, isstack);
return;
}
- result = AudioObjectGetPropertyData(kAudioObjectSystemObject,
- &devlist_address, 0, NULL, &size, devs);
- if (result != kAudioHardwareNoError) {
- return;
+ const UInt32 total_devices = (UInt32) (size / sizeof(AudioDeviceID));
+ for (UInt32 i = 0; i < total_devices; i++) {
+ SDL_AudioDevice *device = SDL_ObtainPhysicalAudioDeviceByHandle((void *)((size_t)devs[i]));
+ if (device) {
+ SDL_UnlockMutex(device->lock);
+ devs[i] = 0; // The system and SDL both agree it's already here, don't check it again.
+ }
}
- max = size / sizeof(AudioDeviceID);
- for (i = 0; i < max; i++) {
- CFStringRef cfstr = NULL;
- char *ptr = NULL;
- AudioDeviceID dev = devs[i];
- AudioBufferList *buflist = NULL;
- int usable = 0;
- CFIndex len = 0;
- double sampleRate = 0;
- SDL_AudioSpec spec;
+ // any non-zero items remaining in `devs` are new devices to be added.
+ for (int iscapture = 0; iscapture < 2; iscapture++) {
const AudioObjectPropertyAddress addr = {
kAudioDevicePropertyStreamConfiguration,
iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
@@ -141,165 +143,167 @@ static void build_device_list(int iscapture, addDevFn addfn, void *addfndata)
kAudioObjectPropertyElementMain
};
- result = AudioObjectGetPropertyDataSize(dev, &addr, 0, NULL, &size);
- if (result != noErr) {
- continue;
- }
-
- buflist = (AudioBufferList *)SDL_malloc(size);
- if (buflist == NULL) {
- continue;
- }
+ for (UInt32 i = 0; i < total_devices; i++) {
+ const AudioDeviceID dev = devs[i];
+ if (!dev) {
+ continue; // already added.
+ }
- result = AudioObjectGetPropertyData(dev, &addr, 0, NULL,
- &size, buflist);
+ AudioBufferList *buflist = NULL;
+ double sampleRate = 0;
- SDL_zero(spec);
- if (result == noErr) {
- UInt32 j;
- for (j = 0; j < buflist->mNumberBuffers; j++) {
- spec.channels += buflist->mBuffers[j].mNumberChannels;
+ if (AudioObjectGetPropertyDataSize(dev, &addr, 0, NULL, &size) != noErr) {
+ continue;
+ } else if ((buflist = (AudioBufferList *)SDL_malloc(size)) == NULL) {
+ continue;
}
- }
- SDL_free(buflist);
+ OSStatus result = AudioObjectGetPropertyData(dev, &addr, 0, NULL, &size, buflist);
- if (spec.channels == 0) {
- continue;
- }
+ SDL_AudioSpec spec;
+ SDL_zero(spec);
+ if (result == noErr) {
+ for (Uint32 j = 0; j < buflist->mNumberBuffers; j++) {
+ spec.channels += buflist->mBuffers[j].mNumberChannels;
+ }
+ }
- size = sizeof(sampleRate);
- result = AudioObjectGetPropertyData(dev, &freqaddr, 0, NULL, &size, &sampleRate);
- if (result == noErr) {
- spec.freq = (int)sampleRate;
- }
+ SDL_free(buflist);
- size = sizeof(CFStringRef);
- result = AudioObjectGetPropertyData(dev, &nameaddr, 0, NULL, &size, &cfstr);
- if (result != kAudioHardwareNoError) {
- continue;
- }
+ if (spec.channels == 0) {
+ continue;
+ }
+
+ size = sizeof(sampleRate);
+ if (AudioObjectGetPropertyData(dev, &freqaddr, 0, NULL, &size, &sampleRate) == noErr) {
+ spec.freq = (int)sampleRate;
+ }
- len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfstr),
- kCFStringEncodingUTF8);
+ CFStringRef cfstr = NULL;
+ size = sizeof(CFStringRef);
+ if (AudioObjectGetPropertyData(dev, &nameaddr, 0, NULL, &size, &cfstr) != kAudioHardwareNoError) {
+ continue;
+ }
- ptr = (char *)SDL_malloc(len + 1);
- usable = ((ptr != NULL) &&
- (CFStringGetCString(cfstr, ptr, len + 1, kCFStringEncodingUTF8)));
+ CFIndex len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfstr), kCFStringEncodingUTF8);
+ char *name = (char *)SDL_malloc(len + 1);
+ SDL_bool usable = ((name != NULL) && (CFStringGetCString(cfstr, name, len + 1, kCFStringEncodingUTF8))) ? SDL_TRUE : SDL_FALSE;
- CFRelease(cfstr);
+ CFRelease(cfstr);
- if (usable) {
- len = SDL_strlen(ptr);
- /* Some devices have whitespace at the end...trim it. */
- while ((len > 0) && (ptr[len - 1] == ' ')) {
- len--;
+ if (usable) {
+ // Some devices have whitespace at the end...trim it.
+ len = (CFIndex) SDL_strlen(name);
+ while ((len > 0) && (name[len - 1] == ' ')) {
+ len--;
+ }
+ usable = (len > 0);
}
- usable = (len > 0);
- }
- if (usable) {
- ptr[len] = '\0';
+ if (usable) {
+ name[len] = '\0';
-#if DEBUG_COREAUDIO
- printf("COREAUDIO: Found %s device #%d: '%s' (devid %d)\n",
- ((iscapture) ? "capture" : "output"),
- (int)i, ptr, (int)dev);
-#endif
- addfn(ptr, &spec, iscapture, dev, addfndata);
+ #if DEBUG_COREAUDIO
+ SDL_Log("COREAUDIO: Found %s device #%d: '%s' (devid %d)\n",
+ ((iscapture) ? "capture" : "output"),
+ (int)i, name, (int)dev);
+ #endif
+
+ devs[i] = 0; // don't bother checking this one on the next iscapture iteration of the loop
+
+ SDL_AudioDevice *device = SDL_AddAudioDevice(iscapture ? SDL_TRUE : SDL_FALSE, name, &spec, (void *)((size_t)dev));
+ if (device) {
+ AudioObjectAddPropertyListener(dev, &alive_address, DeviceAliveNotification, device);
+ }
+ }
+ SDL_free(name); // SDL_AddAudioDevice() would have copied the string.
}
- SDL_free(ptr); /* addfn() would have copied the string. */
}
-}
-static void free_audio_device_list(AudioDeviceList **list)
-{
- AudioDeviceList *item = *list;
- while (item) {
- AudioDeviceList *next = item->next;
- SDL_free(item);
- item = next;
- }
- *list = NULL;
+ SDL_small_free(devs, isstack);
}
-static void COREAUDIO_DetectDevices(void)
+// this is called when the system's list of available audio devices changes.
+static OSStatus DeviceListChangedNotification(AudioObjectID systemObj, UInt32 num_addr, const AudioObjectPropertyAddress *addrs, void *data)
{
- build_device_list(SDL_TRUE, addToDevList, NULL);
- build_device_list(SDL_FALSE, addToDevList, NULL);
+ RefreshPhysicalDevices();
+ return noErr;
}
-static void build_device_change_list(const char *name, SDL_AudioSpec *spec, const int iscapture, AudioDeviceID devId, void *data)
+static OSStatus DefaultAudioDeviceChangedNotification(AudioObjectID inObjectID, const AudioObjectPropertyAddress *addr)
{
- AudioDeviceList **list = (AudioDeviceList **)data;
- AudioDeviceList *item;
- for (item = *list; item != NULL; item = item->next) {
- if (item->devid == devId) {
- item->alive = SDL_TRUE;
- return;
+ AudioDeviceID devid;
+ Uint32 size = sizeof(devid);
+ if (AudioObjectGetPropertyData(inObjectID, addr, 0, NULL, &size, &devid) == noErr) {
+ SDL_AudioDevice *device = SDL_ObtainPhysicalAudioDeviceByHandle((void *)((size_t)devid));
+ if (device) {
+ SDL_UnlockMutex(device->lock);
+ SDL_DefaultAudioDeviceChanged(device);
}
}
+ return noErr;
+}
- add_to_internal_dev_list(iscapture, devId); /* new device, add it. */
- SDL_AddAudioDevice(iscapture, name, spec, (void *)((size_t)devId));
+static OSStatus DefaultOutputDeviceChangedNotification(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, void *inUserData)
+{
+ #if DEBUG_COREAUDIO
+ SDL_Log("COREAUDIO: default output device changed!");
+ #endif
+ SDL_assert(inNumberAddresses == 1);
+ return DefaultAudioDeviceChangedNotification(inObjectID, inAddresses);
}
-static void reprocess_device_list(const int iscapture, AudioDeviceList **list)
+static OSStatus DefaultInputDeviceChangedNotification(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, void *inUserData)
{
- AudioDeviceList *item;
- AudioDeviceList *prev = NULL;
- for (item = *list; item != NULL; item = item->next) {
- item->alive = SDL_FALSE;
- }
+ #if DEBUG_COREAUDIO
+ SDL_Log("COREAUDIO: default input device changed!");
+ #endif
+ SDL_assert(inNumberAddresses == 1);
+ return DefaultAudioDeviceChangedNotification(inObjectID, inAddresses);
+}
+
+static void COREAUDIO_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture)
+{
+ RefreshPhysicalDevices();
- build_device_list(iscapture, build_device_change_list, list);
+ AudioObjectAddPropertyListener(kAudioObjectSystemObject, &devlist_address, DeviceListChangedNotification, NULL);
- /* free items in the list that aren't still alive. */
- item = *list;
- while (item != NULL) {
- AudioDeviceList *next = item->next;
- if (item->alive) {
- prev = item;
- } else {
- SDL_RemoveAudioDevice(iscapture, (void *)((size_t)item->devid));
- if (prev) {
- prev->next = item->next;
- } else {
- *list = item->next;
- }
- SDL_free(item);
+ /* Get the Device ID */
+ UInt32 size;
+ AudioDeviceID devid;
+
+ size = sizeof(AudioDeviceID);
+ if (AudioObjectGetPropertyData(kAudioObjectSystemObject, &default_output_device_address, 0, NULL, &size, &devid) == noErr) {
+ SDL_AudioDevice *device = SDL_ObtainPhysicalAudioDeviceByHandle((void *)((size_t)devid));
+ if (device) {
+ SDL_UnlockMutex(device->lock);
+ *default_output = device;
}
- item = next;
}
-}
+ AudioObjectAddPropertyListener(kAudioObjectSystemObject, &default_output_device_address, DefaultOutputDeviceChangedNotification, NULL);
-/* this is called when the system's list of available audio devices changes. */
-static OSStatus device_list_changed(AudioObjectID systemObj, UInt32 num_addr, const AudioObjectPropertyAddress *addrs, void *data)
-{
- reprocess_device_list(SDL_TRUE, &capture_devs);
- reprocess_device_list(SDL_FALSE, &output_devs);
- return 0;
+ size = sizeof(AudioDeviceID);
+ if (AudioObjectGetPropertyData(kAudioObjectSystemObject, &default_input_device_address, 0, NULL, &size, &devid) == noErr) {
+ SDL_AudioDevice *device = SDL_ObtainPhysicalAudioDeviceByHandle((void *)((size_t)devid));
+ if (device) {
+ SDL_UnlockMutex(device->lock);
+ *default_capture = device;
+ }
+ }
+ AudioObjectAddPropertyListener(kAudioObjectSystemObject, &default_input_device_address, DefaultInputDeviceChangedNotification, NULL);
}
-#endif
-static int open_playback_devices;
-static int open_capture_devices;
-static int num_open_devices;
-static SDL_AudioDevice **open_devices;
+#else // iOS-specific section follows.
-#ifndef MACOSX_COREAUDIO
+static SDL_bool session_active = SDL_FALSE;
-static BOOL session_active = NO;
-
-static void pause_audio_devices(void)
+static void PauseAudioDevices(void) // !!! FIXME: this needs to be updated, and we need a method to access SDL_audio.c's device lists.
{
- int i;
-
if (!open_devices) {
return;
}
- for (i = 0; i < num_open_devices; ++i) {
+ for (int i = 0; i < num_open_devices; ++i) {
SDL_AudioDevice *device = open_devices[i];
if (device->hidden->audioQueue && !device->hidden->interrupted) {
AudioQueuePause(device->hidden->audioQueue);
@@ -307,15 +311,13 @@ static void pause_audio_devices(void)
}
}
-static void resume_audio_devices(void)
+static void ResumeAudioDevices(void) // !!! FIXME: this needs to be updated, and we need a method to access SDL_audio.c's device lists.
{
- int i;
-
if (!open_devices) {
return;
}
- for (i = 0; i < num_open_devices; ++i) {
+ for (int i = 0; i < num_open_devices; ++i) {
SDL_AudioDevice *device = open_devices[i];
if (device->hidden->audioQueue && !device->hidden->interrupted) {
AudioQueueStart(device->hidden->audioQueue, NULL);
@@ -323,7 +325,7 @@ static void resume_audio_devices(void)
}
}
-static void interruption_begin(SDL_AudioDevice *device)
+static void InterruptionBegin(SDL_AudioDevice *device)
{
if (device != NULL && device->hidden->audioQueue != NULL) {
device->hidden->interrupted = SDL_TRUE;
@@ -331,7 +333,7 @@ static void interruption_begin(SDL_AudioDevice *device)
}
}
-static void interruption_end(SDL_AudioDevice *device)
+static void InterruptionEnd(SDL_AudioDevice *device)
{
if (device != NULL && device->hidden != NULL && device->hidden->audioQueue != NULL && device->hidden->interrupted && AudioQueueStart(device->hidden->audioQueue, NULL) == AVAudioSessionErrorCodeNone) {
device->hidden->interrupted = SDL_FALSE;
@@ -351,9 +353,9 @@ - (void)audioSessionInterruption:(NSNotification *)note
@synchronized(self) {
NSNumber *type = note.userInfo[AVAudioSessionInterruptionTypeKey];
if (type.unsignedIntegerValue == AVAudioSessionInterruptionTypeBegan) {
- interruption_begin(self.device);
+ InterruptionBegin(self.device);
} else {
- interruption_end(self.device);
+ InterruptionEnd(self.device);
}
}
}
@@ -361,13 +363,13 @@ - (void)audioSessionInterruption:(NSNotification *)note
- (void)applicationBecameActive:(NSNotification *)note
{
@synchronized(self) {
- interruption_end(self.device);
+ InterruptionEnd(self.device);
}
}
@end
-static BOOL update_audio_session(SDL_AudioDevice *device, SDL_bool open, SDL_bool allow_playandrecord)
+static SDL_bool UpdateAudioSession(SDL_AudioDevice *device, SDL_bool open, SDL_bool allow_playandrecord)
{
@autoreleasepool {
AVAudioSession *session = [AVAudioSession sharedInstance];
@@ -402,11 +404,11 @@ static BOOL update_audio_session(SDL_AudioDevice *device, SDL_bool open, SDL_boo
category = AVAudioSessionCategoryRecord;
}
-#if !TARGET_OS_TV
+ #if !TARGET_OS_TV
if (category == AVAudioSessionCategoryPlayAndRecord) {
options |= AVAudioSessionCategoryOptionDefaultToSpeaker;
}
-#endif
+ #endif
if (category == AVAudioSessionCategoryRecord ||
category == AVAudioSessionCategoryPlayAndRecord) {
/* AVAudioSessionCategoryOptionAllowBluetooth isn't available in the SDK for
@@ -426,27 +428,27 @@ static BOOL update_audio_session(SDL_AudioDevice *device, SDL_bool open, SDL_boo
if ([session respondsToSelector:@selector(setCategory:mode:options:error:)]) {
if (![session.category isEqualToString:category] || session.categoryOptions != options) {
/* Stop the current session so we don't interrupt other application audio */
- pause_audio_devices();
+ PauseAudioDevices();
[session setActive:NO error:nil];
- session_active = NO;
+ session_active = SDL_FALSE;
if (![session setCategory:category mode:mode options:options error:&err]) {
NSString *desc = err.description;
SDL_SetError("Could not set Audio Session category: %s", desc.UTF8String);
- return NO;
+ return SDL_FALSE;
}
}
} else {
if (![session.category isEqualToString:category]) {
/* Stop the current session so we don't interrupt other application audio */
- pause_audio_devices();
+ PauseAudioDevices();
[session setActive:NO error:nil];
- session_active = NO;
+ session_active = SDL_FALSE;
if (![session setCategory:category error:&err]) {
NSString *desc = err.description;
SDL_SetError("Could not set Audio Session category: %s", desc.UTF8String);
- return NO;
+ return SDL_FALSE;
}
}
}
@@ -455,19 +457,19 @@ static BOOL update_audio_session(SDL_AudioDevice *device, SDL_bool open, SDL_boo
if (![session setActive:YES error:&err]) {
if ([err code] == AVAudioSessionErrorCodeResourceNotAvailable &&
category == AVAudioSessionCategoryPlayAndRecord) {
- return update_audio_session(device, open, SDL_FALSE);
+ return UpdateAudioSession(device, open, SDL_FALSE);
}
NSString *desc = err.description;
SDL_SetError("Could not activate Audio Session: %s", desc.UTF8String);
- return NO;
+ return SDL_FALSE;
}
- session_active = YES;
- resume_audio_devices();
+ session_active = SDL_TRUE;
+ ResumeAudioDevices();
} else if (!open_playback_devices && !open_capture_devices && session_active) {
- pause_audio_devices();
+ PauseAudioDevices();
[session setActive:NO error:nil];
- session_active = NO;
+ session_active = SDL_FALSE;
}
if (open) {
@@ -504,191 +506,83 @@ static BOOL update_audio_session(SDL_AudioDevice *device, SDL_bool open, SDL_boo
}
}
- return YES;
+ return SDL_TRUE;
}
#endif
-/* The AudioQueue callback */
-static void outputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer)
-{
- SDL_AudioDevice *device = (SDL_AudioDevice *)inUserData;
-
- /* This flag is set before device->mixer_lock is destroyed during
- shutdown, so check it before grabbing the mutex, and then check it
- again _after_ in case we blocked waiting on the lock. */
- if (SDL_AtomicGet(&device->shutdown)) {
- return; /* don't do anything, since we don't even want to enqueue this buffer again. */
- }
-
- SDL_LockMutex(device->mixer_lock);
-
- if (SDL_AtomicGet(&device->shutdown)) {
- SDL_UnlockMutex(device->mixer_lock);
- return; /* don't do anything, since we don't even want to enqueue this buffer again. */
- }
-
- if (!SDL_AtomicGet(&device->enabled) || SDL_AtomicGet(&device->paused)) {
- /* Supply silence if audio is not enabled or paused */
- SDL_memset(inBuffer->mAudioData, device->spec.silence, inBuffer->mAudioDataBytesCapacity);
- } else if (device->stream) {
- UInt32 remaining = inBuffer->mAudioDataBytesCapacity;
- Uint8 *ptr = (Uint8 *)inBuffer->mAudioData;
-
- while (remaining > 0) {
- if (SDL_GetAudioStreamAvailable(device->stream) == 0) {
- /* Generate the data */
- (*device->callbackspec.callback)(device->callbackspec.userdata,
- device->hidden->buffer, device->hidden->bufferSize);
- device->hidden->bufferOffset = 0;
- SDL_PutAudioStreamData(device->stream, device->hidden->buffer, device->hidden->bufferSize);
- }
- if (SDL_GetAudioStreamAvailable(device->stream) > 0) {
- int got;
- UInt32 len = SDL_GetAudioStreamAvailable(device->stream);
- if (len > remaining) {
- len = remaining;
- }
- got = SDL_GetAudioStreamData(device->stream, ptr, len);
- SDL_assert((got < 0) || (got == len));
- if (got != len) {
- SDL_memset(ptr, device->spec.silence, len);
- }
- ptr = ptr + len;
- remaining -= len;
- }
- }
- } else {
- UInt32 remaining = inBuffer->mAudioDataBytesCapacity;
- Uint8 *ptr = (Uint8 *)inBuffer->mAudioData;
-
- while (remaining > 0) {
- UInt32 len;
- if (device->hidden->bufferOffset >= device->hidden->bufferSize) {
- /* Generate the data */
- (*device->callbackspec.callback)(device->callbackspec.userdata,
- device->hidden->buffer, device->hidden->bufferSize);
- device->hidden->bufferOffset = 0;
- }
-
- len = device->hidden->bufferSize - device->hidden->bufferOffset;
- if (len > remaining) {
- len = remaining;
- }
- SDL_memcpy(ptr, (char *)device->hidden->buffer + device->hidden->bufferOffset, len);
- ptr = ptr + len;
- remaining -= len;
- device->hidden->bufferOffset += len;
- }
- }
-
- AudioQueueEnqueueBuffer(device->hidden->audioQueue, inBuffer, 0, NULL);
- inBuffer->mAudioDataByteSize = inBuffer->mAudioDataBytesCapacity;
+static void COREAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buffer_size)
+{
+ AudioQueueBufferRef current_buffer = device->hidden->current_buffer;
+ SDL_assert(current_buffer != NULL); // should have been called from OutputBufferReadyCallback
+ SDL_assert(buffer == (Uint8 *) current_buffer->mAudioData);
+ current_buffer->mAudioDataByteSize = current_buffer->mAudioDataBytesCapacity;
+ device->hidden->current_buffer = NULL;
+ AudioQueueEnqueueBuffer(device->hidden->audioQueue, current_buffer, 0, NULL);
+}
- SDL_UnlockMutex(device->mixer_lock);
+static Uint8 *COREAUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
+{
+ AudioQueueBufferRef current_buffer = device->hidden->current_buffer;
+ SDL_assert(current_buffer != NULL); // should have been called from OutputBufferReadyCallback
+ SDL_assert(current_buffer->mAudioData != NULL);
+ *buffer_size = (int) current_buffer->mAudioDataBytesCapacity;
+ return (Uint8 *) current_buffer->mAudioData;
}
-static void inputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer,
- const AudioTimeStamp *inStartTime, UInt32 inNumberPacketDescriptions,
- const AudioStreamPacketDescription *inPacketDescs)
+static void OutputBufferReadyCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer)
{
SDL_AudioDevice *device = (SDL_AudioDevice *)inUserData;
-
- if (SDL_AtomicGet(&device->shutdown)) {
- return; /* don't do anything. */
- }
-
- /* ignore unless we're active. */
- if (!SDL_AtomicGet(&device->paused) && SDL_AtomicGet(&device->enabled)) {
- const Uint8 *ptr = (const Uint8 *)inBuffer->mAudioData;
- UInt32 remaining = inBuffer->mAudioDataByteSize;
- while (remaining > 0) {
- UInt32 len = device->hidden->bufferSize - device->hidden->bufferOffset;
- if (len > remaining) {
- len = remaining;
- }
-
- SDL_memcpy((char *)device->hidden->buffer + device->hidden->bufferOffset, ptr, len);
- ptr += len;
- remaining -= len;
- device->hidden->bufferOffset += len;
-
- if (device->hidden->bufferOffset >= device->hidden->bufferSize) {
- SDL_LockMutex(device->mixer_lock);
- (*device->callbackspec.callback)(device->callbackspec.userdata, device->hidden->buffer, device->hidden->bufferSize);
- SDL_UnlockMutex(device->mixer_lock);
- device->hidden->bufferOffset = 0;
- }
- }
- }
-
- AudioQueueEnqueueBuffer(device->hidden->audioQueue, inBuffer, 0, NULL);
+ SDL_assert(inBuffer != NULL); // ...right?
+ SDL_assert(device->hidden->current_buffer == NULL); // shouldn't have anything pending
+ device->hidden->current_buffer = inBuffer;
+ SDL_OutputAudioThreadIterate(device);
+ SDL_assert(device->hidden->current_buffer == NULL); // PlayDevice should have enqueued and cleaned it out.
}
-#ifdef MACOSX_COREAUDIO
-static const AudioObjectPropertyAddress alive_address = {
-
(Patch may be truncated, please check the link at the top of this post.)