--- a/src/audio/coreaudio/SDL_coreaudio.c Mon Aug 01 00:18:56 2016 -0400
+++ b/src/audio/coreaudio/SDL_coreaudio.c Mon Aug 01 00:20:47 2016 -0400
@@ -185,7 +185,7 @@
#if DEBUG_COREAUDIO
printf("COREAUDIO: Found %s device #%d: '%s' (devid %d)\n",
((iscapture) ? "capture" : "output"),
- (int) *devCount, ptr, (int) dev);
+ (int) i, ptr, (int) dev);
#endif
addfn(ptr, iscapture, dev, addfndata);
}
@@ -324,18 +324,52 @@
}
}
- return 0;
+ return noErr;
}
static OSStatus
inputCallback(void *inRefCon,
- AudioUnitRenderActionFlags * ioActionFlags,
- const AudioTimeStamp * inTimeStamp,
+ AudioUnitRenderActionFlags *ioActionFlags,
+ const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber, UInt32 inNumberFrames,
- AudioBufferList * ioData)
+ AudioBufferList *ioData)
{
- /* err = AudioUnitRender(afr->fAudioUnit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, afr->fAudioBuffer); */
- /* !!! FIXME: write me! */
+ SDL_AudioDevice *this = (SDL_AudioDevice *) inRefCon;
+ if (!this->enabled || 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;
}
@@ -394,20 +428,21 @@
const int iscapture = this->iscapture;
const AudioUnitElement bus =
((iscapture) ? input_bus : output_bus);
- const AudioUnitScope scope =
- ((iscapture) ? kAudioUnitScope_Output :
- kAudioUnitScope_Input);
/* stop processing the audio unit */
AudioOutputUnitStop(this->hidden->audioUnit);
/* Remove the input callback */
- SDL_memset(&callback, 0, sizeof(AURenderCallbackStruct));
+ SDL_zero(callback);
AudioUnitSetProperty(this->hidden->audioUnit,
- kAudioUnitProperty_SetRenderCallback,
- scope, bus, &callback, sizeof(callback));
+ 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);
@@ -480,9 +515,6 @@
AudioComponent comp = NULL;
const AudioUnitElement output_bus = 0;
const AudioUnitElement input_bus = 1;
- const AudioUnitElement bus = ((iscapture) ? input_bus : output_bus);
- const AudioUnitScope scope = ((iscapture) ? kAudioUnitScope_Output :
- kAudioUnitScope_Input);
#if MACOSX_COREAUDIO
if (!prepare_device(this, handle, iscapture)) {
@@ -495,7 +527,7 @@
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
#if MACOSX_COREAUDIO
- desc.componentSubType = kAudioUnitSubType_DefaultOutput;
+ desc.componentSubType = iscapture ? kAudioUnitSubType_HALOutput : kAudioUnitSubType_DefaultOutput;
#else
desc.componentSubType = kAudioUnitSubType_RemoteIO;
#endif
@@ -513,9 +545,28 @@
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, 0,
+ kAudioUnitScope_Global, output_bus,
&this->hidden->deviceID,
sizeof(AudioDeviceID));
CHECK_RESULT
@@ -525,16 +576,47 @@
/* Set the data format of the audio unit. */
result = AudioUnitSetProperty(this->hidden->audioUnit,
kAudioUnitProperty_StreamFormat,
- scope, bus, strdesc, sizeof(*strdesc));
+ 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_memset(&callback, 0, sizeof(AURenderCallbackStruct));
+ SDL_zero(callback);
callback.inputProc = ((iscapture) ? inputCallback : outputCallback);
callback.inputProcRefCon = this;
+
result = AudioUnitSetProperty(this->hidden->audioUnit,
- kAudioUnitProperty_SetRenderCallback,
- scope, bus, &callback, sizeof(callback));
+ iscapture ? kAudioOutputUnitProperty_SetInputCallback : kAudioUnitProperty_SetRenderCallback,
+ kAudioUnitScope_Global, output_bus, &callback, sizeof(callback));
CHECK_RESULT
("AudioUnitSetProperty (kAudioUnitProperty_SetRenderCallback)");
@@ -542,8 +624,15 @@
SDL_CalculateAudioSpec(&this->spec);
/* Allocate a sample buffer */
- this->hidden->bufferOffset = this->hidden->bufferSize = this->spec.size;
+ 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");
@@ -552,6 +641,8 @@
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);
@@ -575,10 +666,10 @@
if (this->hidden == NULL) {
return SDL_OutOfMemory();
}
- SDL_memset(this->hidden, 0, (sizeof *this->hidden));
+ SDL_zerop(this->hidden);
/* Setup a AudioStreamBasicDescription with the requested format */
- SDL_memset(&strdesc, '\0', sizeof(AudioStreamBasicDescription));
+ SDL_zero(strdesc);
strdesc.mFormatID = kAudioFormatLinearPCM;
strdesc.mFormatFlags = kLinearPCMFormatFlagIsPacked;
strdesc.mChannelsPerFrame = this->spec.channels;
@@ -651,6 +742,7 @@
#if MACOSX_COREAUDIO
impl->DetectDevices = COREAUDIO_DetectDevices;
AudioObjectAddPropertyListener(kAudioObjectSystemObject, &devlist_address, device_list_changed, NULL);
+ impl->HasCaptureSupport = 1;
#else
impl->OnlyHasDefaultOutputDevice = 1;