23 #include "../SDL_audio_c.h"
24 #include "../SDL_sysaudio.h"
28 #define DEBUG_COREAUDIO 0
32 #define CHECK_RESULT(msg) \
33 if (result != noErr) { \
34 COREAUDIO_CloseDevice(this); \
35 SDL_SetError("CoreAudio error (%s): %d", msg, (int) result); \
59 FindDevIdData *
data = (FindDevIdData *) _data;
73 AudioDeviceID *devs =
NULL;
77 AudioObjectPropertyAddress
addr = {
78 kAudioHardwarePropertyDevices,
79 kAudioObjectPropertyScopeGlobal,
80 kAudioObjectPropertyElementMaster
83 result = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &addr,
85 if (result != kAudioHardwareNoError)
88 devs = (AudioDeviceID *) alloca(size);
92 result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr,
93 0,
NULL, &size, devs);
94 if (result != kAudioHardwareNoError)
97 max = size /
sizeof (AudioDeviceID);
98 for (i = 0; i <
max; i++) {
99 CFStringRef cfstr =
NULL;
101 AudioDeviceID dev = devs[
i];
102 AudioBufferList *buflist =
NULL;
106 addr.mScope = iscapture ? kAudioDevicePropertyScopeInput :
107 kAudioDevicePropertyScopeOutput;
108 addr.mSelector = kAudioDevicePropertyStreamConfiguration;
110 result = AudioObjectGetPropertyDataSize(dev, &addr, 0,
NULL, &size);
114 buflist = (AudioBufferList *)
SDL_malloc(size);
118 result = AudioObjectGetPropertyData(dev, &addr, 0,
NULL,
121 if (result == noErr) {
123 for (j = 0; j < buflist->mNumberBuffers; j++) {
124 if (buflist->mBuffers[j].mNumberChannels > 0) {
136 addr.mSelector = kAudioObjectPropertyName;
137 size =
sizeof (CFStringRef);
138 result = AudioObjectGetPropertyData(dev, &addr, 0,
NULL, &size, &cfstr);
139 if (result != kAudioHardwareNoError)
142 len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfstr),
143 kCFStringEncodingUTF8);
146 usable = ((ptr !=
NULL) &&
148 (cfstr, ptr, len + 1, kCFStringEncodingUTF8)));
155 while ((len > 0) && (ptr[len - 1] ==
' ')) {
165 printf(
"COREAUDIO: Found %s device #%d: '%s' (devid %d)\n",
166 ((iscapture) ?
"capture" :
"output"),
167 (
int) *devCount, ptr, (
int) dev);
169 addfn(ptr, dev, addfndata);
184 AudioDeviceID devid = 0;
190 AudioObjectPropertyAddress
addr = {
192 kAudioObjectPropertyScopeGlobal,
193 kAudioObjectPropertyElementMaster
196 if (devname ==
NULL) {
197 size =
sizeof (AudioDeviceID);
199 ((iscapture) ? kAudioHardwarePropertyDefaultInputDevice :
200 kAudioHardwarePropertyDefaultOutputDevice);
201 result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr,
202 0,
NULL, &size, &devid);
203 CHECK_RESULT(
"AudioHardwareGetProperty (default device)");
207 data.findname = devname;
216 addr.mSelector = kAudioDevicePropertyDeviceIsAlive;
217 addr.mScope = iscapture ? kAudioDevicePropertyScopeInput :
218 kAudioDevicePropertyScopeOutput;
220 size =
sizeof (alive);
221 result = AudioObjectGetPropertyData(devid, &addr, 0,
NULL, &size, &alive);
223 (
"AudioDeviceGetProperty (kAudioDevicePropertyDeviceIsAlive)");
226 SDL_SetError(
"CoreAudio: requested device exists, but isn't alive.");
230 addr.mSelector = kAudioDevicePropertyHogMode;
232 result = AudioObjectGetPropertyData(devid, &addr, 0,
NULL, &size, &pid);
235 if ((result == noErr) && (pid != -1)) {
236 SDL_SetError(
"CoreAudio: requested device is being hogged.");
240 this->hidden->deviceID = devid;
248 AudioUnitRenderActionFlags * ioActionFlags,
249 const AudioTimeStamp * inTimeStamp,
250 UInt32 inBusNumber, UInt32 inNumberFrames,
251 AudioBufferList * ioData)
255 UInt32 remaining,
len;
260 if (!this->
enabled || this->paused) {
261 for (i = 0; i < ioData->mNumberBuffers; i++) {
262 abuf = &ioData->mBuffers[
i];
263 SDL_memset(abuf->mData, this->spec.silence, abuf->mDataByteSize);
276 for (i = 0; i < ioData->mNumberBuffers; i++) {
277 abuf = &ioData->mBuffers[
i];
278 remaining = abuf->mDataByteSize;
280 while (remaining > 0) {
281 if (this->hidden->bufferOffset >= this->hidden->bufferSize) {
284 (*this->spec.callback)(this->spec.userdata,
285 this->hidden->buffer, this->hidden->bufferSize);
287 this->hidden->bufferOffset = 0;
290 len = this->hidden->bufferSize - this->hidden->bufferOffset;
293 SDL_memcpy(ptr, (
char *)this->hidden->buffer +
294 this->hidden->bufferOffset, len);
295 ptr = (
char *)ptr + len;
297 this->hidden->bufferOffset +=
len;
306 AudioUnitRenderActionFlags * ioActionFlags,
307 const AudioTimeStamp * inTimeStamp,
308 UInt32 inBusNumber, UInt32 inNumberFrames,
309 AudioBufferList * ioData)
320 if (this->hidden !=
NULL) {
321 if (this->hidden->audioUnitOpened) {
323 AURenderCallbackStruct callback;
324 const AudioUnitElement output_bus = 0;
325 const AudioUnitElement input_bus = 1;
326 const int iscapture = this->iscapture;
327 const AudioUnitElement bus =
328 ((iscapture) ? input_bus : output_bus);
329 const AudioUnitScope scope =
330 ((iscapture) ? kAudioUnitScope_Output :
331 kAudioUnitScope_Input);
334 result = AudioOutputUnitStop(this->hidden->audioUnit);
337 SDL_memset(&callback, 0,
sizeof(AURenderCallbackStruct));
338 result = AudioUnitSetProperty(this->hidden->audioUnit,
339 kAudioUnitProperty_SetRenderCallback,
340 scope, bus, &callback,
344 CloseComponent(this->hidden->audioUnit);
346 AudioComponentInstanceDispose(this->hidden->audioUnit);
349 this->hidden->audioUnitOpened = 0;
360 const AudioStreamBasicDescription * strdesc)
363 AURenderCallbackStruct callback;
365 ComponentDescription desc;
368 AudioComponentDescription desc;
369 AudioComponent comp =
NULL;
371 const AudioUnitElement output_bus = 0;
372 const AudioUnitElement input_bus = 1;
373 const AudioUnitElement bus = ((iscapture) ? input_bus : output_bus);
374 const AudioUnitScope scope = ((iscapture) ? kAudioUnitScope_Output :
375 kAudioUnitScope_Input);
379 SDL_SetError(
"Couldn't find requested CoreAudio device");
385 desc.componentType = kAudioUnitType_Output;
386 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
389 desc.componentSubType = kAudioUnitSubType_DefaultOutput;
390 comp = FindNextComponent(
NULL, &desc);
392 desc.componentSubType = kAudioUnitSubType_RemoteIO;
393 comp = AudioComponentFindNext(
NULL, &desc);
397 SDL_SetError(
"Couldn't find requested CoreAudio component");
403 result = OpenAComponent(comp, &this->hidden->audioUnit);
410 result = AudioComponentInstanceNew(comp, &this->hidden->audioUnit);
414 this->hidden->audioUnitOpened = 1;
417 result = AudioUnitSetProperty(this->hidden->audioUnit,
418 kAudioOutputUnitProperty_CurrentDevice,
419 kAudioUnitScope_Global, 0,
420 &this->hidden->deviceID,
421 sizeof(AudioDeviceID));
423 (
"AudioUnitSetProperty (kAudioOutputUnitProperty_CurrentDevice)");
427 result = AudioUnitSetProperty(this->hidden->audioUnit,
428 kAudioUnitProperty_StreamFormat,
429 scope, bus, strdesc,
sizeof(*strdesc));
430 CHECK_RESULT(
"AudioUnitSetProperty (kAudioUnitProperty_StreamFormat)");
433 SDL_memset(&callback, 0,
sizeof(AURenderCallbackStruct));
435 callback.inputProcRefCon =
this;
436 result = AudioUnitSetProperty(this->hidden->audioUnit,
437 kAudioUnitProperty_SetRenderCallback,
438 scope, bus, &callback,
sizeof(callback));
440 (
"AudioUnitSetProperty (kAudioUnitProperty_SetRenderCallback)");
446 this->hidden->bufferOffset = this->hidden->bufferSize = this->spec.size;
447 this->hidden->buffer =
SDL_malloc(this->hidden->bufferSize);
449 result = AudioUnitInitialize(this->hidden->audioUnit);
453 result = AudioOutputUnitStart(this->hidden->audioUnit);
464 AudioStreamBasicDescription strdesc;
466 int valid_datatype = 0;
471 if (this->hidden ==
NULL) {
474 SDL_memset(this->hidden, 0, (
sizeof *this->hidden));
477 SDL_memset(&strdesc,
'\0',
sizeof(AudioStreamBasicDescription));
478 strdesc.mFormatID = kAudioFormatLinearPCM;
479 strdesc.mFormatFlags = kLinearPCMFormatFlagIsPacked;
480 strdesc.mChannelsPerFrame = this->spec.channels;
481 strdesc.mSampleRate = this->spec.freq;
482 strdesc.mFramesPerPacket = 1;
484 while ((!valid_datatype) && (test_format)) {
485 this->spec.format = test_format;
487 switch (test_format) {
501 strdesc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
504 strdesc.mFormatFlags |= kLinearPCMFormatFlagIsFloat;
506 strdesc.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
511 if (!valid_datatype) {
516 strdesc.mBytesPerFrame =
517 strdesc.mBitsPerChannel * strdesc.mChannelsPerFrame / 8;
518 strdesc.mBytesPerPacket =
519 strdesc.mBytesPerFrame * strdesc.mFramesPerPacket;
546 UInt32 category = kAudioSessionCategory_AmbientSound;
547 AudioSessionSetProperty(kAudioSessionProperty_AudioCategory,
sizeof(UInt32), &category);
void(* CloseDevice)(_THIS)
static OSStatus inputCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData)
static int find_device_by_name(_THIS, const char *devname, int iscapture)
SDL_AudioFormat SDL_FirstAudioFormat(SDL_AudioFormat format)
GLvoid **typedef void(GLAPIENTRY *PFNGLGETVERTEXATTRIBDVPROC)(GLuint
static void findDevId(const char *name, AudioDeviceID devId, void *_data)
void(* SDL_AddAudioDevice)(const char *name)
#define SDL_AUDIO_ISBIGENDIAN(x)
DECLSPEC int SDLCALL SDL_LockMutex(SDL_mutex *mutex)
GLenum GLsizei const GLuint GLboolean enabled
static OSStatus outputCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData)
DECLSPEC void SDLCALL SDL_free(void *mem)
int ProvidesOwnCallbackThread
#define SDL_AUDIO_ISSIGNED(x)
EGLImageKHR EGLint * name
static void addToDevList(const char *name, AudioDeviceID devId, void *data)
Uint16 SDL_AudioFormat
Audio format flags.
static int comp(const void *a, const void *b)
static int COREAUDIO_OpenDevice(_THIS, const char *devname, int iscapture)
int(* OpenDevice)(_THIS, const char *devname, int iscapture)
DECLSPEC int SDLCALL SDL_UnlockMutex(SDL_mutex *mutex)
#define SDL_AUDIO_ISFLOAT(x)
#define CHECK_RESULT(msg)
void(* DetectDevices)(int iscapture, SDL_AddAudioDevice addfn)
int OnlyHasDefaultOutputDevice
static void build_device_list(int iscapture, addDevFn addfn, void *addfndata)
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
#define SDL_AUDIO_BITSIZE(x)
DECLSPEC void *SDLCALL SDL_memset(void *dst, int c, size_t len)
DECLSPEC int SDLCALL SDL_SetError(const char *fmt,...)
DECLSPEC void *SDLCALL SDL_malloc(size_t size)
DECLSPEC int SDLCALL SDL_strcmp(const char *str1, const char *str2)
void SDL_CalculateAudioSpec(SDL_AudioSpec *spec)
static int prepare_audiounit(_THIS, const char *devname, int iscapture, const AudioStreamBasicDescription *strdesc)
AudioBootStrap COREAUDIO_bootstrap
static void COREAUDIO_CloseDevice(_THIS)
#define SDL_OutOfMemory()
void(* addDevFn)(const char *name, AudioDeviceID devId, void *data)
DECLSPEC void *SDLCALL SDL_memcpy(void *dst, const void *src, size_t len)
static int COREAUDIO_Init(SDL_AudioDriverImpl *impl)
static void COREAUDIO_DetectDevices(int iscapture, SDL_AddAudioDevice addfn)