summaryrefslogtreecommitdiff
path: root/source/3rd-party/SDL2/src/audio/coreaudio
diff options
context:
space:
mode:
authorchai <chaifix@163.com>2019-06-06 00:11:18 +0800
committerchai <chaifix@163.com>2019-06-06 00:11:18 +0800
commit88b882ed0b432c6aff2063213e2f793a36dd25f7 (patch)
tree5fe5d5334050e1a1146aa63e61e88aa2f5170727 /source/3rd-party/SDL2/src/audio/coreaudio
parentf6c0498c9728a286c13980ed3b60763d02e1b3a0 (diff)
*misc
Diffstat (limited to 'source/3rd-party/SDL2/src/audio/coreaudio')
-rw-r--r--source/3rd-party/SDL2/src/audio/coreaudio/SDL_coreaudio.h66
-rw-r--r--source/3rd-party/SDL2/src/audio/coreaudio/SDL_coreaudio.m861
2 files changed, 0 insertions, 927 deletions
diff --git a/source/3rd-party/SDL2/src/audio/coreaudio/SDL_coreaudio.h b/source/3rd-party/SDL2/src/audio/coreaudio/SDL_coreaudio.h
deleted file mode 100644
index dcce3f7..0000000
--- a/source/3rd-party/SDL2/src/audio/coreaudio/SDL_coreaudio.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- Simple DirectMedia Layer
- Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
-*/
-#include "../../SDL_internal.h"
-
-#ifndef SDL_coreaudio_h_
-#define SDL_coreaudio_h_
-
-#include "../SDL_sysaudio.h"
-
-#if !defined(__IPHONEOS__)
-#define MACOSX_COREAUDIO 1
-#endif
-
-#if MACOSX_COREAUDIO
-#include <CoreAudio/CoreAudio.h>
-#include <CoreServices/CoreServices.h>
-#else
-#import <AVFoundation/AVFoundation.h>
-#import <UIKit/UIApplication.h>
-#endif
-
-#include <AudioToolbox/AudioToolbox.h>
-#include <AudioUnit/AudioUnit.h>
-
-/* Hidden "this" pointer for the audio functions */
-#define _THIS SDL_AudioDevice *this
-
-struct SDL_PrivateAudioData
-{
- AudioQueueRef audioQueue;
- int numAudioBuffers;
- AudioQueueBufferRef *audioBuffer;
- void *buffer;
- UInt32 bufferSize;
- AudioStreamBasicDescription strdesc;
- SDL_bool refill;
- SDL_AudioStream *capturestream;
-#if MACOSX_COREAUDIO
- AudioDeviceID deviceID;
-#else
- SDL_bool interrupted;
- CFTypeRef interruption_listener;
-#endif
-};
-
-#endif /* SDL_coreaudio_h_ */
-
-/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/coreaudio/SDL_coreaudio.m b/source/3rd-party/SDL2/src/audio/coreaudio/SDL_coreaudio.m
deleted file mode 100644
index 59242f9..0000000
--- a/source/3rd-party/SDL2/src/audio/coreaudio/SDL_coreaudio.m
+++ /dev/null
@@ -1,861 +0,0 @@
-/*
- Simple DirectMedia Layer
- Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
-*/
-#include "../../SDL_internal.h"
-
-#if SDL_AUDIO_DRIVER_COREAUDIO
-
-/* !!! FIXME: clean out some of the macro salsa in here. */
-
-#include "SDL_audio.h"
-#include "SDL_hints.h"
-#include "SDL_timer.h"
-#include "../SDL_audio_c.h"
-#include "../SDL_sysaudio.h"
-#include "SDL_coreaudio.h"
-#include "SDL_assert.h"
-#include "../../thread/SDL_systhread.h"
-
-#define DEBUG_COREAUDIO 0
-
-#define CHECK_RESULT(msg) \
- if (result != noErr) { \
- SDL_SetError("CoreAudio error (%s): %d", msg, (int) result); \
- return 0; \
- }
-
-#if MACOSX_COREAUDIO
-static const AudioObjectPropertyAddress devlist_address = {
- kAudioHardwarePropertyDevices,
- kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster
-};
-
-typedef void (*addDevFn)(const char *name, const int iscapture, AudioDeviceID devId, void *data);
-
-typedef struct AudioDeviceList
-{
- AudioDeviceID devid;
- SDL_bool alive;
- struct AudioDeviceList *next;
-} AudioDeviceList;
-
-static AudioDeviceList *output_devs = NULL;
-static AudioDeviceList *capture_devs = NULL;
-
-static SDL_bool
-add_to_internal_dev_list(const int iscapture, AudioDeviceID devId)
-{
- AudioDeviceList *item = (AudioDeviceList *) SDL_malloc(sizeof (AudioDeviceList));
- if (item == NULL) {
- return SDL_FALSE;
- }
- item->devid = devId;
- item->alive = SDL_TRUE;
- item->next = iscapture ? capture_devs : output_devs;
- if (iscapture) {
- capture_devs = item;
- } else {
- output_devs = item;
- }
-
- return SDL_TRUE;
-}
-
-static void
-addToDevList(const char *name, const int iscapture, AudioDeviceID devId, void *data)
-{
- if (add_to_internal_dev_list(iscapture, devId)) {
- SDL_AddAudioDevice(iscapture, name, (void *) ((size_t) devId));
- }
-}
-
-static void
-build_device_list(int iscapture, addDevFn addfn, void *addfndata)
-{
- OSStatus result = noErr;
- UInt32 size = 0;
- AudioDeviceID *devs = NULL;
- UInt32 i = 0;
- UInt32 max = 0;
-
- result = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject,
- &devlist_address, 0, NULL, &size);
- if (result != kAudioHardwareNoError)
- return;
-
- devs = (AudioDeviceID *) alloca(size);
- if (devs == NULL)
- return;
-
- result = AudioObjectGetPropertyData(kAudioObjectSystemObject,
- &devlist_address, 0, NULL, &size, devs);
- if (result != kAudioHardwareNoError)
- return;
-
- 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;
- const AudioObjectPropertyAddress addr = {
- kAudioDevicePropertyStreamConfiguration,
- iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
- kAudioObjectPropertyElementMaster
- };
-
- const AudioObjectPropertyAddress nameaddr = {
- kAudioObjectPropertyName,
- iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
- kAudioObjectPropertyElementMaster
- };
-
- result = AudioObjectGetPropertyDataSize(dev, &addr, 0, NULL, &size);
- if (result != noErr)
- continue;
-
- buflist = (AudioBufferList *) SDL_malloc(size);
- if (buflist == NULL)
- continue;
-
- result = AudioObjectGetPropertyData(dev, &addr, 0, NULL,
- &size, buflist);
-
- if (result == noErr) {
- UInt32 j;
- for (j = 0; j < buflist->mNumberBuffers; j++) {
- if (buflist->mBuffers[j].mNumberChannels > 0) {
- usable = 1;
- break;
- }
- }
- }
-
- SDL_free(buflist);
-
- if (!usable)
- continue;
-
-
- size = sizeof (CFStringRef);
- result = AudioObjectGetPropertyData(dev, &nameaddr, 0, NULL, &size, &cfstr);
- if (result != kAudioHardwareNoError)
- continue;
-
- len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfstr),
- kCFStringEncodingUTF8);
-
- ptr = (char *) SDL_malloc(len + 1);
- usable = ((ptr != NULL) &&
- (CFStringGetCString
- (cfstr, ptr, len + 1, kCFStringEncodingUTF8)));
-
- CFRelease(cfstr);
-
- if (usable) {
- len = strlen(ptr);
- /* Some devices have whitespace at the end...trim it. */
- while ((len > 0) && (ptr[len - 1] == ' ')) {
- len--;
- }
- usable = (len > 0);
- }
-
- if (usable) {
- ptr[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, iscapture, dev, addfndata);
- }
- 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;
-}
-
-static void
-COREAUDIO_DetectDevices(void)
-{
- build_device_list(SDL_TRUE, addToDevList, NULL);
- build_device_list(SDL_FALSE, addToDevList, NULL);
-}
-
-static void
-build_device_change_list(const char *name, const int iscapture, AudioDeviceID devId, void *data)
-{
- AudioDeviceList **list = (AudioDeviceList **) data;
- AudioDeviceList *item;
- for (item = *list; item != NULL; item = item->next) {
- if (item->devid == devId) {
- item->alive = SDL_TRUE;
- return;
- }
- }
-
- add_to_internal_dev_list(iscapture, devId); /* new device, add it. */
- SDL_AddAudioDevice(iscapture, name, (void *) ((size_t) devId));
-}
-
-static void
-reprocess_device_list(const int iscapture, AudioDeviceList **list)
-{
- AudioDeviceList *item;
- AudioDeviceList *prev = NULL;
- for (item = *list; item != NULL; item = item->next) {
- item->alive = SDL_FALSE;
- }
-
- build_device_list(iscapture, build_device_change_list, list);
-
- /* 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);
- }
- item = next;
- }
-}
-
-/* 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;
-}
-#endif
-
-
-static int open_playback_devices = 0;
-static int open_capture_devices = 0;
-
-#if !MACOSX_COREAUDIO
-
-static void interruption_begin(_THIS)
-{
- if (this != NULL && this->hidden->audioQueue != NULL) {
- this->hidden->interrupted = SDL_TRUE;
- AudioQueuePause(this->hidden->audioQueue);
- }
-}
-
-static void interruption_end(_THIS)
-{
- if (this != NULL && this->hidden != NULL && this->hidden->audioQueue != NULL
- && this->hidden->interrupted
- && AudioQueueStart(this->hidden->audioQueue, NULL) == AVAudioSessionErrorCodeNone) {
- this->hidden->interrupted = SDL_FALSE;
- }
-}
-
-@interface SDLInterruptionListener : NSObject
-
-@property (nonatomic, assign) SDL_AudioDevice *device;
-
-@end
-
-@implementation SDLInterruptionListener
-
-- (void)audioSessionInterruption:(NSNotification *)note
-{
- @synchronized (self) {
- NSNumber *type = note.userInfo[AVAudioSessionInterruptionTypeKey];
- if (type.unsignedIntegerValue == AVAudioSessionInterruptionTypeBegan) {
- interruption_begin(self.device);
- } else {
- interruption_end(self.device);
- }
- }
-}
-
-- (void)applicationBecameActive:(NSNotification *)note
-{
- @synchronized (self) {
- interruption_end(self.device);
- }
-}
-
-@end
-
-static BOOL update_audio_session(_THIS, SDL_bool open)
-{
- @autoreleasepool {
- AVAudioSession *session = [AVAudioSession sharedInstance];
- NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
- /* Set category to ambient by default so that other music continues playing. */
- NSString *category = AVAudioSessionCategoryAmbient;
- NSError *err = nil;
-
- if (open_playback_devices && open_capture_devices) {
- category = AVAudioSessionCategoryPlayAndRecord;
- } else if (open_capture_devices) {
- category = AVAudioSessionCategoryRecord;
- } else {
- const char *hint = SDL_GetHint(SDL_HINT_AUDIO_CATEGORY);
- if (hint) {
- if (SDL_strcasecmp(hint, "AVAudioSessionCategoryAmbient") == 0) {
- category = AVAudioSessionCategoryAmbient;
- } else if (SDL_strcasecmp(hint, "AVAudioSessionCategorySoloAmbient") == 0) {
- category = AVAudioSessionCategorySoloAmbient;
- } else if (SDL_strcasecmp(hint, "AVAudioSessionCategoryPlayback") == 0 ||
- SDL_strcasecmp(hint, "playback") == 0) {
- category = AVAudioSessionCategoryPlayback;
- }
- }
- }
-
- if (![session setCategory:category error:&err]) {
- NSString *desc = err.description;
- SDL_SetError("Could not set Audio Session category: %s", desc.UTF8String);
- return NO;
- }
-
- if (open && (open_playback_devices + open_capture_devices) == 1) {
- if (![session setActive:YES error:&err]) {
- NSString *desc = err.description;
- SDL_SetError("Could not activate Audio Session: %s", desc.UTF8String);
- return NO;
- }
- } else if (!open_playback_devices && !open_capture_devices) {
- [session setActive:NO error:nil];
- }
-
- if (open) {
- SDLInterruptionListener *listener = [SDLInterruptionListener new];
- listener.device = this;
-
- [center addObserver:listener
- selector:@selector(audioSessionInterruption:)
- name:AVAudioSessionInterruptionNotification
- object:session];
-
- /* An interruption end notification is not guaranteed to be sent if
- we were previously interrupted... resuming if needed when the app
- becomes active seems to be the way to go. */
- [center addObserver:listener
- selector:@selector(applicationBecameActive:)
- name:UIApplicationDidBecomeActiveNotification
- object:session];
-
- [center addObserver:listener
- selector:@selector(applicationBecameActive:)
- name:UIApplicationWillEnterForegroundNotification
- object:session];
-
- this->hidden->interruption_listener = CFBridgingRetain(listener);
- } else {
- if (this->hidden->interruption_listener != NULL) {
- SDLInterruptionListener *listener = nil;
- listener = (SDLInterruptionListener *) CFBridgingRelease(this->hidden->interruption_listener);
- [center removeObserver:listener];
- @synchronized (listener) {
- listener.device = NULL;
- }
- }
- }
- }
-
- return YES;
-}
-#endif
-
-
-/* The AudioQueue callback */
-static void
-outputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer)
-{
- SDL_AudioDevice *this = (SDL_AudioDevice *) inUserData;
- SDL_assert(inBuffer->mAudioDataBytesCapacity == this->hidden->bufferSize);
- SDL_memcpy(inBuffer->mAudioData, this->hidden->buffer, this->hidden->bufferSize);
- SDL_memset(this->hidden->buffer, '\0', this->hidden->bufferSize); /* zero out in case we have to fill again without new data. */
- inBuffer->mAudioDataByteSize = this->hidden->bufferSize;
- AudioQueueEnqueueBuffer(this->hidden->audioQueue, inBuffer, 0, NULL);
- this->hidden->refill = SDL_TRUE;
-}
-
-static Uint8 *
-COREAUDIO_GetDeviceBuf(_THIS)
-{
- return this->hidden->buffer;
-}
-
-static void
-COREAUDIO_WaitDevice(_THIS)
-{
- while (SDL_AtomicGet(&this->enabled) && !this->hidden->refill) {
- CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.10, 1);
- }
- this->hidden->refill = SDL_FALSE;
-}
-
-static void
-inputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer,
- const AudioTimeStamp *inStartTime, UInt32 inNumberPacketDescriptions,
- const AudioStreamPacketDescription *inPacketDescs )
-{
- SDL_AudioDevice *this = (SDL_AudioDevice *) inUserData;
- if (SDL_AtomicGet(&this->enabled)) {
- SDL_AudioStream *stream = this->hidden->capturestream;
- if (SDL_AudioStreamPut(stream, inBuffer->mAudioData, inBuffer->mAudioDataByteSize) == -1) {
- /* yikes, out of memory or something. I guess drop the buffer. Our WASAPI target kills the device in this case, though */
- }
- AudioQueueEnqueueBuffer(this->hidden->audioQueue, inBuffer, 0, NULL);
- this->hidden->refill = SDL_TRUE;
- }
-}
-
-static int
-COREAUDIO_CaptureFromDevice(_THIS, void *buffer, int buflen)
-{
- SDL_AudioStream *stream = this->hidden->capturestream;
- while (SDL_AtomicGet(&this->enabled)) {
- const int avail = SDL_AudioStreamAvailable(stream);
- if (avail > 0) {
- const int cpy = SDL_min(buflen, avail);
- SDL_AudioStreamGet(stream, buffer, cpy);
- return cpy;
- }
-
- /* wait for more data, try again. */
- while (SDL_AtomicGet(&this->enabled) && !this->hidden->refill) {
- CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.10, 1);
- }
- this->hidden->refill = SDL_FALSE;
- }
-
- return 0; /* not enabled, giving up. */
-}
-
-static void
-COREAUDIO_FlushCapture(_THIS)
-{
- while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, 1) == kCFRunLoopRunHandledSource) {
- /* spin. */
- }
- this->hidden->refill = SDL_FALSE;
- SDL_AudioStreamClear(this->hidden->capturestream);
-}
-
-
-#if MACOSX_COREAUDIO
-static const AudioObjectPropertyAddress alive_address =
-{
- kAudioDevicePropertyDeviceIsAlive,
- kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster
-};
-
-static OSStatus
-device_unplugged(AudioObjectID devid, UInt32 num_addr, const AudioObjectPropertyAddress *addrs, void *data)
-{
- SDL_AudioDevice *this = (SDL_AudioDevice *) data;
- SDL_bool dead = SDL_FALSE;
- UInt32 isAlive = 1;
- UInt32 size = sizeof (isAlive);
- OSStatus error;
-
- if (!SDL_AtomicGet(&this->enabled)) {
- return 0; /* already known to be dead. */
- }
-
- error = AudioObjectGetPropertyData(this->hidden->deviceID, &alive_address,
- 0, NULL, &size, &isAlive);
-
- if (error == kAudioHardwareBadDeviceError) {
- dead = SDL_TRUE; /* device was unplugged. */
- } else if ((error == kAudioHardwareNoError) && (!isAlive)) {
- dead = SDL_TRUE; /* device died in some other way. */
- }
-
- if (dead) {
- SDL_OpenedAudioDeviceDisconnected(this);
- }
-
- return 0;
-}
-#endif
-
-static void
-COREAUDIO_CloseDevice(_THIS)
-{
- const SDL_bool iscapture = this->iscapture;
-
-/* !!! FIXME: what does iOS do when a bluetooth audio device vanishes? Headphones unplugged? */
-/* !!! FIXME: (we only do a "default" device on iOS right now...can we do more?) */
-#if MACOSX_COREAUDIO
- /* Fire a callback if the device stops being "alive" (disconnected, etc). */
- AudioObjectRemovePropertyListener(this->hidden->deviceID, &alive_address, device_unplugged, this);
-#endif
-
-#if !MACOSX_COREAUDIO
- update_audio_session(this, SDL_FALSE);
-#endif
-
- if (this->hidden->audioQueue) {
- AudioQueueDispose(this->hidden->audioQueue, 1);
- }
-
- if (this->hidden->capturestream) {
- SDL_FreeAudioStream(this->hidden->capturestream);
- }
-
- /* AudioQueueDispose() frees the actual buffer objects. */
- SDL_free(this->hidden->audioBuffer);
- SDL_free(this->hidden->buffer);
- SDL_free(this->hidden);
-
- if (iscapture) {
- open_capture_devices--;
- } else {
- open_playback_devices--;
- }
-}
-
-#if MACOSX_COREAUDIO
-static int
-prepare_device(_THIS, void *handle, int iscapture)
-{
- AudioDeviceID devid = (AudioDeviceID) ((size_t) handle);
- OSStatus result = noErr;
- UInt32 size = 0;
- UInt32 alive = 0;
- pid_t pid = 0;
-
- AudioObjectPropertyAddress addr = {
- 0,
- kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster
- };
-
- if (handle == NULL) {
- size = sizeof (AudioDeviceID);
- addr.mSelector =
- ((iscapture) ? kAudioHardwarePropertyDefaultInputDevice :
- kAudioHardwarePropertyDefaultOutputDevice);
- result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr,
- 0, NULL, &size, &devid);
- CHECK_RESULT("AudioHardwareGetProperty (default device)");
- }
-
- addr.mSelector = kAudioDevicePropertyDeviceIsAlive;
- addr.mScope = iscapture ? kAudioDevicePropertyScopeInput :
- kAudioDevicePropertyScopeOutput;
-
- size = sizeof (alive);
- result = AudioObjectGetPropertyData(devid, &addr, 0, NULL, &size, &alive);
- CHECK_RESULT
- ("AudioDeviceGetProperty (kAudioDevicePropertyDeviceIsAlive)");
-
- if (!alive) {
- SDL_SetError("CoreAudio: requested device exists, but isn't alive.");
- return 0;
- }
-
- addr.mSelector = kAudioDevicePropertyHogMode;
- size = sizeof (pid);
- result = AudioObjectGetPropertyData(devid, &addr, 0, NULL, &size, &pid);
-
- /* some devices don't support this property, so errors are fine here. */
- if ((result == noErr) && (pid != -1)) {
- SDL_SetError("CoreAudio: requested device is being hogged.");
- return 0;
- }
-
- this->hidden->deviceID = devid;
- return 1;
-}
-#endif
-
-
-/* this all happens in the audio thread, since it needs a separate runloop. */
-static int
-prepare_audioqueue(_THIS)
-{
- const AudioStreamBasicDescription *strdesc = &this->hidden->strdesc;
- const int iscapture = this->iscapture;
- OSStatus result;
- int i;
-
- SDL_assert(CFRunLoopGetCurrent() != NULL);
-
- if (iscapture) {
- result = AudioQueueNewInput(strdesc, inputCallback, this, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0, &this->hidden->audioQueue);
- CHECK_RESULT("AudioQueueNewInput");
- } else {
- result = AudioQueueNewOutput(strdesc, outputCallback, this, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0, &this->hidden->audioQueue);
- CHECK_RESULT("AudioQueueNewOutput");
- }
-
-#if MACOSX_COREAUDIO
-{
- const AudioObjectPropertyAddress prop = {
- kAudioDevicePropertyDeviceUID,
- iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
- kAudioObjectPropertyElementMaster
- };
- CFStringRef devuid;
- UInt32 devuidsize = sizeof (devuid);
- result = AudioObjectGetPropertyData(this->hidden->deviceID, &prop, 0, NULL, &devuidsize, &devuid);
- CHECK_RESULT("AudioObjectGetPropertyData (kAudioDevicePropertyDeviceUID)");
- result = AudioQueueSetProperty(this->hidden->audioQueue, kAudioQueueProperty_CurrentDevice, &devuid, devuidsize);
- CHECK_RESULT("AudioQueueSetProperty (kAudioQueueProperty_CurrentDevice)");
-
- /* !!! FIXME: what does iOS do when a bluetooth audio device vanishes? Headphones unplugged? */
- /* !!! FIXME: (we only do a "default" device on iOS right now...can we do more?) */
- /* Fire a callback if the device stops being "alive" (disconnected, etc). */
- AudioObjectAddPropertyListener(this->hidden->deviceID, &alive_address, device_unplugged, this);
-}
-#endif
-
- /* Make sure we can feed the device a minimum amount of time */
- double MINIMUM_AUDIO_BUFFER_TIME_MS = 15.0;
-#if defined(__IPHONEOS__)
- if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_7_1) {
- /* Older iOS hardware, use 40 ms as a minimum time */
- MINIMUM_AUDIO_BUFFER_TIME_MS = 40.0;
- }
-#endif
- const double msecs = (this->spec.samples / ((double) this->spec.freq)) * 1000.0;
- int numAudioBuffers = 2;
- if (msecs < MINIMUM_AUDIO_BUFFER_TIME_MS) { /* use more buffers if we have a VERY small sample set. */
- numAudioBuffers = ((int)SDL_ceil(MINIMUM_AUDIO_BUFFER_TIME_MS / msecs) * 2);
- }
-
- this->hidden->numAudioBuffers = numAudioBuffers;
- this->hidden->audioBuffer = SDL_calloc(1, sizeof (AudioQueueBufferRef) * numAudioBuffers);
- if (this->hidden->audioBuffer == NULL) {
- SDL_OutOfMemory();
- return 0;
- }
-
-#if DEBUG_COREAUDIO
- printf("COREAUDIO: numAudioBuffers == %d\n", numAudioBuffers);
-#endif
-
- for (i = 0; i < numAudioBuffers; i++) {
- result = AudioQueueAllocateBuffer(this->hidden->audioQueue, this->spec.size, &this->hidden->audioBuffer[i]);
- CHECK_RESULT("AudioQueueAllocateBuffer");
- SDL_memset(this->hidden->audioBuffer[i]->mAudioData, this->spec.silence, this->hidden->audioBuffer[i]->mAudioDataBytesCapacity);
- this->hidden->audioBuffer[i]->mAudioDataByteSize = this->hidden->audioBuffer[i]->mAudioDataBytesCapacity;
- result = AudioQueueEnqueueBuffer(this->hidden->audioQueue, this->hidden->audioBuffer[i], 0, NULL);
- CHECK_RESULT("AudioQueueEnqueueBuffer");
- }
-
- result = AudioQueueStart(this->hidden->audioQueue, NULL);
- CHECK_RESULT("AudioQueueStart");
-
- /* We're running! */
- return 1;
-}
-
-static void
-COREAUDIO_ThreadInit(_THIS)
-{
- const int rc = prepare_audioqueue(this);
- if (!rc) {
- /* !!! FIXME: do this in RunAudio, and maybe block OpenDevice until ThreadInit finishes, too, to report an opening error */
- SDL_OpenedAudioDeviceDisconnected(this); /* oh well. */
- }
-}
-
-static void
-COREAUDIO_PrepareToClose(_THIS)
-{
- /* run long enough to queue some silence, so we know our actual audio
- has been played */
- CFRunLoopRunInMode(kCFRunLoopDefaultMode, (((this->spec.samples * 1000) / this->spec.freq) * 2) / 1000.0f, 0);
- AudioQueueStop(this->hidden->audioQueue, 1);
-}
-
-static int
-COREAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
-{
- AudioStreamBasicDescription *strdesc;
- SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
- int valid_datatype = 0;
-
- /* Initialize all variables that we clean on shutdown */
- this->hidden = (struct SDL_PrivateAudioData *)
- SDL_malloc((sizeof *this->hidden));
- if (this->hidden == NULL) {
- return SDL_OutOfMemory();
- }
- SDL_zerop(this->hidden);
-
- strdesc = &this->hidden->strdesc;
-
- if (iscapture) {
- open_capture_devices++;
- } else {
- open_playback_devices++;
- }
-
-#if !MACOSX_COREAUDIO
- if (!update_audio_session(this, SDL_TRUE)) {
- return -1;
- }
-
- /* Stop CoreAudio from doing expensive audio rate conversion */
- @autoreleasepool {
- AVAudioSession* session = [AVAudioSession sharedInstance];
- [session setPreferredSampleRate:this->spec.freq error:nil];
- this->spec.freq = (int)session.sampleRate;
- }
-#endif
-
- /* Setup a AudioStreamBasicDescription with the requested format */
- SDL_zerop(strdesc);
- strdesc->mFormatID = kAudioFormatLinearPCM;
- strdesc->mFormatFlags = kLinearPCMFormatFlagIsPacked;
- strdesc->mChannelsPerFrame = this->spec.channels;
- strdesc->mSampleRate = this->spec.freq;
- strdesc->mFramesPerPacket = 1;
-
- while ((!valid_datatype) && (test_format)) {
- this->spec.format = test_format;
- /* Just a list of valid SDL formats, so people don't pass junk here. */
- switch (test_format) {
- case AUDIO_U8:
- case AUDIO_S8:
- case AUDIO_U16LSB:
- case AUDIO_S16LSB:
- case AUDIO_U16MSB:
- case AUDIO_S16MSB:
- case AUDIO_S32LSB:
- case AUDIO_S32MSB:
- case AUDIO_F32LSB:
- case AUDIO_F32MSB:
- valid_datatype = 1;
- strdesc->mBitsPerChannel = SDL_AUDIO_BITSIZE(this->spec.format);
- if (SDL_AUDIO_ISBIGENDIAN(this->spec.format))
- strdesc->mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
-
- if (SDL_AUDIO_ISFLOAT(this->spec.format))
- strdesc->mFormatFlags |= kLinearPCMFormatFlagIsFloat;
- else if (SDL_AUDIO_ISSIGNED(this->spec.format))
- strdesc->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
- break;
- }
- }
-
- if (!valid_datatype) { /* shouldn't happen, but just in case... */
- return SDL_SetError("Unsupported audio format");
- }
-
- strdesc->mBytesPerFrame = strdesc->mBitsPerChannel * strdesc->mChannelsPerFrame / 8;
- strdesc->mBytesPerPacket = strdesc->mBytesPerFrame * strdesc->mFramesPerPacket;
-
-#if MACOSX_COREAUDIO
- if (!prepare_device(this, handle, iscapture)) {
- return -1;
- }
-#endif
-
- /* Calculate the final parameters for this audio specification */
- SDL_CalculateAudioSpec(&this->spec);
-
- if (iscapture) {
- this->hidden->capturestream = SDL_NewAudioStream(this->spec.format, this->spec.channels, this->spec.freq, this->spec.format, this->spec.channels, this->spec.freq);
- if (!this->hidden->capturestream) {
- return -1; /* already set SDL_Error */
- }
- } else {
- this->hidden->bufferSize = this->spec.size;
- this->hidden->buffer = SDL_malloc(this->hidden->bufferSize);
- if (this->hidden->buffer == NULL) {
- return SDL_OutOfMemory();
- }
- }
-
- return 0;
-}
-
-static void
-COREAUDIO_Deinitialize(void)
-{
-#if MACOSX_COREAUDIO
- AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &devlist_address, device_list_changed, NULL);
- free_audio_device_list(&capture_devs);
- free_audio_device_list(&output_devs);
-#endif
-}
-
-static int
-COREAUDIO_Init(SDL_AudioDriverImpl * impl)
-{
- /* Set the function pointers */
- impl->OpenDevice = COREAUDIO_OpenDevice;
- impl->CloseDevice = COREAUDIO_CloseDevice;
- impl->Deinitialize = COREAUDIO_Deinitialize;
- impl->ThreadInit = COREAUDIO_ThreadInit;
- impl->WaitDevice = COREAUDIO_WaitDevice;
- impl->GetDeviceBuf = COREAUDIO_GetDeviceBuf;
- impl->PrepareToClose = COREAUDIO_PrepareToClose;
- impl->CaptureFromDevice = COREAUDIO_CaptureFromDevice;
- impl->FlushCapture = COREAUDIO_FlushCapture;
-
-#if MACOSX_COREAUDIO
- impl->DetectDevices = COREAUDIO_DetectDevices;
- AudioObjectAddPropertyListener(kAudioObjectSystemObject, &devlist_address, device_list_changed, NULL);
-#else
- impl->OnlyHasDefaultOutputDevice = 1;
- impl->OnlyHasDefaultCaptureDevice = 1;
-#endif
-
- impl->HasCaptureSupport = 1;
-
- return 1; /* this audio target is available. */
-}
-
-AudioBootStrap COREAUDIO_bootstrap = {
- "coreaudio", "CoreAudio", COREAUDIO_Init, 0
-};
-
-#endif /* SDL_AUDIO_DRIVER_COREAUDIO */
-
-/* vi: set ts=4 sw=4 expandtab: */