From 98bf08bdcf2edd9d397f32650a8bfe62186fbecf Mon Sep 17 00:00:00 2001 From: "Alfred E. Heggestad" Date: Sun, 9 Feb 2014 11:50:07 +0100 Subject: baresip 0.4.10 --- modules/coreaudio/coreaudio.c | 128 +++++++++++++++++++++++++++ modules/coreaudio/coreaudio.h | 20 +++++ modules/coreaudio/module.mk | 13 +++ modules/coreaudio/player.c | 167 +++++++++++++++++++++++++++++++++++ modules/coreaudio/recorder.c | 199 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 527 insertions(+) create mode 100644 modules/coreaudio/coreaudio.c create mode 100644 modules/coreaudio/coreaudio.h create mode 100644 modules/coreaudio/module.mk create mode 100644 modules/coreaudio/player.c create mode 100644 modules/coreaudio/recorder.c (limited to 'modules/coreaudio') diff --git a/modules/coreaudio/coreaudio.c b/modules/coreaudio/coreaudio.c new file mode 100644 index 0000000..bb6ea64 --- /dev/null +++ b/modules/coreaudio/coreaudio.c @@ -0,0 +1,128 @@ +/** + * @file coreaudio.c Apple Coreaudio sound driver + * + * Copyright (C) 2010 Creytiv.com + */ +#include +#include +#include +#include +#include "coreaudio.h" + + +static struct auplay *auplay; +static struct ausrc *ausrc; + + +int audio_fmt(enum aufmt fmt) +{ + switch (fmt) { + + case AUFMT_S16LE: return kAudioFormatLinearPCM; + case AUFMT_PCMA: return kAudioFormatALaw; + case AUFMT_PCMU: return kAudioFormatULaw; + default: + warning("coreaudio: unknown format %d\n", fmt); + return -1; + } +} + + +int bytesps(enum aufmt fmt) +{ + switch (fmt) { + + case AUFMT_S16LE: return 2; + case AUFMT_PCMA: return 1; + case AUFMT_PCMU: return 1; + default: return 0; + } +} + + +#if TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_2_0 +static void interruptionListener(void *data, UInt32 inInterruptionState) +{ + (void)data; + + /* TODO: implement this properly */ + + if (inInterruptionState == kAudioSessionBeginInterruption) { + debug("coreaudio: player interrupt: Begin\n"); + } + else if (inInterruptionState == kAudioSessionEndInterruption) { + debug("coreaudio: player interrupt: End\n"); + } +} + + +int audio_session_enable(void) +{ + OSStatus res; + UInt32 category; + + res = AudioSessionInitialize(NULL, NULL, interruptionListener, 0); + if (res && res != 1768843636) + return ENODEV; + + category = kAudioSessionCategory_PlayAndRecord; + res = AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, + sizeof(category), &category); + if (res) { + warning("coreaudio: Audio Category: %d\n", res); + return ENODEV; + } + + res = AudioSessionSetActive(true); + if (res) { + warning("coreaudio: AudioSessionSetActive: %d\n", res); + return ENODEV; + } + + return 0; +} + + +void audio_session_disable(void) +{ + AudioSessionSetActive(false); +} +#else +int audio_session_enable(void) +{ + return 0; +} + + +void audio_session_disable(void) +{ +} +#endif + + +static int module_init(void) +{ + int err; + + err = auplay_register(&auplay, "coreaudio", coreaudio_player_alloc); + err |= ausrc_register(&ausrc, "coreaudio", coreaudio_recorder_alloc); + + return err; +} + + +static int module_close(void) +{ + auplay = mem_deref(auplay); + ausrc = mem_deref(ausrc); + + return 0; +} + + +EXPORT_SYM const struct mod_export DECL_EXPORTS(coreaudio) = { + "coreaudio", + "audio", + module_init, + module_close, +}; diff --git a/modules/coreaudio/coreaudio.h b/modules/coreaudio/coreaudio.h new file mode 100644 index 0000000..530e45e --- /dev/null +++ b/modules/coreaudio/coreaudio.h @@ -0,0 +1,20 @@ +/** + * @file coreaudio.h Apple Coreaudio sound driver -- internal API + * + * Copyright (C) 2010 Creytiv.com + */ + + +int audio_session_enable(void); +void audio_session_disable(void); + +int audio_fmt(enum aufmt fmt); +int bytesps(enum aufmt fmt); + +int coreaudio_player_alloc(struct auplay_st **stp, struct auplay *ap, + struct auplay_prm *prm, const char *device, + auplay_write_h *wh, void *arg); +int coreaudio_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/coreaudio/module.mk b/modules/coreaudio/module.mk new file mode 100644 index 0000000..35d51cf --- /dev/null +++ b/modules/coreaudio/module.mk @@ -0,0 +1,13 @@ +# +# module.mk +# +# Copyright (C) 2010 Creytiv.com +# + +MOD := coreaudio +$(MOD)_SRCS += coreaudio.c +$(MOD)_SRCS += player.c +$(MOD)_SRCS += recorder.c +$(MOD)_LFLAGS += -framework CoreAudio -framework AudioToolbox + +include mk/mod.mk diff --git a/modules/coreaudio/player.c b/modules/coreaudio/player.c new file mode 100644 index 0000000..68aca4e --- /dev/null +++ b/modules/coreaudio/player.c @@ -0,0 +1,167 @@ +/** + * @file coreaudio/player.c Apple Coreaudio sound driver - player + * + * Copyright (C) 2010 Creytiv.com + */ +#include +#include +#include +#include +#include +#include "coreaudio.h" + + +/* This value can be tuned */ +#if TARGET_OS_IPHONE +#define BUFC 20 +#else +#define BUFC 6 +#endif + + +struct auplay_st { + struct auplay *ap; /* inheritance */ + AudioQueueRef queue; + AudioQueueBufferRef buf[BUFC]; + pthread_mutex_t mutex; + auplay_write_h *wh; + void *arg; +}; + + +static void auplay_destructor(void *arg) +{ + struct auplay_st *st = arg; + uint32_t i; + + pthread_mutex_lock(&st->mutex); + st->wh = NULL; + pthread_mutex_unlock(&st->mutex); + + audio_session_disable(); + + if (st->queue) { + AudioQueuePause(st->queue); + AudioQueueStop(st->queue, true); + + for (i=0; ibuf); i++) + if (st->buf[i]) + AudioQueueFreeBuffer(st->queue, st->buf[i]); + + AudioQueueDispose(st->queue, true); + } + + mem_deref(st->ap); + + pthread_mutex_destroy(&st->mutex); +} + + +static void play_handler(void *userData, AudioQueueRef outQ, + AudioQueueBufferRef outQB) +{ + struct auplay_st *st = userData; + auplay_write_h *wh; + void *arg; + + pthread_mutex_lock(&st->mutex); + wh = st->wh; + arg = st->arg; + pthread_mutex_unlock(&st->mutex); + + if (!wh) + return; + + if (!wh(outQB->mAudioData, outQB->mAudioDataByteSize, arg)) { + /* Set the buffer to silence */ + memset(outQB->mAudioData, 0, outQB->mAudioDataByteSize); + } + + AudioQueueEnqueueBuffer(outQ, outQB, 0, NULL); +} + + +int coreaudio_player_alloc(struct auplay_st **stp, struct auplay *ap, + struct auplay_prm *prm, const char *device, + auplay_write_h *wh, void *arg) +{ + AudioStreamBasicDescription fmt; + struct auplay_st *st; + uint32_t sampc, bytc, i; + OSStatus status; + 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 = audio_session_enable(); + if (err) + goto out; + + fmt.mSampleRate = (Float64)prm->srate; + fmt.mFormatID = audio_fmt(prm->fmt); + fmt.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | + kAudioFormatFlagIsPacked; +#ifdef __BIG_ENDIAN__ + fmt.mFormatFlags |= kAudioFormatFlagIsBigEndian; +#endif + fmt.mFramesPerPacket = 1; + fmt.mBytesPerFrame = prm->ch * bytesps(prm->fmt); + fmt.mBytesPerPacket = prm->ch * bytesps(prm->fmt); + fmt.mChannelsPerFrame = prm->ch; + fmt.mBitsPerChannel = 8*bytesps(prm->fmt); + + status = AudioQueueNewOutput(&fmt, play_handler, st, NULL, + kCFRunLoopCommonModes, 0, &st->queue); + if (status) { + warning("coreaudio: AudioQueueNewOutput error: %i\n", status); + err = ENODEV; + goto out; + } + + sampc = prm->srate * prm->ch * prm->ptime / 1000; + bytc = sampc * bytesps(prm->fmt); + + for (i=0; ibuf); i++) { + + status = AudioQueueAllocateBuffer(st->queue, bytc, + &st->buf[i]); + if (status) { + err = ENOMEM; + goto out; + } + + st->buf[i]->mAudioDataByteSize = bytc; + + memset(st->buf[i]->mAudioData, 0, + st->buf[i]->mAudioDataByteSize); + + (void)AudioQueueEnqueueBuffer(st->queue, st->buf[i], 0, NULL); + } + + status = AudioQueueStart(st->queue, NULL); + if (status) { + warning("coreaudio: AudioQueueStart error %i\n", status); + err = ENODEV; + goto out; + } + + out: + if (err) + mem_deref(st); + else + *stp = st; + + return err; +} diff --git a/modules/coreaudio/recorder.c b/modules/coreaudio/recorder.c new file mode 100644 index 0000000..b1f91fc --- /dev/null +++ b/modules/coreaudio/recorder.c @@ -0,0 +1,199 @@ +/** + * @file coreaudio/recorder.c Apple Coreaudio sound driver - recorder + * + * Copyright (C) 2010 Creytiv.com + */ +#include +#include +#include +#include +#include +#include +#include "coreaudio.h" + + +#define BUFC 3 + + +struct ausrc_st { + struct ausrc *as; /* inheritance */ + AudioQueueRef queue; + AudioQueueBufferRef buf[BUFC]; + pthread_mutex_t mutex; + struct mbuf *mb; + ausrc_read_h *rh; + void *arg; + unsigned int ptime; +}; + + +static void ausrc_destructor(void *arg) +{ + struct ausrc_st *st = arg; + uint32_t i; + + pthread_mutex_lock(&st->mutex); + st->rh = NULL; + pthread_mutex_unlock(&st->mutex); + + audio_session_disable(); + + if (st->queue) { + AudioQueuePause(st->queue); + AudioQueueStop(st->queue, true); + + for (i=0; ibuf); i++) + if (st->buf[i]) + AudioQueueFreeBuffer(st->queue, st->buf[i]); + + AudioQueueDispose(st->queue, true); + } + + mem_deref(st->mb); + mem_deref(st->as); + + pthread_mutex_destroy(&st->mutex); +} + + +static void record_handler(void *userData, AudioQueueRef inQ, + AudioQueueBufferRef inQB, + const AudioTimeStamp *inStartTime, + UInt32 inNumPackets, + const AudioStreamPacketDescription *inPacketDesc) +{ + struct ausrc_st *st = userData; + struct mbuf *mb = st->mb; + unsigned int ptime; + ausrc_read_h *rh; + size_t sz, sp; + void *arg; + (void)inStartTime; + (void)inNumPackets; + (void)inPacketDesc; + + pthread_mutex_lock(&st->mutex); + ptime = st->ptime; + rh = st->rh; + arg = st->arg; + pthread_mutex_unlock(&st->mutex); + + if (!rh) + return; + + sz = inQB->mAudioDataByteSize; + sp = mbuf_get_space(mb); + + if (sz >= sp) { + mbuf_write_mem(mb, inQB->mAudioData, sp); + rh(mb->buf, (uint32_t)mb->size, arg); + mb->pos = 0; + mbuf_write_mem(mb, (uint8_t *)inQB->mAudioData + sp, sz - sp); + } + else { + mbuf_write_mem(mb, inQB->mAudioData, sz); + } + + AudioQueueEnqueueBuffer(inQ, inQB, 0, NULL); + + /* Force a sleep here, coreaudio's timing is too fast */ +#if !TARGET_OS_IPHONE +#define ENCODE_TIME 1000 + usleep((ptime * 1000) - ENCODE_TIME); +#endif +} + + +int coreaudio_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; + struct ausrc_st *st; + uint32_t sampc, bytc, i; + OSStatus status; + int err; + + (void)ctx; + (void)device; + (void)errh; + + if (!stp || !as || !prm) + return EINVAL; + + st = mem_zalloc(sizeof(*st), ausrc_destructor); + if (!st) + return ENOMEM; + + st->ptime = prm->ptime; + st->as = mem_ref(as); + st->rh = rh; + st->arg = arg; + + sampc = prm->srate * prm->ch * prm->ptime / 1000; + bytc = sampc * bytesps(prm->fmt); + + st->mb = mbuf_alloc(bytc); + if (!st->mb) { + err = ENOMEM; + goto out; + } + + err = pthread_mutex_init(&st->mutex, NULL); + if (err) + goto out; + + err = audio_session_enable(); + if (err) + goto out; + + fmt.mSampleRate = (Float64)prm->srate; + fmt.mFormatID = audio_fmt(prm->fmt); + fmt.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | + kAudioFormatFlagIsPacked; +#ifdef __BIG_ENDIAN__ + fmt.mFormatFlags |= kAudioFormatFlagIsBigEndian; +#endif + + fmt.mFramesPerPacket = 1; + fmt.mBytesPerFrame = prm->ch * bytesps(prm->fmt); + fmt.mBytesPerPacket = prm->ch * bytesps(prm->fmt); + fmt.mChannelsPerFrame = prm->ch; + fmt.mBitsPerChannel = 8*bytesps(prm->fmt); + + status = AudioQueueNewInput(&fmt, record_handler, st, NULL, + kCFRunLoopCommonModes, 0, &st->queue); + if (status) { + warning("coreaudio: AudioQueueNewInput error: %i\n", status); + err = ENODEV; + goto out; + } + + for (i=0; ibuf); i++) { + + status = AudioQueueAllocateBuffer(st->queue, bytc, + &st->buf[i]); + if (status) { + err = ENOMEM; + goto out; + } + + AudioQueueEnqueueBuffer(st->queue, st->buf[i], 0, NULL); + } + + status = AudioQueueStart(st->queue, NULL); + if (status) { + warning("coreaudio: AudioQueueStart error %i\n", status); + err = ENODEV; + goto out; + } + + out: + if (err) + mem_deref(st); + else + *stp = st; + + return err; +} -- cgit v1.2.3