| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769 |
- /*
- Simple DirectMedia Layer
- Copyright (C) 1997-2016 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
- #include "SDL_audio.h"
- #include "../SDL_audio_c.h"
- #include "../SDL_sysaudio.h"
- #include "SDL_coreaudio.h"
- #include "SDL_assert.h"
- #define DEBUG_COREAUDIO 0
- static void COREAUDIO_CloseDevice(_THIS);
- #define CHECK_RESULT(msg) \
- if (result != noErr) { \
- COREAUDIO_CloseDevice(this); \
- 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
- /* The CoreAudio callback */
- static OSStatus
- outputCallback(void *inRefCon,
- AudioUnitRenderActionFlags * ioActionFlags,
- const AudioTimeStamp * inTimeStamp,
- UInt32 inBusNumber, UInt32 inNumberFrames,
- AudioBufferList * ioData)
- {
- SDL_AudioDevice *this = (SDL_AudioDevice *) inRefCon;
- AudioBuffer *abuf;
- UInt32 remaining, len;
- void *ptr;
- UInt32 i;
- /* Only do anything if audio is enabled and not paused */
- if (!SDL_AtomicGet(&this->enabled) || SDL_AtomicGet(&this->paused)) {
- for (i = 0; i < ioData->mNumberBuffers; i++) {
- abuf = &ioData->mBuffers[i];
- SDL_memset(abuf->mData, this->spec.silence, abuf->mDataByteSize);
- }
- return 0;
- }
- /* No SDL conversion should be needed here, ever, since we accept
- any input format in OpenAudio, and leave the conversion to CoreAudio.
- */
- /*
- SDL_assert(!this->convert.needed);
- SDL_assert(this->spec.channels == ioData->mNumberChannels);
- */
- for (i = 0; i < ioData->mNumberBuffers; i++) {
- abuf = &ioData->mBuffers[i];
- remaining = abuf->mDataByteSize;
- ptr = abuf->mData;
- while (remaining > 0) {
- if (this->hidden->bufferOffset >= this->hidden->bufferSize) {
- /* Generate the data */
- SDL_LockMutex(this->mixer_lock);
- (*this->spec.callback)(this->spec.userdata,
- this->hidden->buffer, this->hidden->bufferSize);
- SDL_UnlockMutex(this->mixer_lock);
- this->hidden->bufferOffset = 0;
- }
- len = this->hidden->bufferSize - this->hidden->bufferOffset;
- if (len > remaining)
- len = remaining;
- SDL_memcpy(ptr, (char *)this->hidden->buffer +
- this->hidden->bufferOffset, len);
- ptr = (char *)ptr + len;
- remaining -= len;
- this->hidden->bufferOffset += len;
- }
- }
- return noErr;
- }
- static OSStatus
- inputCallback(void *inRefCon,
- AudioUnitRenderActionFlags *ioActionFlags,
- const AudioTimeStamp *inTimeStamp,
- UInt32 inBusNumber, UInt32 inNumberFrames,
- AudioBufferList *ioData)
- {
- SDL_AudioDevice *this = (SDL_AudioDevice *) inRefCon;
- if (!SDL_AtomicGet(&this->enabled) || SDL_AtomicGet(&this->paused)) {
- return noErr; /* just drop this if we're not accepting input. */
- }
- const OSStatus err = AudioUnitRender(this->hidden->audioUnit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, &this->hidden->captureBufferList);
- SDL_assert(this->hidden->captureBufferList.mNumberBuffers == 1);
- if (err == noErr) {
- const AudioBuffer *abuf = &this->hidden->captureBufferList.mBuffers[0];
- UInt32 remaining = abuf->mDataByteSize;
- const Uint8 *ptr = (const Uint8 *) abuf->mData;
- /* No SDL conversion should be needed here, ever, since we accept
- any input format in OpenAudio, and leave the conversion to CoreAudio.
- */
- while (remaining > 0) {
- UInt32 len = this->hidden->bufferSize - this->hidden->bufferOffset;
- if (len > remaining)
- len = remaining;
- SDL_memcpy((char *)this->hidden->buffer + this->hidden->bufferOffset, ptr, len);
- ptr += len;
- remaining -= len;
- this->hidden->bufferOffset += len;
- if (this->hidden->bufferOffset >= this->hidden->bufferSize) {
- SDL_LockMutex(this->mixer_lock);
- (*this->spec.callback)(this->spec.userdata,
- this->hidden->buffer, this->hidden->bufferSize);
- SDL_UnlockMutex(this->mixer_lock);
- this->hidden->bufferOffset = 0;
- }
- }
- }
- return noErr;
- }
- #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)
- {
- if (this->hidden != NULL) {
- if (this->hidden->audioUnitOpened) {
- #if MACOSX_COREAUDIO
- /* Unregister our disconnect callback. */
- AudioObjectRemovePropertyListener(this->hidden->deviceID, &alive_address, device_unplugged, this);
- #endif
- AURenderCallbackStruct callback;
- const AudioUnitElement output_bus = 0;
- const AudioUnitElement input_bus = 1;
- const int iscapture = this->iscapture;
- const AudioUnitElement bus =
- ((iscapture) ? input_bus : output_bus);
- /* stop processing the audio unit */
- AudioOutputUnitStop(this->hidden->audioUnit);
- /* Remove the input callback */
- SDL_zero(callback);
- AudioUnitSetProperty(this->hidden->audioUnit,
- iscapture ? kAudioOutputUnitProperty_SetInputCallback : kAudioUnitProperty_SetRenderCallback,
- kAudioUnitScope_Global, bus, &callback, sizeof(callback));
- AudioComponentInstanceDispose(this->hidden->audioUnit);
- this->hidden->audioUnitOpened = 0;
- #if MACOSX_COREAUDIO
- SDL_free(this->hidden->captureBufferList.mBuffers[0].mData);
- #endif
- }
- SDL_free(this->hidden->buffer);
- SDL_free(this->hidden);
- this->hidden = NULL;
- }
- }
- #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
- static int
- prepare_audiounit(_THIS, void *handle, int iscapture,
- const AudioStreamBasicDescription * strdesc)
- {
- OSStatus result = noErr;
- AURenderCallbackStruct callback;
- AudioComponentDescription desc;
- AudioComponent comp = NULL;
- const AudioUnitElement output_bus = 0;
- const AudioUnitElement input_bus = 1;
- #if MACOSX_COREAUDIO
- if (!prepare_device(this, handle, iscapture)) {
- return 0;
- }
- #endif
- SDL_zero(desc);
- desc.componentType = kAudioUnitType_Output;
- desc.componentManufacturer = kAudioUnitManufacturer_Apple;
- #if MACOSX_COREAUDIO
- desc.componentSubType = iscapture ? kAudioUnitSubType_HALOutput : kAudioUnitSubType_DefaultOutput;
- #else
- desc.componentSubType = kAudioUnitSubType_RemoteIO;
- #endif
- comp = AudioComponentFindNext(NULL, &desc);
- if (comp == NULL) {
- SDL_SetError("Couldn't find requested CoreAudio component");
- return 0;
- }
- /* Open & initialize the audio unit */
- result = AudioComponentInstanceNew(comp, &this->hidden->audioUnit);
- CHECK_RESULT("AudioComponentInstanceNew");
- this->hidden->audioUnitOpened = 1;
- #if MACOSX_COREAUDIO
- if (iscapture) { /* have to do EnableIO only for capture devices. */
- UInt32 enable = 1;
- result = AudioUnitSetProperty(this->hidden->audioUnit,
- kAudioOutputUnitProperty_EnableIO,
- kAudioUnitScope_Input, input_bus,
- &enable, sizeof (enable));
- CHECK_RESULT
- ("AudioUnitSetProperty (kAudioOutputUnitProperty_EnableIO input bus)");
- enable = 0;
- result = AudioUnitSetProperty(this->hidden->audioUnit,
- kAudioOutputUnitProperty_EnableIO,
- kAudioUnitScope_Output, output_bus,
- &enable, sizeof (enable));
- CHECK_RESULT
- ("AudioUnitSetProperty (kAudioOutputUnitProperty_EnableIO output bus)");
- }
- /* this is always on the output_bus, even for capture devices. */
- result = AudioUnitSetProperty(this->hidden->audioUnit,
- kAudioOutputUnitProperty_CurrentDevice,
- kAudioUnitScope_Global, output_bus,
- &this->hidden->deviceID,
- sizeof(AudioDeviceID));
- CHECK_RESULT
- ("AudioUnitSetProperty (kAudioOutputUnitProperty_CurrentDevice)");
- #endif
- /* Set the data format of the audio unit. */
- result = AudioUnitSetProperty(this->hidden->audioUnit,
- kAudioUnitProperty_StreamFormat,
- iscapture ? kAudioUnitScope_Output : kAudioUnitScope_Input,
- iscapture ? input_bus : output_bus,
- strdesc, sizeof (*strdesc));
- CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_StreamFormat)");
- #if MACOSX_COREAUDIO
- if (iscapture) { /* only need to do this for capture devices. */
- void *ptr;
- UInt32 framesize = 0;
- UInt32 propsize = sizeof (UInt32);
- result = AudioUnitGetProperty(this->hidden->audioUnit,
- kAudioDevicePropertyBufferFrameSize,
- kAudioUnitScope_Global, output_bus,
- &framesize, &propsize);
- CHECK_RESULT
- ("AudioUnitGetProperty (kAudioDevicePropertyBufferFrameSize)");
- framesize *= SDL_AUDIO_BITSIZE(this->spec.format) / 8;
- ptr = SDL_calloc(1, framesize);
- if (ptr == NULL) {
- COREAUDIO_CloseDevice(this);
- SDL_OutOfMemory();
- return 0;
- }
- this->hidden->captureBufferList.mNumberBuffers = 1;
- this->hidden->captureBufferList.mBuffers[0].mNumberChannels = this->spec.channels;
- this->hidden->captureBufferList.mBuffers[0].mDataByteSize = framesize;
- this->hidden->captureBufferList.mBuffers[0].mData = ptr;
- }
- #endif
- /* Set the audio callback */
- SDL_zero(callback);
- callback.inputProc = ((iscapture) ? inputCallback : outputCallback);
- callback.inputProcRefCon = this;
- result = AudioUnitSetProperty(this->hidden->audioUnit,
- iscapture ? kAudioOutputUnitProperty_SetInputCallback : kAudioUnitProperty_SetRenderCallback,
- kAudioUnitScope_Global, output_bus, &callback, sizeof(callback));
- CHECK_RESULT
- ("AudioUnitSetProperty (kAudioUnitProperty_SetRenderCallback)");
- /* Calculate the final parameters for this audio specification */
- SDL_CalculateAudioSpec(&this->spec);
- /* Allocate a sample buffer */
- this->hidden->bufferSize = this->spec.size;
- this->hidden->bufferOffset = iscapture ? 0 : this->hidden->bufferSize;
- this->hidden->buffer = SDL_malloc(this->hidden->bufferSize);
- if (this->hidden->buffer == NULL) {
- COREAUDIO_CloseDevice(this);
- SDL_OutOfMemory();
- return 0;
- }
- result = AudioUnitInitialize(this->hidden->audioUnit);
- CHECK_RESULT("AudioUnitInitialize");
- /* Finally, start processing of the audio unit */
- result = AudioOutputUnitStart(this->hidden->audioUnit);
- CHECK_RESULT("AudioOutputUnitStart");
- /* !!! 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). */
- AudioObjectAddPropertyListener(this->hidden->deviceID, &alive_address, device_unplugged, this);
- #endif
- /* We're running! */
- return 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);
- /* Setup a AudioStreamBasicDescription with the requested format */
- SDL_zero(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... */
- COREAUDIO_CloseDevice(this);
- return SDL_SetError("Unsupported audio format");
- }
- strdesc.mBytesPerFrame =
- strdesc.mBitsPerChannel * strdesc.mChannelsPerFrame / 8;
- strdesc.mBytesPerPacket =
- strdesc.mBytesPerFrame * strdesc.mFramesPerPacket;
- if (!prepare_audiounit(this, handle, iscapture, &strdesc)) {
- COREAUDIO_CloseDevice(this);
- return -1; /* prepare_audiounit() will call SDL_SetError()... */
- }
- return 0; /* good to go. */
- }
- 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;
- #if MACOSX_COREAUDIO
- impl->DetectDevices = COREAUDIO_DetectDevices;
- AudioObjectAddPropertyListener(kAudioObjectSystemObject, &devlist_address, device_list_changed, NULL);
- impl->HasCaptureSupport = 1;
- #else
- impl->OnlyHasDefaultOutputDevice = 1;
- /* Set category to ambient sound so that other music continues playing.
- You can change this at runtime in your own code if you need different
- behavior. If this is common, we can add an SDL hint for this.
- */
- AudioSessionInitialize(NULL, NULL, NULL, nil);
- UInt32 category = kAudioSessionCategory_AmbientSound;
- AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(UInt32), &category);
- #endif
- impl->ProvidesOwnCallbackThread = 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: */
|