21 #include "../../SDL_internal.h" 23 #if SDL_AUDIO_DRIVER_COREAUDIO 26 #include "../SDL_audio_c.h" 27 #include "../SDL_sysaudio.h" 31 #define DEBUG_COREAUDIO 0 33 static void COREAUDIO_CloseDevice(
_THIS);
35 #define CHECK_RESULT(msg) \ 36 if (result != noErr) { \ 37 COREAUDIO_CloseDevice(this); \ 38 SDL_SetError("CoreAudio error (%s): %d", msg, (int) result); \ 43 static const AudioObjectPropertyAddress devlist_address = {
44 kAudioHardwarePropertyDevices,
45 kAudioObjectPropertyScopeGlobal,
46 kAudioObjectPropertyElementMaster
49 typedef void (*addDevFn)(
const char *
name,
const int iscapture, AudioDeviceID devId,
void *
data);
51 typedef struct AudioDeviceList
55 struct AudioDeviceList *next;
58 static AudioDeviceList *output_devs =
NULL;
59 static AudioDeviceList *capture_devs =
NULL;
62 add_to_internal_dev_list(
const int iscapture, AudioDeviceID devId)
64 AudioDeviceList *item = (AudioDeviceList *)
SDL_malloc(
sizeof (AudioDeviceList));
70 item->next = iscapture ? capture_devs : output_devs;
81 addToDevList(
const char *
name,
const int iscapture, AudioDeviceID devId,
void *
data)
83 if (add_to_internal_dev_list(iscapture, devId)) {
89 build_device_list(
int iscapture, addDevFn addfn,
void *addfndata)
93 AudioDeviceID *devs =
NULL;
97 result = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject,
98 &devlist_address, 0,
NULL, &size);
99 if (result != kAudioHardwareNoError)
102 devs = (AudioDeviceID *) alloca(size);
106 result = AudioObjectGetPropertyData(kAudioObjectSystemObject,
107 &devlist_address, 0,
NULL, &size, devs);
108 if (result != kAudioHardwareNoError)
111 max = size /
sizeof (AudioDeviceID);
112 for (i = 0; i < max; i++) {
113 CFStringRef cfstr =
NULL;
115 AudioDeviceID dev = devs[
i];
116 AudioBufferList *buflist =
NULL;
119 const AudioObjectPropertyAddress
addr = {
120 kAudioDevicePropertyStreamConfiguration,
121 iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
122 kAudioObjectPropertyElementMaster
125 const AudioObjectPropertyAddress nameaddr = {
126 kAudioObjectPropertyName,
127 iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
128 kAudioObjectPropertyElementMaster
131 result = AudioObjectGetPropertyDataSize(dev, &addr, 0,
NULL, &size);
135 buflist = (AudioBufferList *)
SDL_malloc(size);
139 result = AudioObjectGetPropertyData(dev, &addr, 0,
NULL,
142 if (result == noErr) {
144 for (j = 0; j < buflist->mNumberBuffers; j++) {
145 if (buflist->mBuffers[j].mNumberChannels > 0) {
158 size =
sizeof (CFStringRef);
159 result = AudioObjectGetPropertyData(dev, &nameaddr, 0,
NULL, &size, &cfstr);
160 if (result != kAudioHardwareNoError)
163 len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfstr),
164 kCFStringEncodingUTF8);
167 usable = ((ptr !=
NULL) &&
169 (cfstr, ptr, len + 1, kCFStringEncodingUTF8)));
176 while ((len > 0) && (ptr[len - 1] ==
' ')) {
186 printf(
"COREAUDIO: Found %s device #%d: '%s' (devid %d)\n",
187 ((iscapture) ?
"capture" :
"output"),
188 (
int) *devCount, ptr, (
int) dev);
190 addfn(ptr, iscapture, dev, addfndata);
197 free_audio_device_list(AudioDeviceList **list)
199 AudioDeviceList *item = *list;
201 AudioDeviceList *next = item->next;
209 COREAUDIO_DetectDevices(
void)
216 build_device_change_list(
const char *name,
const int iscapture, AudioDeviceID devId,
void *data)
218 AudioDeviceList **list = (AudioDeviceList **) data;
219 AudioDeviceList *item;
220 for (item = *list; item !=
NULL; item = item->next) {
221 if (item->devid == devId) {
227 add_to_internal_dev_list(iscapture, devId);
232 reprocess_device_list(
const int iscapture, AudioDeviceList **list)
234 AudioDeviceList *item;
235 AudioDeviceList *prev =
NULL;
236 for (item = *list; item !=
NULL; item = item->next) {
240 build_device_list(iscapture, build_device_change_list, list);
244 while (item !=
NULL) {
245 AudioDeviceList *next = item->next;
251 prev->next = item->next;
263 device_list_changed(AudioObjectID systemObj, UInt32 num_addr,
const AudioObjectPropertyAddress *addrs,
void *data)
265 reprocess_device_list(
SDL_TRUE, &capture_devs);
266 reprocess_device_list(
SDL_FALSE, &output_devs);
273 outputCallback(
void *inRefCon,
274 AudioUnitRenderActionFlags * ioActionFlags,
275 const AudioTimeStamp * inTimeStamp,
276 UInt32 inBusNumber, UInt32 inNumberFrames,
277 AudioBufferList * ioData)
281 UInt32 remaining,
len;
287 for (i = 0; i < ioData->mNumberBuffers; i++) {
288 abuf = &ioData->mBuffers[
i];
289 SDL_memset(abuf->mData, this->spec.silence, abuf->mDataByteSize);
302 for (i = 0; i < ioData->mNumberBuffers; i++) {
303 abuf = &ioData->mBuffers[
i];
304 remaining = abuf->mDataByteSize;
306 while (remaining > 0) {
307 if (this->hidden->bufferOffset >= this->hidden->bufferSize) {
311 this->hidden->buffer, this->hidden->bufferSize);
313 this->hidden->bufferOffset = 0;
316 len = this->hidden->bufferSize - this->hidden->bufferOffset;
319 SDL_memcpy(ptr, (
char *)this->hidden->buffer +
320 this->hidden->bufferOffset, len);
321 ptr = (
char *)ptr + len;
323 this->hidden->bufferOffset +=
len;
331 inputCallback(
void *inRefCon,
332 AudioUnitRenderActionFlags * ioActionFlags,
333 const AudioTimeStamp * inTimeStamp,
334 UInt32 inBusNumber, UInt32 inNumberFrames,
335 AudioBufferList * ioData)
344 static const AudioObjectPropertyAddress alive_address =
346 kAudioDevicePropertyDeviceIsAlive,
347 kAudioObjectPropertyScopeGlobal,
348 kAudioObjectPropertyElementMaster
352 device_unplugged(AudioObjectID devid, UInt32 num_addr,
const AudioObjectPropertyAddress *addrs,
void *data)
357 UInt32 size =
sizeof (isAlive);
364 error = AudioObjectGetPropertyData(this->hidden->deviceID, &alive_address,
365 0,
NULL, &size, &isAlive);
367 if (error == kAudioHardwareBadDeviceError) {
369 }
else if ((error == kAudioHardwareNoError) && (!isAlive)) {
382 COREAUDIO_CloseDevice(
_THIS)
384 if (this->hidden !=
NULL) {
385 if (this->hidden->audioUnitOpened) {
388 AudioObjectRemovePropertyListener(this->hidden->deviceID, &alive_address, device_unplugged,
this);
392 const AudioUnitElement output_bus = 0;
393 const AudioUnitElement input_bus = 1;
394 const int iscapture = this->iscapture;
395 const AudioUnitElement bus =
396 ((iscapture) ? input_bus : output_bus);
397 const AudioUnitScope scope =
398 ((iscapture) ? kAudioUnitScope_Output :
399 kAudioUnitScope_Input);
402 AudioOutputUnitStop(this->hidden->audioUnit);
405 SDL_memset(&callback, 0,
sizeof(AURenderCallbackStruct));
406 AudioUnitSetProperty(this->hidden->audioUnit,
407 kAudioUnitProperty_SetRenderCallback,
408 scope, bus, &callback,
sizeof(callback));
411 CloseComponent(this->hidden->audioUnit);
413 AudioComponentInstanceDispose(this->hidden->audioUnit);
416 this->hidden->audioUnitOpened = 0;
426 prepare_device(
_THIS,
void *handle,
int iscapture)
428 AudioDeviceID devid = (AudioDeviceID) ((
size_t) handle);
429 OSStatus result = noErr;
434 AudioObjectPropertyAddress addr = {
436 kAudioObjectPropertyScopeGlobal,
437 kAudioObjectPropertyElementMaster
440 if (handle ==
NULL) {
441 size =
sizeof (AudioDeviceID);
443 ((iscapture) ? kAudioHardwarePropertyDefaultInputDevice :
444 kAudioHardwarePropertyDefaultOutputDevice);
445 result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr,
446 0,
NULL, &size, &devid);
447 CHECK_RESULT(
"AudioHardwareGetProperty (default device)");
450 addr.mSelector = kAudioDevicePropertyDeviceIsAlive;
451 addr.mScope = iscapture ? kAudioDevicePropertyScopeInput :
452 kAudioDevicePropertyScopeOutput;
454 size =
sizeof (
alive);
455 result = AudioObjectGetPropertyData(devid, &addr, 0,
NULL, &size, &alive);
457 (
"AudioDeviceGetProperty (kAudioDevicePropertyDeviceIsAlive)");
460 SDL_SetError(
"CoreAudio: requested device exists, but isn't alive.");
464 addr.mSelector = kAudioDevicePropertyHogMode;
466 result = AudioObjectGetPropertyData(devid, &addr, 0,
NULL, &size, &pid);
469 if ((result == noErr) && (pid != -1)) {
470 SDL_SetError(
"CoreAudio: requested device is being hogged.");
474 this->hidden->deviceID = devid;
480 prepare_audiounit(
_THIS,
void *handle,
int iscapture,
481 const AudioStreamBasicDescription * strdesc)
483 OSStatus result = noErr;
486 ComponentDescription desc;
487 Component comp =
NULL;
489 AudioComponentDescription desc;
490 AudioComponent comp =
NULL;
492 const AudioUnitElement output_bus = 0;
493 const AudioUnitElement input_bus = 1;
494 const AudioUnitElement bus = ((iscapture) ? input_bus : output_bus);
495 const AudioUnitScope scope = ((iscapture) ? kAudioUnitScope_Output :
496 kAudioUnitScope_Input);
499 if (!prepare_device(
this, handle, iscapture)) {
505 desc.componentType = kAudioUnitType_Output;
506 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
509 desc.componentSubType = kAudioUnitSubType_DefaultOutput;
510 comp = FindNextComponent(
NULL, &desc);
512 desc.componentSubType = kAudioUnitSubType_RemoteIO;
513 comp = AudioComponentFindNext(
NULL, &desc);
517 SDL_SetError(
"Couldn't find requested CoreAudio component");
523 result = OpenAComponent(comp, &this->hidden->audioUnit);
524 CHECK_RESULT(
"OpenAComponent");
530 result = AudioComponentInstanceNew(comp, &this->hidden->audioUnit);
531 CHECK_RESULT(
"AudioComponentInstanceNew");
534 this->hidden->audioUnitOpened = 1;
537 result = AudioUnitSetProperty(this->hidden->audioUnit,
538 kAudioOutputUnitProperty_CurrentDevice,
539 kAudioUnitScope_Global, 0,
540 &this->hidden->deviceID,
541 sizeof(AudioDeviceID));
543 (
"AudioUnitSetProperty (kAudioOutputUnitProperty_CurrentDevice)");
547 result = AudioUnitSetProperty(this->hidden->audioUnit,
548 kAudioUnitProperty_StreamFormat,
549 scope, bus, strdesc,
sizeof(*strdesc));
550 CHECK_RESULT(
"AudioUnitSetProperty (kAudioUnitProperty_StreamFormat)");
553 SDL_memset(&callback, 0,
sizeof(AURenderCallbackStruct));
554 callback.inputProc = ((iscapture) ? inputCallback : outputCallback);
555 callback.inputProcRefCon =
this;
556 result = AudioUnitSetProperty(this->hidden->audioUnit,
557 kAudioUnitProperty_SetRenderCallback,
558 scope, bus, &callback,
sizeof(callback));
560 (
"AudioUnitSetProperty (kAudioUnitProperty_SetRenderCallback)");
566 this->hidden->bufferOffset = this->hidden->bufferSize = this->
spec.
size;
567 this->hidden->buffer =
SDL_malloc(this->hidden->bufferSize);
569 result = AudioUnitInitialize(this->hidden->audioUnit);
570 CHECK_RESULT(
"AudioUnitInitialize");
573 result = AudioOutputUnitStart(this->hidden->audioUnit);
574 CHECK_RESULT(
"AudioOutputUnitStart");
578 AudioObjectAddPropertyListener(this->hidden->deviceID, &alive_address, device_unplugged,
this);
587 COREAUDIO_OpenDevice(
_THIS,
void *handle,
const char *devname,
int iscapture)
589 AudioStreamBasicDescription strdesc;
591 int valid_datatype = 0;
596 if (this->hidden ==
NULL) {
599 SDL_memset(this->hidden, 0, (
sizeof *this->hidden));
602 SDL_memset(&strdesc,
'\0',
sizeof(AudioStreamBasicDescription));
603 strdesc.mFormatID = kAudioFormatLinearPCM;
604 strdesc.mFormatFlags = kLinearPCMFormatFlagIsPacked;
606 strdesc.mSampleRate = this->
spec.
freq;
607 strdesc.mFramesPerPacket = 1;
609 while ((!valid_datatype) && (test_format)) {
612 switch (test_format) {
626 strdesc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
629 strdesc.mFormatFlags |= kLinearPCMFormatFlagIsFloat;
631 strdesc.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
636 if (!valid_datatype) {
637 COREAUDIO_CloseDevice(
this);
641 strdesc.mBytesPerFrame =
642 strdesc.mBitsPerChannel * strdesc.mChannelsPerFrame / 8;
643 strdesc.mBytesPerPacket =
644 strdesc.mBytesPerFrame * strdesc.mFramesPerPacket;
646 if (!prepare_audiounit(
this, handle, iscapture, &strdesc)) {
647 COREAUDIO_CloseDevice(
this);
655 COREAUDIO_Deinitialize(
void)
658 AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &devlist_address, device_list_changed,
NULL);
659 free_audio_device_list(&capture_devs);
660 free_audio_device_list(&output_devs);
674 AudioObjectAddPropertyListener(kAudioObjectSystemObject, &devlist_address, device_list_changed,
NULL);
683 UInt32 category = kAudioSessionCategory_AmbientSound;
684 AudioSessionSetProperty(kAudioSessionProperty_AudioCategory,
sizeof(UInt32), &category);
693 "coreaudio",
"CoreAudio", COREAUDIO_Init, 0
SDL_AudioFormat SDL_FirstAudioFormat(SDL_AudioFormat format)
void(* DetectDevices)(void)
#define SDL_AUDIO_ISBIGENDIAN(x)
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
int ProvidesOwnCallbackThread
#define SDL_AUDIO_ISSIGNED(x)
void SDL_OpenedAudioDeviceDisconnected(SDL_AudioDevice *device)
Uint16 SDL_AudioFormat
Audio format flags.
GLuint const GLchar * name
#define SDL_AUDIO_ISFLOAT(x)
int OnlyHasDefaultOutputDevice
void SDL_RemoveAudioDevice(const int iscapture, void *handle)
#define SDL_AUDIO_BITSIZE(x)
void(* Deinitialize)(void)
AudioBootStrap COREAUDIO_bootstrap
static Uint32 callback(Uint32 interval, void *param)
void SDL_CalculateAudioSpec(SDL_AudioSpec *spec)
SDL_AudioCallback callback
GLenum GLenum GLsizei const GLuint GLboolean enabled
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
int(* OpenDevice)(_THIS, void *handle, const char *devname, int iscapture)
#define SDL_OutOfMemory()
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 void
void(* CloseDevice)(_THIS)
void SDL_AddAudioDevice(const int iscapture, const char *name, void *handle)
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int int in j)