From b5c028a4a4813a656c4553e01596f3e40f9728ed Mon Sep 17 00:00:00 2001 From: Jonathan Howard Date: Mon, 14 Dec 2015 02:21:13 -0500 Subject: [PATCH] initial implementation of CoreAudio driver --- src/CMakeLists.txt | 8 ++ src/drivers.c | 6 ++ src/drivers/coreaudiodrv.c | 205 +++++++++++++++++++++++++++++++++++++ src/drivers/coreaudiodrv.h | 32 ++++++ 4 files changed, 251 insertions(+) create mode 100644 src/drivers/coreaudiodrv.c create mode 100644 src/drivers/coreaudiodrv.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 52d0b44..b5c4bf0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -52,6 +52,7 @@ set(sources ${sources} drivers/bufferdrv.c drivers/dummydrv.c drivers/mallocdrv.c + drivers/coreaudiodrv.c ) if(SDL_FOUND) @@ -70,6 +71,13 @@ find_package(Threads) add_library(audiality2 ${sources}) +if(APPLE) + find_library(CORE_AUDIO CoreAudio) + find_library(AUDIO_TOOLBOX AudioToolbox) + + target_link_libraries(audiality2 ${CORE_AUDIO} ${AUDIO_TOOLBOX}) +endif(APPLE) + if(UNIX) target_link_libraries(audiality2 m) endif(UNIX) diff --git a/src/drivers.c b/src/drivers.c index 0de54c8..a597eee 100644 --- a/src/drivers.c +++ b/src/drivers.c @@ -35,6 +35,7 @@ #include "jackdrv.h" #include "dummydrv.h" #include "bufferdrv.h" +#include "coreaudiodrv.h" #define A2_DEFAULT_SYSDRIVER a2_malloc_sysdriver @@ -42,6 +43,8 @@ # define A2_DEFAULT_AUDIODRIVER a2_sdl_audiodriver #elif defined(A2_HAVE_JACK) # define A2_DEFAULT_AUDIODRIVER a2_jack_audiodriver +#elif defined(__APPLE__) && !defined(A2_DEFAULT_AUDIODRIVER) +# define A2_DEFAULT_AUDIODRIVER a2_coreaudio_audiodriver #else # define A2_DEFAULT_AUDIODRIVER a2_dummy_audiodriver #endif @@ -271,6 +274,9 @@ static A2_regdriver a2_builtin_drivers[] = { #endif #ifdef A2_HAVE_JACK { NULL, A2_AUDIODRIVER, 1, "jack", a2_jack_audiodriver }, +#endif +#ifdef __APPLE__ + { NULL, A2_AUDIODRIVER, 1, "coreaudio", a2_coreaudio_audiodriver }, #endif { NULL, A2_AUDIODRIVER, 1, "dummy", a2_dummy_audiodriver }, { NULL, A2_AUDIODRIVER, 1, "buffer", a2_buffer_audiodriver }, diff --git a/src/drivers/coreaudiodrv.c b/src/drivers/coreaudiodrv.c new file mode 100644 index 0000000..4d46b7e --- /dev/null +++ b/src/drivers/coreaudiodrv.c @@ -0,0 +1,205 @@ +/* + * coreaudiodrv.c - Audiality 2 Core Audio driver + * + * Copyright 2015 Jonathan Howard + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from the + * use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#ifdef __APPLE__ + +#include +#include + +#include "coreaudiodrv.h" +#include "platform.h" + +/* Extended A2_audiodriver struct */ +static const int kNumBuffers = 2; +typedef struct CoreAudio_audiodriver +{ + A2_audiodriver ad; + AudioQueueRef queue; + AudioQueueBufferRef buffer[kNumBuffers]; + AudioStreamBasicDescription desc; +} CoreAudio_audiodriver; + +/* CoreAudio render thread callback */ +static void coreaudio_process(void * inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) +{ + A2_audiodriver *driver = (A2_audiodriver *)inUserData; + CoreAudio_audiodriver * cad = (CoreAudio_audiodriver *)inUserData; + A2_config * config = driver->driver.config; + int c, i; + + int frames = config->buffer; + + if( driver->Process ) + { + driver->Process(driver, config->buffer); + } + else + { + for ( c = 0; c < config->channels; c++ ) + { + memset(driver->buffers[c], 0, sizeof(int32_t) * config->buffer); + } + } + + for ( i = 0; i < frames; i++ ) + { + for ( c = 0; c < config->channels; c++ ) + { + ((int32_t *)inBuffer->mAudioData)[i + c] = driver->buffers[c][i]; + } + } + inBuffer->mAudioDataByteSize = inBuffer->mAudioDataBytesCapacity; + + AudioQueueEnqueueBuffer(cad->queue, inBuffer, 0, NULL); +} + +static void coreaudiod_Close(A2_driver *driver) +{ + CoreAudio_audiodriver * cad = (CoreAudio_audiodriver *)driver; + + AudioQueueStop(cad->queue, true); + + if ( cad->ad.buffers ) + { + int c; + for ( c = 0; c < cad->ad.driver.config->channels; c++ ) + free( cad->ad.buffers[c] ); + free( cad->ad.buffers ); + } + + AudioQueueDispose(cad->queue, true); + + cad->ad.Run = NULL; + cad->ad.Lock = NULL; + cad->ad.Unlock = NULL; +} + +static void coreaudio_Lock(A2_audiodriver * driver) +{ +} + +static void coreaudio_Unlock(A2_audiodriver * driver) +{ +} + +static A2_errors coreaudiod_Open(A2_driver *driver) +{ + CoreAudio_audiodriver * drv = (CoreAudio_audiodriver *)driver; + A2_config * config = drv->ad.driver.config; + AudioStreamBasicDescription * desc = &drv->desc; + OSStatus err; + int c, i; + + /* allocate Audiality2 buffers */ + if ( !(drv->ad.buffers = calloc(config->channels, sizeof(int32_t *)))) + return A2_OOMEMORY; + for ( c = 0; c < config->channels; c++ ) + { + if ( !(drv->ad.buffers[c] = calloc(config->buffer, sizeof(int32_t)))) + return A2_OOMEMORY; + } + + /* a2 callbacks */ + drv->ad.Run = NULL; + drv->ad.Lock = coreaudio_Lock; + drv->ad.Unlock = coreaudio_Unlock; + + config->buffer = 4096; + + /* set up stream description */ + desc->mSampleRate = (Float64)config->samplerate; + desc->mFormatID = kAudioFormatLinearPCM; + desc->mFormatFlags = kAudioFormatFlagIsSignedInteger; + + desc->mFramesPerPacket = 1; + desc->mChannelsPerFrame = config->channels; + + /* packet -> frame -> channel -> data */ + desc->mBytesPerFrame = desc->mChannelsPerFrame * sizeof(int32_t); + desc->mBytesPerPacket = desc->mBytesPerFrame * desc->mFramesPerPacket; + desc->mBitsPerChannel = 24; /* 8:24 PCM */ + + /* set up queue */ + err = AudioQueueNewOutput( + desc, // data format + coreaudio_process, // callback + driver, // data passed to callback + NULL, // internal run loop + NULL, // kCFRunLoopCommonMode + 0, // reserved by Apple + &drv->queue // queue output + ); + if ( err ) goto error; + + err = AudioQueueStart(drv->queue, NULL); + + for ( i = 0; i < kNumBuffers; i++ ) + { + /* internal buffer */ + err = AudioQueueAllocateBuffer( + drv->queue, + desc->mBytesPerPacket * config->buffer, + &drv->buffer[i] + ); + + printf("allocating buffer %i: ------\n" + "\t mBytesPerPacket: %i\n" + "\tmAudioDataBytesCapacity: %i\n" + , + i, + desc->mBytesPerPacket, + drv->buffer[i]->mAudioDataBytesCapacity); + + if (err) goto error; + + /* start callback polling */ + drv->buffer[i]->mAudioDataByteSize = drv->buffer[i]->mAudioDataBytesCapacity; + err = AudioQueueEnqueueBuffer(drv->queue, drv->buffer[i], 0, NULL); + if (err) goto error; + } + return A2_OK; + +error: + fprintf(stderr, "Audiality 2: Cannot activate CoreAudio driver!\n"); + printf("CoreAudio driver.\n"); + coreaudiod_Close(&drv->ad.driver); + return A2_DEVICEOPEN; +} + +A2_driver *a2_coreaudio_audiodriver(A2_drivertypes type, const char *name) +{ + CoreAudio_audiodriver * cad = calloc(1, sizeof(CoreAudio_audiodriver)); + A2_driver * d = &cad->ad.driver; + + if (!d) + return NULL; + + d->type = A2_AUDIODRIVER; + d->name = "coreaudio"; + d->Open = coreaudiod_Open; + d->Close = coreaudiod_Close; + d->flags = A2_REALTIME; + + return d; +} + +#endif // __APPLE__ diff --git a/src/drivers/coreaudiodrv.h b/src/drivers/coreaudiodrv.h new file mode 100644 index 0000000..845d03b --- /dev/null +++ b/src/drivers/coreaudiodrv.h @@ -0,0 +1,32 @@ +/* + * coreaudiodrv.h - Audiality 2 Core Audio driver + * + * Copyright 2015 Jonathan Howard + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from the + * use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#ifndef A2_COREAUDIODRV_H +#define A2_COREAUDIODRV_H + +#include "audiality2.h" + +#ifdef __APPLE__ +A2_driver *a2_coreaudio_audiodriver(A2_drivertypes type, const char *name); +#endif // __APPLE__ + +#endif // A2_COREAUDIODRV_H