diff options
Diffstat (limited to 'src/audioOutputs/audioOutput_osx.c')
-rw-r--r-- | src/audioOutputs/audioOutput_osx.c | 329 |
1 files changed, 143 insertions, 186 deletions
diff --git a/src/audioOutputs/audioOutput_osx.c b/src/audioOutputs/audioOutput_osx.c index ab31cc6f6..c14bdc17d 100644 --- a/src/audioOutputs/audioOutput_osx.c +++ b/src/audioOutputs/audioOutput_osx.c @@ -20,73 +20,28 @@ #ifdef HAVE_OSX -#include "../conf.h" -#include "../log.h" - -#include <CoreAudio/AudioHardware.h> +#include <AudioUnit/AudioUnit.h> #include <stdlib.h> #include <pthread.h> -#define BUFFER_SIZE 1024 +#include "../log.h" + +#define BUFFER_SIZE 8192 typedef struct _OsxData { - AudioDeviceID deviceID; - AudioStreamBasicDescription streamDesc; + AudioUnit au; pthread_mutex_t mutex; pthread_cond_t condition; - Float32 buffer[BUFFER_SIZE]; + char buffer[BUFFER_SIZE]; int pos; int len; int go; int started; } OsxData; -static void printError(OSStatus val) { - switch(val) { - case kAudioHardwareNoError: - ERROR("kAudioHardwareNoErr"); - break; - case kAudioHardwareNotRunningError: - ERROR("kAudioHardwareNotRunningError"); - break; - case kAudioHardwareUnspecifiedError: - ERROR("kAudioHardwareUnspecifiedError"); - break; - case kAudioHardwareUnknownPropertyError: - ERROR("kAudioHardwareUnknownPropertyError"); - break; - case kAudioHardwareBadPropertySizeError: - ERROR("kAudioHardwareBadPropertySizeError"); - break; - case kAudioHardwareIllegalOperationError: - ERROR("kAudioHardwareIllegalOperationError"); - break; - case kAudioHardwareBadDeviceError: - ERROR("kAudioHardwareBadDeviceError"); - break; - case kAudioHardwareBadStreamError: - ERROR("kAudioHardwareBadStreamError"); - break; - case kAudioHardwareUnsupportedOperationError: - ERROR("kAudioHardwareUnsupportedOperationError"); - break; - case kAudioDeviceUnsupportedFormatError: - ERROR("kAudioDeviceUnsupportedFormatError"); - break; - case kAudioDevicePermissionsError: - ERROR("kAudioDevicePermissionsError"); - break; - default: - ERROR("unknown"); - break; - } -} - static OsxData * newOsxData() { OsxData * ret = malloc(sizeof(OsxData)); - ret->deviceID = kAudioDeviceUnknown; - pthread_mutex_init(&ret->mutex, NULL); pthread_cond_init(&ret->condition, NULL); @@ -99,17 +54,28 @@ static OsxData * newOsxData() { } static int osx_testDefault() { - int err; - AudioDeviceID deviceID; - UInt32 propertySize = sizeof(deviceID); - - err = AudioHardwareGetProperty( - kAudioHardwarePropertyDefaultOutputDevice, - &propertySize, &deviceID); - if(err || deviceID == kAudioDeviceUnknown) { - WARNING("Not able to get the default OS X device\n"); + /*AudioUnit au; + ComponentDescription desc; + Component comp; + + desc.componentType = kAudioUnitType_Output; + desc.componentSubType = kAudioUnitSubType_Output; + desc.componentManufacturer = kAudioUnitManufacturer_Apple; + desc.componentFlags = 0; + desc.componentFlagsMask = 0; + + comp = FindNextComponent(NULL, &desc); + if(!comp) { + ERROR("Unable to open default OS X defice\n"); + return -1; + } + + if(OpenAComponent(comp, &au) != noErr) { + ERROR("Unable to open default OS X defice\n"); return -1; } + + CloseComponent(au);*/ return 0; } @@ -141,109 +107,132 @@ static void osx_closeDevice(AudioOutput * audioOutput) { audioOutput->open = 0; } -static OSStatus osx_IOProc(AudioDeviceID deviceID, - const AudioTimeStamp * inNow, const AudioBufferList *inData, - const AudioTimeStamp * inInputTime, AudioBufferList *outData, - const AudioTimeStamp * inOutputTime, void * vdata) +static OSStatus osx_render(void * vdata, + AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp * inTimeStamp, + UInt32 inBusNumber, UInt32 inNumberFrames, + AudioBufferList *bufferList) { OsxData * od = (OsxData *)vdata; - AudioBuffer * buffer = &outData->mBuffers[0]; - int bufferSize = buffer->mDataByteSize/sizeof(Float32); - int floatsToCopy; + AudioBuffer * buffer = &bufferList->mBuffers[0]; + int bufferSize = buffer->mDataByteSize; + int bytesToCopy; int curpos = 0; - DEBUG("entering IOProc\n"); - pthread_mutex_lock(&od->mutex); while((od->go || od->len) && bufferSize) { while(od->go && od->len < bufferSize && od->len < BUFFER_SIZE) { + pthread_cond_signal(&od->condition); pthread_cond_wait(&od->condition, &od->mutex); } - floatsToCopy = od->len < bufferSize ? od->len : bufferSize; - bufferSize -= floatsToCopy; + bytesToCopy = od->len < bufferSize ? od->len : bufferSize; + bufferSize -= bytesToCopy; + od->len -= bytesToCopy; - if(od->pos+floatsToCopy > BUFFER_SIZE) { - int floats = BUFFER_SIZE-od->pos; - memcpy(buffer->mData+curpos, od->buffer+od->pos, - floats*sizeof(Float32)); - od->len -= floats; + if(od->pos+bytesToCopy > BUFFER_SIZE) { + int bytes = BUFFER_SIZE-od->pos; + memcpy(buffer->mData+curpos, od->buffer+od->pos, bytes); od->pos = 0; - curpos += floats; - floatsToCopy -= floats; + curpos += bytes; + bytesToCopy -= bytes; } - memcpy(buffer->mData+curpos, od->buffer+od->pos, - floatsToCopy*sizeof(Float32)); - od->len -= floatsToCopy; - od->pos += floatsToCopy; - curpos += floatsToCopy; + assert(bytesToCopy); + memcpy(buffer->mData+curpos, od->buffer+od->pos, bytesToCopy); + od->pos += bytesToCopy; + curpos += bytesToCopy; + + if(od->pos >= BUFFER_SIZE) od->pos = 0; } if(bufferSize) { - memset(buffer->mData+curpos, 0, bufferSize*sizeof(Float32)); + memset(buffer->mData+curpos, 0, bufferSize); } - pthread_mutex_unlock(&od->mutex); pthread_cond_signal(&od->condition); - - DEBUG("exiting IOProc\n"); + pthread_mutex_unlock(&od->mutex); return 0; } static int osx_openDevice(AudioOutput * audioOutput) { - int err; OsxData * od = (OsxData *)audioOutput->data; - UInt32 propertySize; + ComponentDescription desc; + Component comp; + AURenderCallbackStruct callback; AudioFormat * audioFormat = &audioOutput->outAudioFormat; - UInt32 bufferByteCount = 8192; - - propertySize = sizeof(od->deviceID); - err = AudioHardwareGetProperty( - kAudioHardwarePropertyDefaultOutputDevice, - &propertySize, &od->deviceID); - if(err || od->deviceID == kAudioDeviceUnknown) { - ERROR("Not able to get the default OS X device\n"); + AudioStreamBasicDescription streamDesc; + + desc.componentType = kAudioUnitType_Output; + desc.componentSubType = kAudioUnitSubType_DefaultOutput; + desc.componentManufacturer = kAudioUnitManufacturer_Apple; + desc.componentFlags = 0; + desc.componentFlagsMask = 0; + + DEBUG("finding component\n"); + + comp = FindNextComponent(NULL, &desc); + if(comp == 0) { + ERROR("Error finding OS X component\n"); return -1; } - od->streamDesc.mFormatID = kAudioFormatLinearPCM; - od->streamDesc.mSampleRate = audioFormat->sampleRate; - od->streamDesc.mFormatFlags = kLinearPCMFormatFlagIsFloat | - kLinearPCMFormatFlagIsBigEndian | - kLinearPCMFormatFlagIsPacked; - od->streamDesc.mBytesPerPacket = audioFormat->channels*sizeof(Float32); - od->streamDesc.mFramesPerPacket = 1; - od->streamDesc.mBytesPerFrame = audioFormat->channels*sizeof(Float32); - od->streamDesc.mChannelsPerFrame = audioFormat->channels; - od->streamDesc.mBitsPerChannel = 8 * sizeof(Float32); - - audioFormat->bits = 16; - - propertySize = sizeof(od->streamDesc); - err = AudioDeviceSetProperty(od->deviceID, 0, 0, false, - kAudioDevicePropertyStreamFormat, - propertySize, &od->streamDesc); - if(err) { - ERROR("unable to set format %i:%i:% on osx device\n", - (int)audioFormat->sampleRate, - (int)audioFormat->bits, - (int)audioFormat->channels); + DEBUG("opening component\n"); + if(OpenAComponent(comp, &od->au) != noErr) { + ERROR("Unable to open OS X component\n"); return -1; } - propertySize = sizeof(UInt32); - err = AudioDeviceSetProperty(od->deviceID, 0, 0, false, - kAudioDevicePropertyBufferSize, - propertySize, &bufferByteCount); + DEBUG("initializing au\n"); + if(AudioUnitInitialize(od->au) != 0) { + CloseComponent(od->au); + ERROR("Unable to initialuze OS X audio unit\n"); + return -1; + } + + callback.inputProc = osx_render; + callback.inputProcRefCon = od; + + DEBUG("set callback\n"); + if(AudioUnitSetProperty(od->au, kAudioUnitProperty_SetRenderCallback, + kAudioUnitScope_Input, 0, + &callback, sizeof(callback)) != 0) + { + AudioUnitUninitialize(od->au); + CloseComponent(od->au); + ERROR("unable to set callbak for OS X audio unit\n"); + return -1; + } - err = AudioDeviceAddIOProc(od->deviceID, osx_IOProc, od); + streamDesc.mSampleRate = audioFormat->sampleRate; + streamDesc.mFormatID = kAudioFormatLinearPCM; + streamDesc.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | + kLinearPCMFormatFlagIsBigEndian; + streamDesc.mBytesPerPacket = audioFormat->channels*audioFormat->bits/8; + streamDesc.mFramesPerPacket = 1; + streamDesc.mBytesPerFrame = streamDesc.mBytesPerPacket; + streamDesc.mChannelsPerFrame = audioFormat->channels; + streamDesc.mBitsPerChannel = audioFormat->bits; + + DEBUG("set format\n"); + if(AudioUnitSetProperty(od->au, kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, 0, + &streamDesc, sizeof(streamDesc)) != 0) + { + AudioUnitUninitialize(od->au); + CloseComponent(od->au); + ERROR("Unable to set format on OS X device\n"); + return -1; + } + + DEBUG("start\n"); + int err = AudioOutputUnitStart(od->au); if(err) { - ERROR("error adding IOProc\n"); + ERROR("unable to start audio output: %i\n", err); return -1; } @@ -253,86 +242,54 @@ static int osx_openDevice(AudioOutput * audioOutput) { audioOutput->open = 1; + DEBUG("opened OS X device\n"); return 0; } -static void copyIntBufferToFloat(char * playChunk, int size, float * buffer, - int floats) -{ - /* this is for 16-bit audio only */ - SInt16 * sample; - - while(floats) { - sample = (SInt16 *)playChunk; - *buffer = *sample/32767.0; - playChunk += 2; - buffer++; - floats--; - } -} - static int osx_play(AudioOutput * audioOutput, char * playChunk, int size) { OsxData * od = (OsxData *)audioOutput->data; - int floatsToCopy; - - size /= 2; - - DEBUG("entering osx_play\n"); + int bytesToCopy; + int curpos; pthread_mutex_lock(&od->mutex); - DEBUG("entering while loop\n"); + curpos = od->pos+od->len; + if(curpos >= BUFFER_SIZE) curpos -= BUFFER_SIZE; + while(size) { - DEBUG("iterating loop with size = %i\n", size); - while(od->len == BUFFER_SIZE) { - if(!od->started) { - OSStatus err = AudioDeviceStart(od->deviceID, - osx_IOProc); - DEBUG("start audio device\n"); - if(err) { - printError(err); - ERROR(" error doing AudioDeviceStart " - "for osx device: %i\n", - (int)err); - pthread_mutex_unlock(&od->mutex); - return -1; - } - od->started = 1; - DEBUG("audio device started\n"); + while(od->len >= BUFFER_SIZE) { + if(curpos!=od->pos) { + DEBUG("%i != %i\n", curpos, od->pos); + abort(); } - - DEBUG("cond_wait\n"); + pthread_cond_signal(&od->condition); pthread_cond_wait(&od->condition, &od->mutex); } - floatsToCopy = BUFFER_SIZE - od->len; - floatsToCopy = floatsToCopy < size ? floatsToCopy : size; - size -= floatsToCopy; - - if(od->pos+floatsToCopy > BUFFER_SIZE) { - int floats = BUFFER_SIZE-od->pos; - copyIntBufferToFloat(playChunk, - audioOutput->outAudioFormat.bits/8, - od->buffer, - floats); - od->pos = 0; - od->len += floats; - playChunk += floats*sizeof(Float32); + bytesToCopy = BUFFER_SIZE - od->len; + bytesToCopy = bytesToCopy < size ? bytesToCopy : size; + size -= bytesToCopy; + od->len += bytesToCopy; + + if(curpos+bytesToCopy > BUFFER_SIZE) { + int bytes = BUFFER_SIZE-curpos; + memcpy(od->buffer+curpos, playChunk, bytes); + curpos = 0; + playChunk += bytes; + bytesToCopy -= bytes; } - copyIntBufferToFloat(playChunk, - audioOutput->outAudioFormat.bits/8, - od->buffer, - floatsToCopy); - od->pos += floatsToCopy; - od->len += floatsToCopy; - playChunk += floatsToCopy*sizeof(Float32); + assert(bytesToCopy); + memcpy(od->buffer+curpos, playChunk, bytesToCopy); + curpos += bytesToCopy; + playChunk += bytesToCopy; + + if(curpos >= BUFFER_SIZE) curpos = 0; } - pthread_mutex_unlock(&od->mutex); pthread_cond_signal(&od->condition); + pthread_mutex_unlock(&od->mutex); - DEBUG("exiting osx_play\n"); return 0; } |