diff options
author | Alfred E. Heggestad <aeh@db.org> | 2014-02-09 11:50:07 +0100 |
---|---|---|
committer | Alfred E. Heggestad <aeh@db.org> | 2014-02-09 11:50:07 +0100 |
commit | 98bf08bdcf2edd9d397f32650a8bfe62186fbecf (patch) | |
tree | ebc6ec71f44bff8c42e4eefced61948623df02fc /modules/audiounit | |
parent | e6ad5cf4401b860ba402d4b7b3c7c254bc87a019 (diff) |
baresip 0.4.10
Diffstat (limited to 'modules/audiounit')
-rw-r--r-- | modules/audiounit/audiounit.c | 88 | ||||
-rw-r--r-- | modules/audiounit/audiounit.h | 27 | ||||
-rw-r--r-- | modules/audiounit/module.mk | 14 | ||||
-rw-r--r-- | modules/audiounit/player.c | 189 | ||||
-rw-r--r-- | modules/audiounit/recorder.c | 194 | ||||
-rw-r--r-- | modules/audiounit/sess.c | 174 |
6 files changed, 686 insertions, 0 deletions
diff --git a/modules/audiounit/audiounit.c b/modules/audiounit/audiounit.c new file mode 100644 index 0000000..d5bbcc7 --- /dev/null +++ b/modules/audiounit/audiounit.c @@ -0,0 +1,88 @@ +/** + * @file audiounit.c AudioUnit sound driver + * + * Copyright (C) 2010 Creytiv.com + */ +#include <AudioUnit/AudioUnit.h> +#include <AudioToolbox/AudioToolbox.h> +#include <re.h> +#include <baresip.h> +#include "audiounit.h" + + +AudioComponent output_comp = NULL; + +static struct auplay *auplay; +static struct ausrc *ausrc; + + +#if TARGET_OS_IPHONE +static void interruptionListener(void *data, UInt32 inInterruptionState) +{ + (void)data; + + if (inInterruptionState == kAudioSessionBeginInterruption) { + info("audiounit: interrupt Begin\n"); + audiosess_interrupt(true); + } + else if (inInterruptionState == kAudioSessionEndInterruption) { + info("audiounit: interrupt End\n"); + audiosess_interrupt(false); + } +} +#endif + + +static int module_init(void) +{ + AudioComponentDescription desc; + int err; + +#if TARGET_OS_IPHONE + OSStatus ret; + + ret = AudioSessionInitialize(NULL, NULL, interruptionListener, 0); + if (ret && ret != kAudioSessionAlreadyInitialized) { + warning("audiounit: AudioSessionInitialize: %d\n", ret); + return ENODEV; + } +#endif + + desc.componentType = kAudioUnitType_Output; +#if TARGET_OS_IPHONE + desc.componentSubType = kAudioUnitSubType_VoiceProcessingIO; +#else + desc.componentSubType = kAudioUnitSubType_HALOutput; +#endif + desc.componentManufacturer = kAudioUnitManufacturer_Apple; + desc.componentFlags = 0; + desc.componentFlagsMask = 0; + + output_comp = AudioComponentFindNext(NULL, &desc); + if (!output_comp) { + warning("audiounit: Voice Processing I/O not found\n"); + return ENOENT; + } + + err = auplay_register(&auplay, "audiounit", audiounit_player_alloc); + err |= ausrc_register(&ausrc, "audiounit", audiounit_recorder_alloc); + + return 0; +} + + +static int module_close(void) +{ + ausrc = mem_deref(ausrc); + auplay = mem_deref(auplay); + + return 0; +} + + +EXPORT_SYM const struct mod_export DECL_EXPORTS(audiounit) = { + "audiounit", + "audio", + module_init, + module_close, +}; diff --git a/modules/audiounit/audiounit.h b/modules/audiounit/audiounit.h new file mode 100644 index 0000000..dd85131 --- /dev/null +++ b/modules/audiounit/audiounit.h @@ -0,0 +1,27 @@ +/** + * @file audiounit.h AudioUnit sound driver -- Internal interface + * + * Copyright (C) 2010 Creytiv.com + */ + + +AudioComponent output_comp; + + +struct audiosess; +struct audiosess_st; + +typedef void (audiosess_int_h)(bool start, void *arg); + +int audiosess_alloc(struct audiosess_st **stp, + audiosess_int_h *inth, void *arg); +void audiosess_interrupt(bool interrupted); + + +int audiounit_player_alloc(struct auplay_st **stp, struct auplay *ap, + struct auplay_prm *prm, const char *device, + auplay_write_h *wh, void *arg); +int audiounit_recorder_alloc(struct ausrc_st **stp, struct ausrc *as, + struct media_ctx **ctx, + struct ausrc_prm *prm, const char *device, + ausrc_read_h *rh, ausrc_error_h *errh, void *arg); diff --git a/modules/audiounit/module.mk b/modules/audiounit/module.mk new file mode 100644 index 0000000..1dd1a30 --- /dev/null +++ b/modules/audiounit/module.mk @@ -0,0 +1,14 @@ +# +# module.mk +# +# Copyright (C) 2010 Creytiv.com +# + +MOD := audiounit +$(MOD)_SRCS += audiounit.c +$(MOD)_SRCS += sess.c +$(MOD)_SRCS += player.c +$(MOD)_SRCS += recorder.c +$(MOD)_LFLAGS += -framework CoreAudio -framework AudioToolbox + +include mk/mod.mk diff --git a/modules/audiounit/player.c b/modules/audiounit/player.c new file mode 100644 index 0000000..0c3a2d1 --- /dev/null +++ b/modules/audiounit/player.c @@ -0,0 +1,189 @@ +/** + * @file audiounit/player.c AudioUnit output player + * + * Copyright (C) 2010 Creytiv.com + */ +#include <AudioUnit/AudioUnit.h> +#include <AudioToolbox/AudioToolbox.h> +#include <pthread.h> +#include <re.h> +#include <baresip.h> +#include "audiounit.h" + + +static uint8_t silbuf[4096]; /* silence */ + + +struct auplay_st { + struct auplay *ap; /* inheritance */ + struct audiosess_st *sess; + AudioUnit au; + pthread_mutex_t mutex; + auplay_write_h *wh; + void *arg; +}; + + +static void auplay_destructor(void *arg) +{ + struct auplay_st *st = arg; + + pthread_mutex_lock(&st->mutex); + st->wh = NULL; + pthread_mutex_unlock(&st->mutex); + + AudioOutputUnitStop(st->au); + AudioUnitUninitialize(st->au); + AudioComponentInstanceDispose(st->au); + + mem_deref(st->sess); + mem_deref(st->ap); + + pthread_mutex_destroy(&st->mutex); +} + + +static OSStatus output_callback(void *inRefCon, + AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp *inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames, + AudioBufferList *ioData) +{ + struct auplay_st *st = inRefCon; + auplay_write_h *wh; + void *arg; + uint32_t i; + + (void)ioActionFlags; + (void)inTimeStamp; + (void)inBusNumber; + (void)inNumberFrames; + + pthread_mutex_lock(&st->mutex); + wh = st->wh; + arg = st->arg; + pthread_mutex_unlock(&st->mutex); + + if (!wh) + return 0; + + for (i = 0; i < ioData->mNumberBuffers; ++i) { + + AudioBuffer *ab = &ioData->mBuffers[i]; + + if (!wh(ab->mData, ab->mDataByteSize, arg)) { + + if (ab->mDataByteSize < sizeof(silbuf)) + ab->mData = silbuf; + else + memset(ab->mData, 0, ab->mDataByteSize); + } + } + + return 0; +} + + +static void interrupt_handler(bool interrupted, void *arg) +{ + struct auplay_st *st = arg; + + if (interrupted) + AudioOutputUnitStop(st->au); + else + AudioOutputUnitStart(st->au); +} + + +int audiounit_player_alloc(struct auplay_st **stp, struct auplay *ap, + struct auplay_prm *prm, const char *device, + auplay_write_h *wh, void *arg) +{ + AudioStreamBasicDescription fmt; + AudioUnitElement outputBus = 0; + AURenderCallbackStruct cb; + struct auplay_st *st; + UInt32 enable = 1; + OSStatus ret = 0; + int err; + + (void)device; + + st = mem_zalloc(sizeof(*st), auplay_destructor); + if (!st) + return ENOMEM; + + st->ap = mem_ref(ap); + st->wh = wh; + st->arg = arg; + + err = pthread_mutex_init(&st->mutex, NULL); + if (err) + goto out; + + err = audiosess_alloc(&st->sess, interrupt_handler, st); + if (err) + goto out; + + ret = AudioComponentInstanceNew(output_comp, &st->au); + if (ret) + goto out; + + ret = AudioUnitSetProperty(st->au, kAudioOutputUnitProperty_EnableIO, + kAudioUnitScope_Output, outputBus, + &enable, sizeof(enable)); + if (ret) + goto out; + + fmt.mSampleRate = prm->srate; + fmt.mFormatID = kAudioFormatLinearPCM; +#if TARGET_OS_IPHONE + fmt.mFormatFlags = kAudioFormatFlagsCanonical; +#else + fmt.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger + | kLinearPCMFormatFlagIsPacked; +#endif + fmt.mBitsPerChannel = 16; + fmt.mChannelsPerFrame = prm->ch; + fmt.mBytesPerFrame = 2 * prm->ch; + fmt.mFramesPerPacket = 1; + fmt.mBytesPerPacket = 2 * prm->ch; + + ret = AudioUnitInitialize(st->au); + if (ret) + goto out; + + ret = AudioUnitSetProperty(st->au, kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, outputBus, + &fmt, sizeof(fmt)); + if (ret) + goto out; + + cb.inputProc = output_callback; + cb.inputProcRefCon = st; + ret = AudioUnitSetProperty(st->au, + kAudioUnitProperty_SetRenderCallback, + kAudioUnitScope_Input, outputBus, + &cb, sizeof(cb)); + if (ret) + goto out; + + ret = AudioOutputUnitStart(st->au); + if (ret) + goto out; + + out: + if (ret) { + warning("audiounit: player failed: %d (%c%c%c%c)\n", ret, + ret>>24, ret>>16, ret>>8, ret); + err = ENODEV; + } + + if (err) + mem_deref(st); + else + *stp = st; + + return err; +} diff --git a/modules/audiounit/recorder.c b/modules/audiounit/recorder.c new file mode 100644 index 0000000..4b460d6 --- /dev/null +++ b/modules/audiounit/recorder.c @@ -0,0 +1,194 @@ +/** + * @file audiounit/recorder.c AudioUnit input recorder + * + * Copyright (C) 2010 Creytiv.com + */ +#include <AudioUnit/AudioUnit.h> +#include <AudioToolbox/AudioToolbox.h> +#include <pthread.h> +#include <re.h> +#include <baresip.h> +#include "audiounit.h" + + +struct ausrc_st { + struct ausrc *as; /* inheritance */ + struct audiosess_st *sess; + AudioUnit au; + pthread_mutex_t mutex; + int ch; + ausrc_read_h *rh; + void *arg; +}; + + +static void ausrc_destructor(void *arg) +{ + struct ausrc_st *st = arg; + + pthread_mutex_lock(&st->mutex); + st->rh = NULL; + pthread_mutex_unlock(&st->mutex); + + AudioOutputUnitStop(st->au); + AudioUnitUninitialize(st->au); + AudioComponentInstanceDispose(st->au); + + mem_deref(st->sess); + mem_deref(st->as); + + pthread_mutex_destroy(&st->mutex); +} + + +static OSStatus input_callback(void *inRefCon, + AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp *inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames, + AudioBufferList *ioData) +{ + struct ausrc_st *st = inRefCon; + AudioBufferList abl; + OSStatus ret; + ausrc_read_h *rh; + void *arg; + + (void)ioData; + + pthread_mutex_lock(&st->mutex); + rh = st->rh; + arg = st->arg; + pthread_mutex_unlock(&st->mutex); + + if (!rh) + return 0; + + abl.mNumberBuffers = 1; + abl.mBuffers[0].mNumberChannels = st->ch; + abl.mBuffers[0].mData = NULL; + abl.mBuffers[0].mDataByteSize = inNumberFrames * 2; + + ret = AudioUnitRender(st->au, + ioActionFlags, + inTimeStamp, + inBusNumber, + inNumberFrames, + &abl); + if (ret) + return ret; + + rh(abl.mBuffers[0].mData, abl.mBuffers[0].mDataByteSize, arg); + + return 0; +} + + +static void interrupt_handler(bool interrupted, void *arg) +{ + struct ausrc_st *st = arg; + + if (interrupted) + AudioOutputUnitStop(st->au); + else + AudioOutputUnitStart(st->au); +} + + +int audiounit_recorder_alloc(struct ausrc_st **stp, struct ausrc *as, + struct media_ctx **ctx, + struct ausrc_prm *prm, const char *device, + ausrc_read_h *rh, ausrc_error_h *errh, void *arg) +{ + AudioStreamBasicDescription fmt; + AudioUnitElement inputBus = 1; + AURenderCallbackStruct cb; + struct ausrc_st *st; + UInt32 enable = 1; + OSStatus ret = 0; + int err; + + (void)ctx; + (void)device; + (void)errh; + + st = mem_zalloc(sizeof(*st), ausrc_destructor); + if (!st) + return ENOMEM; + + st->as = mem_ref(as); + st->rh = rh; + st->arg = arg; + st->ch = prm->ch; + + err = pthread_mutex_init(&st->mutex, NULL); + if (err) + goto out; + + err = audiosess_alloc(&st->sess, interrupt_handler, st); + if (err) + goto out; + + ret = AudioComponentInstanceNew(output_comp, &st->au); + if (ret) + goto out; + + ret = AudioUnitSetProperty(st->au, kAudioOutputUnitProperty_EnableIO, + kAudioUnitScope_Input, inputBus, + &enable, sizeof(enable)); + if (ret) + goto out; + + fmt.mSampleRate = prm->srate; + fmt.mFormatID = kAudioFormatLinearPCM; +#if TARGET_OS_IPHONE + fmt.mFormatFlags = kAudioFormatFlagsCanonical; +#else + fmt.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger + | kLinearPCMFormatFlagIsPacked; +#endif + fmt.mBitsPerChannel = 16; + fmt.mChannelsPerFrame = prm->ch; + fmt.mBytesPerFrame = 2 * prm->ch; + fmt.mFramesPerPacket = 1; + fmt.mBytesPerPacket = 2 * prm->ch; + fmt.mReserved = 0; + + ret = AudioUnitSetProperty(st->au, kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Output, inputBus, + &fmt, sizeof(fmt)); + if (ret) + goto out; + + /* NOTE: done after desc */ + ret = AudioUnitInitialize(st->au); + if (ret) + goto out; + + cb.inputProc = input_callback; + cb.inputProcRefCon = st; + ret = AudioUnitSetProperty(st->au, + kAudioOutputUnitProperty_SetInputCallback, + kAudioUnitScope_Global, inputBus, + &cb, sizeof(cb)); + if (ret) + goto out; + + ret = AudioOutputUnitStart(st->au); + if (ret) + goto out; + + out: + if (ret) { + warning("audiounit: record failed: %d (%c%c%c%c)\n", ret, + ret>>24, ret>>16, ret>>8, ret); + err = ENODEV; + } + + if (err) + mem_deref(st); + else + *stp = st; + + return err; +} diff --git a/modules/audiounit/sess.c b/modules/audiounit/sess.c new file mode 100644 index 0000000..abc966e --- /dev/null +++ b/modules/audiounit/sess.c @@ -0,0 +1,174 @@ +/** + * @file sess.c AudioUnit sound driver - session + * + * Copyright (C) 2010 Creytiv.com + */ +#include <AudioUnit/AudioUnit.h> +#include <AudioToolbox/AudioToolbox.h> +#include <re.h> +#include <baresip.h> +#include "audiounit.h" + + +struct audiosess { + struct list sessl; +}; + + +struct audiosess_st { + struct audiosess *as; + struct le le; + audiosess_int_h *inth; + void *arg; +}; + + +static struct audiosess *gas; + + +#if TARGET_OS_IPHONE +static void propListener(void *inClientData, AudioSessionPropertyID inID, + UInt32 inDataSize, const void *inData) +{ + struct audiosess *sess = inClientData; + CFDictionaryRef dref = inData; + CFNumberRef nref; + SInt32 reason = 0; + + (void)inDataSize; + (void)sess; + + if (kAudioSessionProperty_AudioRouteChange != inID) + return; + + nref = CFDictionaryGetValue( + dref, + CFSTR(kAudioSession_AudioRouteChangeKey_Reason) + ); + + CFNumberGetValue(nref, kCFNumberSInt32Type, &reason); + + info("audiounit: AudioRouteChange - reason %d\n", reason); +} +#endif + + +static void sess_destructor(void *arg) +{ + struct audiosess_st *st = arg; + + list_unlink(&st->le); + mem_deref(st->as); +} + + +static void destructor(void *arg) +{ + struct audiosess *as = arg; +#if TARGET_OS_IPHONE + AudioSessionPropertyID id = kAudioSessionProperty_AudioRouteChange; + + AudioSessionRemovePropertyListenerWithUserData(id, propListener, as); + AudioSessionSetActive(false); +#endif + + list_flush(&as->sessl); + + gas = NULL; +} + + +int audiosess_alloc(struct audiosess_st **stp, + audiosess_int_h *inth, void *arg) +{ + struct audiosess_st *st = NULL; + struct audiosess *as = NULL; + int err = 0; + bool created = false; +#if TARGET_OS_IPHONE + AudioSessionPropertyID id = kAudioSessionProperty_AudioRouteChange; + UInt32 category; + OSStatus ret; +#endif + + if (!stp) + return EINVAL; + +#if TARGET_OS_IPHONE + /* Must be done for all modules */ + category = kAudioSessionCategory_PlayAndRecord; + ret = AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, + sizeof(category), &category); + if (ret) { + warning("audiounit: Audio Category: %d\n", ret); + return EINVAL; + } +#endif + + if (gas) + goto makesess; + + as = mem_zalloc(sizeof(*as), destructor); + if (!as) + return ENOMEM; + +#if TARGET_OS_IPHONE + ret = AudioSessionSetActive(true); + if (ret) { + warning("audiounit: AudioSessionSetActive: %d\n", ret); + err = ENOSYS; + goto out; + } + + ret = AudioSessionAddPropertyListener(id, propListener, as); + if (ret) { + warning("audiounit: AudioSessionAddPropertyListener: %d\n", + ret); + err = EINVAL; + goto out; + } +#endif + + gas = as; + created = true; + + makesess: + st = mem_zalloc(sizeof(*st), sess_destructor); + if (!st) { + err = ENOMEM; + goto out; + } + st->inth = inth; + st->arg = arg; + st->as = created ? gas : mem_ref(gas); + + list_append(&gas->sessl, &st->le, st); + + out: + if (err) { + mem_deref(as); + mem_deref(st); + } + else { + *stp = st; + } + + return err; +} + + +void audiosess_interrupt(bool start) +{ + struct le *le; + + if (!gas) + return; + + for (le = gas->sessl.head; le; le = le->next) { + + struct audiosess_st *st = le->data; + + if (st->inth) + st->inth(start, st->arg); + } +} |