summaryrefslogtreecommitdiff
path: root/modules/audiounit
diff options
context:
space:
mode:
authorAlfred E. Heggestad <aeh@db.org>2014-02-09 11:50:07 +0100
committerAlfred E. Heggestad <aeh@db.org>2014-02-09 11:50:07 +0100
commit98bf08bdcf2edd9d397f32650a8bfe62186fbecf (patch)
treeebc6ec71f44bff8c42e4eefced61948623df02fc /modules/audiounit
parente6ad5cf4401b860ba402d4b7b3c7c254bc87a019 (diff)
baresip 0.4.10
Diffstat (limited to 'modules/audiounit')
-rw-r--r--modules/audiounit/audiounit.c88
-rw-r--r--modules/audiounit/audiounit.h27
-rw-r--r--modules/audiounit/module.mk14
-rw-r--r--modules/audiounit/player.c189
-rw-r--r--modules/audiounit/recorder.c194
-rw-r--r--modules/audiounit/sess.c174
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);
+ }
+}