comparison src/audio/macosx/SDL_coreaudio.c @ 2049:5f6550e5184f

Merged SDL-ryan-multiple-audio-device branch r2803:2871 into the trunk.
author Ryan C. Gordon <icculus@icculus.org>
date Tue, 17 Oct 2006 09:15:21 +0000
parents adf732f1f016
children 72cc2226d6a3
comparison
equal deleted inserted replaced
2048:6067c7f9a672 2049:5f6550e5184f
19 Sam Lantinga 19 Sam Lantinga
20 slouken@libsdl.org 20 slouken@libsdl.org
21 */ 21 */
22 #include "SDL_config.h" 22 #include "SDL_config.h"
23 23
24 #include <CoreAudio/CoreAudio.h>
24 #include <AudioUnit/AudioUnit.h> 25 #include <AudioUnit/AudioUnit.h>
25 26
26 #include "SDL_audio.h" 27 #include "SDL_audio.h"
27 #include "../SDL_audio_c.h" 28 #include "../SDL_audio_c.h"
28 #include "../SDL_sysaudio.h" 29 #include "../SDL_sysaudio.h"
29 #include "SDL_coreaudio.h" 30 #include "SDL_coreaudio.h"
30 31
31 32 #define DEBUG_COREAUDIO 0
32 /* Audio driver functions */ 33
33 34 typedef struct COREAUDIO_DeviceList
34 static int Core_OpenAudio(_THIS, SDL_AudioSpec * spec); 35 {
35 static void Core_WaitAudio(_THIS); 36 AudioDeviceID id;
36 static void Core_PlayAudio(_THIS); 37 const char *name;
37 static Uint8 *Core_GetAudioBuf(_THIS); 38 } COREAUDIO_DeviceList;
38 static void Core_CloseAudio(_THIS); 39
39 40 static COREAUDIO_DeviceList *inputDevices = NULL;
40 /* Audio driver bootstrap functions */ 41 static int inputDeviceCount = 0;
42 static COREAUDIO_DeviceList *outputDevices = NULL;
43 static int outputDeviceCount = 0;
44
45 static void
46 free_device_list(COREAUDIO_DeviceList **devices, int *devCount)
47 {
48 if (*devices) {
49 int i = *devCount;
50 while (i--)
51 SDL_free((void *) (*devices)[i].name);
52 SDL_free(*devices);
53 *devices = NULL;
54 }
55 *devCount = 0;
56 }
57
58
59 static void
60 build_device_list(int iscapture, COREAUDIO_DeviceList **devices, int *devCount)
61 {
62 Boolean outWritable = 0;
63 OSStatus result = noErr;
64 UInt32 size = 0;
65 AudioDeviceID *devs = NULL;
66 UInt32 i = 0;
67 UInt32 max = 0;
68
69 free_device_list(devices, devCount);
70
71 result = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices,
72 &size, &outWritable);
73
74 if (result != kAudioHardwareNoError)
75 return;
76
77 devs = (AudioDeviceID *) alloca(size);
78 if (devs == NULL)
79 return;
80
81 max = size / sizeof (AudioDeviceID);
82 *devices = (COREAUDIO_DeviceList *) SDL_malloc(max * sizeof (**devices));
83 if (*devices == NULL)
84 return;
85
86 result = AudioHardwareGetProperty(kAudioHardwarePropertyDevices,
87 &size, devs);
88 if (result != kAudioHardwareNoError)
89 return;
90
91 for (i = 0; i < max; i++) {
92 CFStringRef cfstr = NULL;
93 char *ptr = NULL;
94 AudioDeviceID dev = devs[i];
95 AudioBufferList *buflist = NULL;
96 int usable = 0;
97 CFIndex len = 0;
98
99 result = AudioDeviceGetPropertyInfo(dev, 0, iscapture,
100 kAudioDevicePropertyStreamConfiguration,
101 &size, &outWritable);
102 if (result != noErr)
103 continue;
104
105 buflist = (AudioBufferList *) SDL_malloc(size);
106 if (buflist == NULL)
107 continue;
108
109 result = AudioDeviceGetProperty(dev, 0, iscapture,
110 kAudioDevicePropertyStreamConfiguration,
111 &size, buflist);
112
113 if (result == noErr) {
114 UInt32 j;
115 for (j = 0; j < buflist->mNumberBuffers; j++) {
116 if (buflist->mBuffers[j].mNumberChannels > 0) {
117 usable = 1;
118 break;
119 }
120 }
121 }
122
123 SDL_free(buflist);
124
125 if (!usable)
126 continue;
127
128 size = sizeof (CFStringRef);
129 result = AudioDeviceGetProperty(dev, 0, iscapture,
130 kAudioObjectPropertyName,
131 &size, &cfstr);
132
133 if (result != kAudioHardwareNoError)
134 continue;
135
136 len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfstr),
137 kCFStringEncodingUTF8);
138
139 ptr = (char *) SDL_malloc(len + 1);
140 usable = ( (ptr != NULL) &&
141 (CFStringGetCString(cfstr,ptr,len+1,kCFStringEncodingUTF8)) );
142
143 CFRelease(cfstr);
144
145 if (usable) {
146 len = strlen(ptr);
147 /* Some devices have whitespace at the end...trim it. */
148 while ((len > 0) && (ptr[len-1] == ' ')) {
149 len--;
150 }
151 usable = (len > 0);
152 }
153
154 if (!usable) {
155 SDL_free(ptr);
156 } else {
157 ptr[len] = '\0';
158
159 #if DEBUG_COREAUDIO
160 printf("COREAUDIO: Found %s device #%d: '%s' (devid %d)\n",
161 ((iscapture) ? "capture" : "output"),
162 (int) *devCount, ptr, (int) dev);
163 #endif
164
165 (*devices)[*devCount].id = dev;
166 (*devices)[*devCount].name = ptr;
167 (*devCount)++;
168 }
169 }
170 }
171
172 static inline void
173 build_device_lists(void)
174 {
175 build_device_list(0, &outputDevices, &outputDeviceCount);
176 build_device_list(1, &inputDevices, &inputDeviceCount);
177 }
178
179
180 static inline void
181 free_device_lists(void)
182 {
183 free_device_list(&outputDevices, &outputDeviceCount);
184 free_device_list(&inputDevices, &inputDeviceCount);
185 }
186
41 187
42 static int 188 static int
43 Audio_Available(void) 189 find_device_id(const char *devname, int iscapture, AudioDeviceID *id)
44 { 190 {
45 return (1); 191 int i = ((iscapture) ? inputDeviceCount : outputDeviceCount);
46 } 192 COREAUDIO_DeviceList *devs = ((iscapture) ? inputDevices : outputDevices);
193 while (i--) {
194 if (SDL_strcmp(devname, devs->name) == 0) {
195 *id = devs->id;
196 return 1;
197 }
198 devs++;
199 }
200
201 return 0;
202 }
203
204
205 static int
206 COREAUDIO_DetectDevices(int iscapture)
207 {
208 if (iscapture) {
209 build_device_list(1, &inputDevices, &inputDeviceCount);
210 return inputDeviceCount;
211 } else {
212 build_device_list(0, &outputDevices, &outputDeviceCount);
213 return outputDeviceCount;
214 }
215
216 return 0; /* shouldn't ever hit this. */
217 }
218
219
220 static const char *
221 COREAUDIO_GetDeviceName(int index, int iscapture)
222 {
223 if ((iscapture) && (index < inputDeviceCount)) {
224 return inputDevices[index].name;
225 } else if ((!iscapture) && (index < outputDeviceCount)) {
226 return outputDevices[index].name;
227 }
228
229 SDL_SetError("No such device");
230 return NULL;
231 }
232
47 233
48 static void 234 static void
49 Audio_DeleteDevice(SDL_AudioDevice * device) 235 COREAUDIO_Deinitialize(void)
50 { 236 {
51 SDL_free(device->hidden); 237 free_device_lists();
52 SDL_free(device); 238 }
53 } 239
54
55 static SDL_AudioDevice *
56 Audio_CreateDevice(int devindex)
57 {
58 SDL_AudioDevice *this;
59
60 /* Initialize all variables that we clean on shutdown */
61 this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
62 if (this) {
63 SDL_memset(this, 0, (sizeof *this));
64 this->hidden = (struct SDL_PrivateAudioData *)
65 SDL_malloc((sizeof *this->hidden));
66 }
67 if ((this == NULL) || (this->hidden == NULL)) {
68 SDL_OutOfMemory();
69 if (this) {
70 SDL_free(this);
71 }
72 return (0);
73 }
74 SDL_memset(this->hidden, 0, (sizeof *this->hidden));
75
76 /* Set the function pointers */
77 this->OpenAudio = Core_OpenAudio;
78 this->WaitAudio = Core_WaitAudio;
79 this->PlayAudio = Core_PlayAudio;
80 this->GetAudioBuf = Core_GetAudioBuf;
81 this->CloseAudio = Core_CloseAudio;
82
83 this->free = Audio_DeleteDevice;
84
85 return this;
86 }
87
88 AudioBootStrap COREAUDIO_bootstrap = {
89 "coreaudio", "Mac OS X CoreAudio",
90 Audio_Available, Audio_CreateDevice
91 };
92 240
93 /* The CoreAudio callback */ 241 /* The CoreAudio callback */
94 static OSStatus 242 static OSStatus
95 audioCallback(void *inRefCon, 243 outputCallback(void *inRefCon,
96 AudioUnitRenderActionFlags inActionFlags, 244 AudioUnitRenderActionFlags *ioActionFlags,
97 const AudioTimeStamp * inTimeStamp, 245 const AudioTimeStamp * inTimeStamp,
98 UInt32 inBusNumber, AudioBuffer * ioData) 246 UInt32 inBusNumber, UInt32 inNumberFrames,
247 AudioBufferList *ioDataList)
99 { 248 {
100 SDL_AudioDevice *this = (SDL_AudioDevice *) inRefCon; 249 SDL_AudioDevice *this = (SDL_AudioDevice *) inRefCon;
250 AudioBuffer *ioData = &ioDataList->mBuffers[0];
101 UInt32 remaining, len; 251 UInt32 remaining, len;
102 void *ptr; 252 void *ptr;
253
254 /* Is there ever more than one buffer, and what do you do with it? */
255 if (ioDataList->mNumberBuffers != 1) {
256 return noErr;
257 }
103 258
104 /* Only do anything if audio is enabled and not paused */ 259 /* Only do anything if audio is enabled and not paused */
105 if (!this->enabled || this->paused) { 260 if (!this->enabled || this->paused) {
106 SDL_memset(ioData->mData, this->spec.silence, ioData->mDataByteSize); 261 SDL_memset(ioData->mData, this->spec.silence, ioData->mDataByteSize);
107 return 0; 262 return 0;
116 */ 271 */
117 272
118 remaining = ioData->mDataByteSize; 273 remaining = ioData->mDataByteSize;
119 ptr = ioData->mData; 274 ptr = ioData->mData;
120 while (remaining > 0) { 275 while (remaining > 0) {
121 if (bufferOffset >= bufferSize) { 276 if (this->hidden->bufferOffset >= this->hidden->bufferSize) {
122 /* Generate the data */ 277 /* Generate the data */
123 SDL_memset(buffer, this->spec.silence, bufferSize); 278 SDL_memset(this->hidden->buffer, this->spec.silence,
279 this->hidden->bufferSize);
124 SDL_mutexP(this->mixer_lock); 280 SDL_mutexP(this->mixer_lock);
125 (*this->spec.callback) (this->spec.userdata, buffer, bufferSize); 281 (*this->spec.callback) (this->spec.userdata, this->hidden->buffer,
282 this->hidden->bufferSize);
126 SDL_mutexV(this->mixer_lock); 283 SDL_mutexV(this->mixer_lock);
127 bufferOffset = 0; 284 this->hidden->bufferOffset = 0;
128 } 285 }
129 286
130 len = bufferSize - bufferOffset; 287 len = this->hidden->bufferSize - this->hidden->bufferOffset;
131 if (len > remaining) 288 if (len > remaining)
132 len = remaining; 289 len = remaining;
133 SDL_memcpy(ptr, (char *) buffer + bufferOffset, len); 290 SDL_memcpy(ptr,
291 (char *) this->hidden->buffer + this->hidden->bufferOffset,
292 len);
134 ptr = (char *) ptr + len; 293 ptr = (char *) ptr + len;
135 remaining -= len; 294 remaining -= len;
136 bufferOffset += len; 295 this->hidden->bufferOffset += len;
137 } 296 }
138 297
139 return 0; 298 return 0;
140 } 299 }
141 300
142 /* Dummy functions -- we don't use thread-based audio */ 301 static OSStatus
143 void 302 inputCallback(void *inRefCon,
144 Core_WaitAudio(_THIS) 303 AudioUnitRenderActionFlags *ioActionFlags,
145 { 304 const AudioTimeStamp * inTimeStamp,
146 return; 305 UInt32 inBusNumber, UInt32 inNumberFrames,
147 } 306 AudioBufferList *ioData)
148 307 {
149 void 308 //err = AudioUnitRender(afr->fAudioUnit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, afr->fAudioBuffer);
150 Core_PlayAudio(_THIS) 309 // !!! FIXME: write me!
151 { 310 return noErr;
152 return; 311 }
153 } 312
154 313
155 Uint8 * 314 static void
156 Core_GetAudioBuf(_THIS) 315 COREAUDIO_CloseDevice(_THIS)
157 { 316 {
158 return (NULL); 317 if (this->hidden != NULL) {
159 } 318 OSStatus result = noErr;
160 319 AURenderCallbackStruct callback;
161 void 320 const AudioUnitElement output_bus = 0;
162 Core_CloseAudio(_THIS) 321 const AudioUnitElement input_bus = 1;
163 { 322 const int iscapture = this->iscapture;
164 OSStatus result; 323 const AudioUnitElement bus = ((iscapture) ? input_bus : output_bus);
165 struct AudioUnitInputCallback callback; 324 const AudioUnitScope scope = ((iscapture) ? kAudioUnitScope_Output :
166 325 kAudioUnitScope_Input);
167 /* stop processing the audio unit */ 326
168 result = AudioOutputUnitStop(outputAudioUnit); 327 /* stop processing the audio unit */
169 if (result != noErr) { 328 result = AudioOutputUnitStop(this->hidden->audioUnit);
170 SDL_SetError("Core_CloseAudio: AudioOutputUnitStop"); 329
171 return; 330 /* Remove the input callback */
172 } 331 SDL_memset(&callback, '\0', sizeof (AURenderCallbackStruct));
173 332 result = AudioUnitSetProperty(this->hidden->audioUnit,
174 /* Remove the input callback */ 333 kAudioUnitProperty_SetRenderCallback,
175 callback.inputProc = 0; 334 scope, bus, &callback, sizeof (callback));
176 callback.inputProcRefCon = 0; 335
177 result = AudioUnitSetProperty(outputAudioUnit, 336 CloseComponent(this->hidden->audioUnit);
178 kAudioUnitProperty_SetInputCallback, 337
179 kAudioUnitScope_Input, 338 SDL_free(this->hidden->buffer);
180 0, &callback, sizeof(callback)); 339 SDL_free(this->hidden);
181 if (result != noErr) { 340 this->hidden = NULL;
182 SDL_SetError 341 }
183 ("Core_CloseAudio: AudioUnitSetProperty (kAudioUnitProperty_SetInputCallback)"); 342 }
184 return; 343
185 }
186
187 result = CloseComponent(outputAudioUnit);
188 if (result != noErr) {
189 SDL_SetError("Core_CloseAudio: CloseComponent");
190 return;
191 }
192
193 SDL_free(buffer);
194 }
195 344
196 #define CHECK_RESULT(msg) \ 345 #define CHECK_RESULT(msg) \
197 if (result != noErr) { \ 346 if (result != noErr) { \
347 COREAUDIO_CloseDevice(this); \
198 SDL_SetError("CoreAudio error (%s): %d", msg, (int) result); \ 348 SDL_SetError("CoreAudio error (%s): %d", msg, (int) result); \
199 return -1; \ 349 return 0; \
200 } 350 }
201 351
202 352 static int
203 int 353 find_device_by_name(_THIS, const char *devname, int iscapture)
204 Core_OpenAudio(_THIS, SDL_AudioSpec * spec) 354 {
205 { 355 AudioDeviceID devid = 0;
206 OSStatus result = noErr; 356 OSStatus result = noErr;
207 Component comp; 357 UInt32 size = 0;
358 UInt32 alive = 0;
359 pid_t pid = 0;
360
361 if (devname == NULL) {
362 size = sizeof (AudioDeviceID);
363 const AudioHardwarePropertyID propid =
364 ((iscapture) ? kAudioHardwarePropertyDefaultInputDevice :
365 kAudioHardwarePropertyDefaultOutputDevice);
366
367 result = AudioHardwareGetProperty(propid, &size, &devid);
368 CHECK_RESULT("AudioHardwareGetProperty (default device)");
369 } else {
370 if (!find_device_id(devname, iscapture, &devid)) {
371 SDL_SetError("CoreAudio: No such audio device.");
372 return 0;
373 }
374 }
375
376 size = sizeof (alive);
377 result = AudioDeviceGetProperty(devid, 0, iscapture,
378 kAudioDevicePropertyDeviceIsAlive,
379 &size, &alive);
380 CHECK_RESULT("AudioDeviceGetProperty (kAudioDevicePropertyDeviceIsAlive)");
381
382 if (!alive) {
383 SDL_SetError("CoreAudio: requested device exists, but isn't alive.");
384 return 0;
385 }
386
387 size = sizeof (pid);
388 result = AudioDeviceGetProperty(devid, 0, iscapture,
389 kAudioDevicePropertyHogMode, &size, &pid);
390
391 /* some devices don't support this property, so errors are fine here. */
392 if ((result == noErr) && (pid != -1)) {
393 SDL_SetError("CoreAudio: requested device is being hogged.");
394 return 0;
395 }
396
397 this->hidden->deviceID = devid;
398 return 1;
399 }
400
401
402 static int
403 prepare_audiounit(_THIS, const char *devname, int iscapture,
404 const AudioStreamBasicDescription *strdesc)
405 {
406 OSStatus result = noErr;
407 AURenderCallbackStruct callback;
208 ComponentDescription desc; 408 ComponentDescription desc;
209 struct AudioUnitInputCallback callback; 409 Component comp = NULL;
410 int use_system_device = 0;
411 UInt32 enableIO = 0;
412 const AudioUnitElement output_bus = 0;
413 const AudioUnitElement input_bus = 1;
414 const AudioUnitElement bus = ((iscapture) ? input_bus : output_bus);
415 const AudioUnitScope scope = ((iscapture) ? kAudioUnitScope_Output :
416 kAudioUnitScope_Input);
417
418 if (!find_device_by_name(this, devname, iscapture)) {
419 SDL_SetError("Couldn't find requested CoreAudio device");
420 return 0;
421 }
422
423 SDL_memset(&desc, '\0', sizeof(ComponentDescription));
424 desc.componentType = kAudioUnitType_Output;
425 desc.componentSubType = kAudioUnitSubType_HALOutput;
426 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
427
428 comp = FindNextComponent(NULL, &desc);
429 if (comp == NULL) {
430 SDL_SetError("Couldn't find requested CoreAudio component");
431 return 0;
432 }
433
434 /* Open & initialize the audio unit */
435 result = OpenAComponent(comp, &this->hidden->audioUnit);
436 CHECK_RESULT("OpenAComponent");
437
438 // !!! FIXME: this is wrong?
439 enableIO = ((iscapture) ? 1 : 0);
440 result = AudioUnitSetProperty(this->hidden->audioUnit,
441 kAudioOutputUnitProperty_EnableIO,
442 kAudioUnitScope_Input, input_bus,
443 &enableIO, sizeof (enableIO));
444 CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_EnableIO input)");
445
446 // !!! FIXME: this is wrong?
447 enableIO = ((iscapture) ? 0 : 1);
448 result = AudioUnitSetProperty(this->hidden->audioUnit,
449 kAudioOutputUnitProperty_EnableIO,
450 kAudioUnitScope_Output, output_bus,
451 &enableIO, sizeof (enableIO));
452 CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_EnableIO output)");
453
454 result = AudioUnitSetProperty(this->hidden->audioUnit,
455 kAudioOutputUnitProperty_CurrentDevice,
456 kAudioUnitScope_Global, 0,
457 &this->hidden->deviceID,
458 sizeof (AudioDeviceID));
459 CHECK_RESULT("AudioUnitSetProperty (kAudioOutputUnitProperty_CurrentDevice)");
460
461 /* Set the data format of the audio unit. */
462 result = AudioUnitSetProperty(this->hidden->audioUnit,
463 kAudioUnitProperty_StreamFormat,
464 scope, bus, strdesc, sizeof (*strdesc));
465 CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_StreamFormat)");
466
467 /* Set the audio callback */
468 SDL_memset(&callback, '\0', sizeof (AURenderCallbackStruct));
469 callback.inputProc = ((iscapture) ? inputCallback : outputCallback);
470 callback.inputProcRefCon = this;
471 result = AudioUnitSetProperty(this->hidden->audioUnit,
472 kAudioUnitProperty_SetRenderCallback,
473 scope, bus, &callback, sizeof (callback));
474 CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_SetInputCallback)");
475
476 /* Calculate the final parameters for this audio specification */
477 SDL_CalculateAudioSpec(&this->spec);
478
479 /* Allocate a sample buffer */
480 this->hidden->bufferOffset = this->hidden->bufferSize = this->spec.size;
481 this->hidden->buffer = SDL_malloc(this->hidden->bufferSize);
482
483 result = AudioUnitInitialize(this->hidden->audioUnit);
484 CHECK_RESULT("AudioUnitInitialize");
485
486 /* Finally, start processing of the audio unit */
487 result = AudioOutputUnitStart(this->hidden->audioUnit);
488 CHECK_RESULT("AudioOutputUnitStart");
489
490 /* We're running! */
491 return 1;
492 }
493
494
495 static int
496 COREAUDIO_OpenDevice(_THIS, const char *devname, int iscapture)
497 {
210 AudioStreamBasicDescription strdesc; 498 AudioStreamBasicDescription strdesc;
211 SDL_AudioFormat test_format = SDL_FirstAudioFormat(spec->format); 499 SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
212 int valid_datatype = 0; 500 int valid_datatype = 0;
213 501
502 /* Initialize all variables that we clean on shutdown */
503 this->hidden = (struct SDL_PrivateAudioData *)
504 SDL_malloc((sizeof *this->hidden));
505 if (this->hidden == NULL) {
506 SDL_OutOfMemory();
507 return (0);
508 }
509 SDL_memset(this->hidden, 0, (sizeof *this->hidden));
510
214 /* Setup a AudioStreamBasicDescription with the requested format */ 511 /* Setup a AudioStreamBasicDescription with the requested format */
215 memset(&strdesc, '\0', sizeof(AudioStreamBasicDescription)); 512 SDL_memset(&strdesc, '\0', sizeof(AudioStreamBasicDescription));
216 strdesc.mFormatID = kAudioFormatLinearPCM; 513 strdesc.mFormatID = kAudioFormatLinearPCM;
217 strdesc.mFormatFlags = kLinearPCMFormatFlagIsPacked; 514 strdesc.mFormatFlags = kLinearPCMFormatFlagIsPacked;
218 strdesc.mChannelsPerFrame = spec->channels; 515 strdesc.mChannelsPerFrame = this->spec.channels;
219 strdesc.mSampleRate = spec->freq; 516 strdesc.mSampleRate = this->spec.freq;
220 strdesc.mFramesPerPacket = 1; 517 strdesc.mFramesPerPacket = 1;
221 518
222 while ((!valid_datatype) && (test_format)) { 519 while ((!valid_datatype) && (test_format)) {
223 spec->format = test_format; 520 this->spec.format = test_format;
224 /* Just a list of valid SDL formats, so people don't pass junk here. */ 521 /* Just a list of valid SDL formats, so people don't pass junk here. */
225 switch (test_format) { 522 switch (test_format) {
226 case AUDIO_U8: 523 case AUDIO_U8:
227 case AUDIO_S8: 524 case AUDIO_S8:
228 case AUDIO_U16LSB: 525 case AUDIO_U16LSB:
232 case AUDIO_S32LSB: 529 case AUDIO_S32LSB:
233 case AUDIO_S32MSB: 530 case AUDIO_S32MSB:
234 case AUDIO_F32LSB: 531 case AUDIO_F32LSB:
235 case AUDIO_F32MSB: 532 case AUDIO_F32MSB:
236 valid_datatype = 1; 533 valid_datatype = 1;
237 strdesc.mBitsPerChannel = SDL_AUDIO_BITSIZE(spec->format); 534 strdesc.mBitsPerChannel = SDL_AUDIO_BITSIZE(this->spec.format);
238 if (SDL_AUDIO_ISBIGENDIAN(spec->format)) 535 if (SDL_AUDIO_ISBIGENDIAN(this->spec.format))
239 strdesc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian; 536 strdesc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
240 537
241 if (SDL_AUDIO_ISFLOAT(spec->format)) 538 if (SDL_AUDIO_ISFLOAT(this->spec.format))
242 strdesc.mFormatFlags |= kLinearPCMFormatFlagIsFloat; 539 strdesc.mFormatFlags |= kLinearPCMFormatFlagIsFloat;
243 else if (SDL_AUDIO_ISSIGNED(spec->format)) 540 else if (SDL_AUDIO_ISSIGNED(this->spec.format))
244 strdesc.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger; 541 strdesc.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
245 break; 542 break;
246 } 543 }
247 } 544 }
248 545
249 if (!valid_datatype) { /* shouldn't happen, but just in case... */ 546 if (!valid_datatype) { /* shouldn't happen, but just in case... */
250 SDL_SetError("Unsupported audio format"); 547 SDL_SetError("Unsupported audio format");
251 return (-1); 548 return 0;
252 } 549 }
253 550
254 strdesc.mBytesPerFrame = 551 strdesc.mBytesPerFrame =
255 strdesc.mBitsPerChannel * strdesc.mChannelsPerFrame / 8; 552 strdesc.mBitsPerChannel * strdesc.mChannelsPerFrame / 8;
256 strdesc.mBytesPerPacket = 553 strdesc.mBytesPerPacket =
257 strdesc.mBytesPerFrame * strdesc.mFramesPerPacket; 554 strdesc.mBytesPerFrame * strdesc.mFramesPerPacket;
258 555
259 /* Locate the default output audio unit */ 556 if (!prepare_audiounit(this, devname, iscapture, &strdesc)) {
260 memset(&desc, '\0', sizeof(ComponentDescription)); 557 return 0; /* prepare_audiounit() will call SDL_SetError()... */
261 desc.componentType = kAudioUnitComponentType; 558 }
262 desc.componentSubType = kAudioUnitSubType_Output; 559
263 desc.componentManufacturer = kAudioUnitID_DefaultOutput; 560 return 1; /* good to go. */
264 desc.componentFlags = 0; 561 }
265 desc.componentFlagsMask = 0; 562
266 563 static int
267 comp = FindNextComponent(NULL, &desc); 564 COREAUDIO_Init(SDL_AudioDriverImpl *impl)
268 if (comp == NULL) { 565 {
269 SDL_SetError 566 /* Set the function pointers */
270 ("Failed to start CoreAudio: FindNextComponent returned NULL"); 567 impl->DetectDevices = COREAUDIO_DetectDevices;
271 return -1; 568 impl->GetDeviceName = COREAUDIO_GetDeviceName;
272 } 569 impl->OpenDevice = COREAUDIO_OpenDevice;
273 570 impl->CloseDevice = COREAUDIO_CloseDevice;
274 /* Open & initialize the default output audio unit */ 571 impl->Deinitialize = COREAUDIO_Deinitialize;
275 result = OpenAComponent(comp, &outputAudioUnit); 572 impl->ProvidesOwnCallbackThread = 1;
276 CHECK_RESULT("OpenAComponent") 573
277 result = AudioUnitInitialize(outputAudioUnit); 574 build_device_lists(); /* do an initial check for devices... */
278 CHECK_RESULT("AudioUnitInitialize") 575
279 /* Set the input format of the audio unit. */ 576 return 1;
280 result = AudioUnitSetProperty(outputAudioUnit, 577 }
281 kAudioUnitProperty_StreamFormat, 578
282 kAudioUnitScope_Input, 579 AudioBootStrap COREAUDIO_bootstrap = {
283 0, &strdesc, sizeof(strdesc)); 580 "coreaudio", "Mac OS X CoreAudio", COREAUDIO_Init, 0
284 CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_StreamFormat)") 581 };
285 /* Set the audio callback */
286 callback.inputProc = audioCallback;
287 callback.inputProcRefCon = this;
288 result = AudioUnitSetProperty(outputAudioUnit,
289 kAudioUnitProperty_SetInputCallback,
290 kAudioUnitScope_Input,
291 0, &callback, sizeof(callback));
292 CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_SetInputCallback)")
293 /* Calculate the final parameters for this audio specification */
294 SDL_CalculateAudioSpec(spec);
295
296 /* Allocate a sample buffer */
297 bufferOffset = bufferSize = this->spec.size;
298 buffer = SDL_malloc(bufferSize);
299
300 /* Finally, start processing of the audio unit */
301 result = AudioOutputUnitStart(outputAudioUnit);
302 CHECK_RESULT("AudioOutputUnitStart")
303 /* We're running! */
304 return (1);
305 }
306 582
307 /* vi: set ts=4 sw=4 expandtab: */ 583 /* vi: set ts=4 sw=4 expandtab: */