diff options
author | kpfleming <kpfleming@f38db490-d61c-443f-a65b-d21fe96a405b> | 2005-07-20 00:53:21 +0000 |
---|---|---|
committer | kpfleming <kpfleming@f38db490-d61c-443f-a65b-d21fe96a405b> | 2005-07-20 00:53:21 +0000 |
commit | 000130b1d3cd30b4e007969098fbda821d28d89f (patch) | |
tree | 56647b2721ff9f4f4491bfdc2b945618860a2f25 | |
parent | 7428435033ff215dbc6b157a696e604d0bad9c61 (diff) |
add slinfactory object, and change app_chanspy to use it (bug #4724)
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@6177 f38db490-d61c-443f-a65b-d21fe96a405b
-rwxr-xr-x | Makefile | 2 | ||||
-rwxr-xr-x | apps/app_chanspy.c | 365 | ||||
-rwxr-xr-x | include/asterisk/slinfactory.h | 47 | ||||
-rwxr-xr-x | slinfactory.c | 152 |
4 files changed, 315 insertions, 251 deletions
@@ -276,7 +276,7 @@ OBJS=io.o sched.o logger.o frame.o loader.o config.o channel.o \ dsp.o chanvars.o indications.o autoservice.o db.o privacy.o \ astmm.o enum.o srv.o dns.o aescrypt.o aestab.o aeskey.o \ utils.o config_old.o plc.o jitterbuf.o dnsmgr.o devicestate.o \ - netsock.o + netsock.o slinfactory.o ifeq (${OSARCH},Darwin) OBJS+=poll.o dlfcn.o ASTLINK=-Wl,-dynamic diff --git a/apps/app_chanspy.c b/apps/app_chanspy.c index 7ed00cd31..5bc8c79d7 100755 --- a/apps/app_chanspy.c +++ b/apps/app_chanspy.c @@ -25,6 +25,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/channel.h" #include "asterisk/features.h" #include "asterisk/options.h" +#include "asterisk/slinfactory.h" #include "asterisk/app.h" #include "asterisk/utils.h" #include "asterisk/say.h" @@ -35,7 +36,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") AST_MUTEX_DEFINE_STATIC(modlock); -#define ast_fit_in_short(in) (in < -32768 ? -32768 : in > 32767 ? 32767 : in) #define AST_NAME_STRLEN 256 #define ALL_DONE(u, ret) LOCAL_USER_REMOVE(u); return ret; #define get_volfactor(x) x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0 @@ -80,28 +80,9 @@ LOCAL_USER_DECL; struct chanspy_translation_helper { /* spy data */ struct ast_channel_spy spy; - - /* read frame */ - int fmt0; - short *buf0; - int len0; - struct ast_trans_pvt *trans0; - - /* write frame */ - int fmt1; - struct ast_trans_pvt *trans1; - short *buf1; - int len1; - - /* muxed frame */ - struct ast_frame frame; - short *buf; - int len; - - int samples; - int rsamples; int volfactor; int fd; + struct ast_slinfactory slinfactory[2]; }; /* Prototypes */ @@ -165,33 +146,17 @@ static void spy_release(struct ast_channel *chan, void *data) { struct chanspy_translation_helper *csth = data; + ast_slinfactory_destroy(&csth->slinfactory[0]); + ast_slinfactory_destroy(&csth->slinfactory[1]); - if (csth->trans0) { - ast_translator_free_path(csth->trans0); - csth->trans0 = NULL; - } - if (csth->trans1) { - ast_translator_free_path(csth->trans1); - csth->trans1 = NULL; - } - - if (csth->buf0) { - free(csth->buf0); - csth->buf0 = NULL; - } - if (csth->buf1) { - free(csth->buf1); - csth->buf1 = NULL; - } - if (csth->buf) { - free(csth->buf); - csth->buf = NULL; - } return; } static void *spy_alloc(struct ast_channel *chan, void *params) { + struct chanspy_translation_helper *csth = params; + ast_slinfactory_init(&csth->slinfactory[0]); + ast_slinfactory_init(&csth->slinfactory[1]); return params; } @@ -224,245 +189,148 @@ static void ast_flush_spy_queue(struct ast_channel_spy *spy) ast_mutex_unlock(&spy->lock); } -static int spy_generate(struct ast_channel *chan, void *data, int len, int samples) -{ - struct ast_frame *f, *f0, *f1; - int x, vf, dlen, maxsamp, loops; - struct chanspy_translation_helper *csth = data; - if (csth->rsamples < csth->samples) { - csth->rsamples += samples; - return 0; - } - csth->rsamples += samples; - loops = 0; - do { - loops++; - f = f0 = f1 = NULL; - x = vf = dlen = maxsamp = 0; - if (csth->rsamples == csth->samples) { - csth->rsamples = csth->samples = 0; +#if 0 +static int extract_audio(short *buf, size_t len, struct ast_trans_pvt *trans, struct ast_frame *fr, int *maxsamp) +{ + struct ast_frame *f; + int size, retlen = 0; + + if (trans) { + if ((f = ast_translate(trans, fr, 0))) { + size = (f->datalen > len) ? len : f->datalen; + memcpy(buf, f->data, size); + retlen = f->datalen; + ast_frfree(f); + } else { + /* your guess is as good as mine why this will happen but it seems to only happen on iax and appears harmless */ + ast_log(LOG_DEBUG, "Failed to translate frame from %s\n", ast_getformatname(fr->subclass)); } + } else { + size = (fr->datalen > len) ? len : fr->datalen; + memcpy(buf, fr->data, size); + retlen = fr->datalen; + } - ast_mutex_lock(&csth->spy.lock); - f0 = spy_queue_shift(&csth->spy, 0); - f1 = spy_queue_shift(&csth->spy, 1); - ast_mutex_unlock(&csth->spy.lock); - - if (csth->spy.status == CHANSPY_DONE) { - return -1; + if (retlen > 0 && (size = retlen / 2)) { + if (size > *maxsamp) { + *maxsamp = size; } + } - if (!f0 && !f1) { - return 0; - } + return retlen; +} - if (f0 && csth->fmt0 && csth->fmt0 != f0->subclass) { - ast_translator_free_path(csth->trans0); - csth->trans0 = NULL; - csth->fmt0 = f0->subclass; - } - if (f1 && csth->fmt1 && csth->fmt1 != f1->subclass) { - ast_translator_free_path(csth->trans1); - csth->trans1 = NULL; - csth->fmt1 = f1->subclass; - } - - if (!csth->fmt0 && f0) { - csth->fmt0 = f0->subclass; - } +static int spy_queue_ready(struct ast_channel_spy *spy) +{ + int res = 0; - if (!csth->fmt1 && f1) { - csth->fmt1 = f1->subclass; - } + ast_mutex_lock(&spy->lock); + if (spy->status == CHANSPY_RUNNING) { + res = (spy->queue[0] && spy->queue[1]) ? 1 : 0; + } else { + res = (spy->queue[0] || spy->queue[1]) ? 1 : -1; + } + ast_mutex_unlock(&spy->lock); + return res; +} +#endif - if (csth->fmt0 && csth->fmt0 != AST_FORMAT_SLINEAR && !csth->trans0) { - if ((csth->trans0 = ast_translator_build_path(AST_FORMAT_SLINEAR, csth->fmt0)) == NULL) { - ast_log(LOG_WARNING, "Cannot build a path from %s to slin\n", ast_getformatname(csth->fmt0)); - csth->spy.status = CHANSPY_DONE; - return -1; - } + +static int spy_generate(struct ast_channel *chan, void *data, int len, int samples) +{ + + struct chanspy_translation_helper *csth = data; + struct ast_frame frame, *f; + int len0 = 0, len1 = 0, samp0 = 0, samp1 = 0, x, vf, maxsamp; + short buf0[1280], buf1[1280], buf[1280]; + + if (csth->spy.status == CHANSPY_DONE) { + return -1; + } + + ast_mutex_lock(&csth->spy.lock); + while((f = csth->spy.queue[0])) { + csth->spy.queue[0] = f->next; + ast_slinfactory_feed(&csth->slinfactory[0], f); + ast_frfree(f); } - if (csth->fmt1 && csth->fmt1 != AST_FORMAT_SLINEAR && !csth->trans1) { - if ((csth->trans1 = ast_translator_build_path(AST_FORMAT_SLINEAR, csth->fmt1)) == NULL) { - ast_log(LOG_WARNING, "Cannot build a path from %s to slin\n", ast_getformatname(csth->fmt1)); - csth->spy.status = CHANSPY_DONE; - return -1; - } + ast_mutex_unlock(&csth->spy.lock); + ast_mutex_lock(&csth->spy.lock); + while((f = csth->spy.queue[1])) { + csth->spy.queue[1] = f->next; + ast_slinfactory_feed(&csth->slinfactory[1], f); + ast_frfree(f); } - - if (f0) { - if (csth->trans0) { - if ((f = ast_translate(csth->trans0, f0, 0))) { - if (csth->len0 < f->datalen) { - if (!csth->len0) { - if (!(csth->buf0 = malloc(f->datalen * 2))) { - csth->spy.status = CHANSPY_DONE; - return -1; - } - } else { - if (!realloc(csth->buf0, f->datalen * 2)) { - csth->spy.status = CHANSPY_DONE; - return -1; - } - } - csth->len0 = f->datalen; - } - memcpy(csth->buf0, f->data, f->datalen); - maxsamp = f->samples; - ast_frfree(f); - } else { - return 0; - } - } else { - if (csth->len0 < f0->datalen) { - if (!csth->len0) { - if (!(csth->buf0 = malloc(f0->datalen * 2))) { - csth->spy.status = CHANSPY_DONE; - return -1; - } - } else { - if (!realloc(csth->buf0, f0->datalen * 2)) { - csth->spy.status = CHANSPY_DONE; - return -1; - } - } - csth->len0 = f0->datalen; - } - memcpy(csth->buf0, f0->data, f0->datalen); - maxsamp = f0->samples; - } + ast_mutex_unlock(&csth->spy.lock); + + if (csth->slinfactory[0].size < len || csth->slinfactory[1].size < len) { + return 0; } - - if (f1) { - if (csth->trans1) { - if ((f = ast_translate(csth->trans1, f1, 0))) { - if (csth->len1 < f->datalen) { - if (!csth->len1) { - if (!(csth->buf1 = malloc(f->datalen * 2))) { - csth->spy.status = CHANSPY_DONE; - return -1; - } - } else { - if (!realloc(csth->buf1, f->datalen * 2)) { - csth->spy.status = CHANSPY_DONE; - return -1; - } - } - csth->len1 = f->datalen; - } - memcpy(csth->buf1, f->data, f->datalen); - if (f->samples > maxsamp) { - maxsamp = f->samples; - } - ast_frfree(f); - - } else { - return 0; - } - } else { - if (csth->len1 < f1->datalen) { - if (!csth->len1) { - if (!(csth->buf1 = malloc(f1->datalen * 2))) { - csth->spy.status = CHANSPY_DONE; - return -1; - } - } else { - if (!realloc(csth->buf1, f1->datalen * 2)) { - csth->spy.status = CHANSPY_DONE; - return -1; - } - } - csth->len1 = f1->datalen; - } - memcpy(csth->buf1, f1->data, f1->datalen); - if (f1->samples > maxsamp) { - maxsamp = f1->samples; - } - } + + if ((len0 = ast_slinfactory_read(&csth->slinfactory[0], buf0, len))) { + samp0 = len0 / 2; + } + if((len1 = ast_slinfactory_read(&csth->slinfactory[1], buf1, len))) { + samp1 = len1 / 2; } + maxsamp = (samp0 > samp1) ? samp0 : samp1; vf = get_volfactor(csth->volfactor); - vf = minmax(vf, 16); - - dlen = (csth->len0 > csth->len1) ? csth->len0 : csth->len1; - - if (csth->len < dlen) { - if (!csth->len) { - if (!(csth->buf = malloc(dlen*2))) { - csth->spy.status = CHANSPY_DONE; - return -1; - } - } else { - if (!realloc(csth->buf, dlen * 2)) { - csth->spy.status = CHANSPY_DONE; - return -1; - } - } - csth->len = dlen; - } - + vf = minmax(vf, 16); + for(x=0; x < maxsamp; x++) { if (vf < 0) { - if (f0) { - csth->buf0[x] /= abs(vf); + if (samp0) { + buf0[x] /= abs(vf); } - if (f1) { - csth->buf1[x] /= abs(vf); + if (samp1) { + buf1[x] /= abs(vf); } } else if (vf > 0) { - if (f0) { - csth->buf0[x] *= vf; + if (samp0) { + buf0[x] *= vf; } - if (f1) { - csth->buf1[x] *= vf; + if (samp1) { + buf1[x] *= vf; } } - if (f0 && f1) { - if (x < csth->len0 && x < csth->len1) { - csth->buf[x] = ast_fit_in_short(csth->buf0[x] + csth->buf1[x]); - } else if (x < csth->len0) { - csth->buf[x] = csth->buf0[x]; - } else if (x < csth->len1) { - csth->buf[x] = csth->buf1[x]; + if (samp0 && samp1) { + if (x < samp0 && x < samp1) { + buf[x] = buf0[x] + buf1[x]; + } else if (x < samp0) { + buf[x] = buf0[x]; + } else if (x < samp1) { + buf[x] = buf1[x]; } - } else if (f0 && x < csth->len0) { - csth->buf[x] = csth->buf0[x]; - } else if (f1 && x < csth->len1) { - csth->buf[x] = csth->buf1[x]; + } else if (x < samp0) { + buf[x] = buf0[x]; + } else if (x < samp1) { + buf[x] = buf1[x]; } } - - csth->frame.data = csth->buf; - csth->frame.samples = maxsamp; - csth->frame.datalen = csth->frame.samples * 2; - csth->samples += csth->frame.samples; - if (ast_write(chan, &csth->frame)) { + memset(&frame, 0, sizeof(frame)); + frame.frametype = AST_FRAME_VOICE; + frame.subclass = AST_FORMAT_SLINEAR; + frame.data = buf; + frame.samples = x; + frame.datalen = x * 2; + + if (ast_write(chan, &frame)) { csth->spy.status = CHANSPY_DONE; return -1; } - if (csth->fd) { - write(csth->fd, csth->frame.data, csth->frame.datalen); - } - if (f0) { - ast_frfree(f0); - } - if (f1) { - ast_frfree(f1); - } - - if (loops > 10) { - ast_log(LOG_WARNING, "Too Many Loops Bailing Out...."); - break; + if (csth->fd) { + write(csth->fd, buf1, len1); } - } while (csth->samples < csth->rsamples); - return 0; + return 0; } + static struct ast_generator spygen = { alloc: spy_alloc, release: spy_release, @@ -548,10 +416,7 @@ static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, int csth.spy.status = CHANSPY_RUNNING; ast_mutex_init(&csth.spy.lock); csth.volfactor = *volfactor; - csth.frame.frametype = AST_FRAME_VOICE; - csth.frame.subclass = AST_FORMAT_SLINEAR; - csth.frame.datalen = 320; - csth.frame.samples = 160; + if (fd) { csth.fd = fd; } diff --git a/include/asterisk/slinfactory.h b/include/asterisk/slinfactory.h new file mode 100755 index 000000000..95c655cb2 --- /dev/null +++ b/include/asterisk/slinfactory.h @@ -0,0 +1,47 @@ +/* + * Asterisk -- A telephony toolkit for Linux. + * + * A machine to gather up arbitrary frames and convert them + * to raw slinear on demand. + * + * Copyright (C) 2005, Anthony Minessale II. + * + * Anthony Minessale <anthmct@yahoo.com> + * + * This program is free software, distributed under the terms of + * the GNU General Public License + */ + +#ifndef _ASTERISK_SLINFACTORY_H +#define _ASTERISK_SLINFACTORY_H +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +struct ast_slinfactory { + struct ast_frame *queue; + struct ast_trans_pvt *trans; + short hold[1280]; + short *offset; + size_t holdlen; + int size; + int format; +}; + +void ast_slinfactory_init(struct ast_slinfactory *sf); +void ast_slinfactory_destroy(struct ast_slinfactory *sf); +int ast_slinfactory_feed(struct ast_slinfactory *sf, struct ast_frame *f); +int ast_slinfactory_read(struct ast_slinfactory *sf, short *buf, size_t bytes); + + + +#if defined(__cplusplus) || defined(c_plusplus) +} +#endif + +#endif diff --git a/slinfactory.c b/slinfactory.c new file mode 100755 index 000000000..f6abe7bb1 --- /dev/null +++ b/slinfactory.c @@ -0,0 +1,152 @@ +/* + * Asterisk -- A telephony toolkit for Linux. + * + * A machine to gather up arbitrary frames and convert them + * to raw slinear on demand. + * + * Copyright (C) 2005, Anthony Minessale II. + * + * Anthony Minessale <anthmct@yahoo.com> + * + * This program is free software, distributed under the terms of + * the GNU General Public License + */ + +#include "asterisk/slinfactory.h" +#include "asterisk/file.h" +#include "asterisk/logger.h" +#include "asterisk/channel.h" +#include "asterisk/pbx.h" +#include "asterisk/module.h" +#include "asterisk/lock.h" +#include "asterisk/cli.h" +#include "asterisk/options.h" +#include "asterisk/app.h" +#include "asterisk/translate.h" + + +void ast_slinfactory_init(struct ast_slinfactory *sf) +{ + memset(sf, 0, sizeof(struct ast_slinfactory)); + sf->offset = sf->hold; + sf->queue = NULL; +} + +void ast_slinfactory_destroy(struct ast_slinfactory *sf) +{ + struct ast_frame *f; + + if (sf->trans) { + ast_translator_free_path(sf->trans); + sf->trans = NULL; + } + + while((f = sf->queue)) { + sf->queue = f->next; + ast_frfree(f); + } +} + +int ast_slinfactory_feed(struct ast_slinfactory *sf, struct ast_frame *f) +{ + struct ast_frame *frame, *frame_ptr; + + if (!f) { + return 0; + } + + if (f->subclass != AST_FORMAT_SLINEAR) { + if (sf->trans && f->subclass != sf->format) { + ast_translator_free_path(sf->trans); + sf->trans = NULL; + } + if (!sf->trans) { + if ((sf->trans = ast_translator_build_path(AST_FORMAT_SLINEAR, f->subclass)) == NULL) { + ast_log(LOG_WARNING, "Cannot build a path from %s to slin\n", ast_getformatname(f->subclass)); + return 0; + } else { + sf->format = f->subclass; + } + } + } + + if (sf->trans) { + frame = ast_translate(sf->trans, f, 0); + } else { + frame = ast_frdup(f); + } + + if (frame) { + int x = 0; + for (frame_ptr = sf->queue; frame_ptr && frame_ptr->next; frame_ptr=frame_ptr->next) { + x++; + } + if (frame_ptr) { + frame_ptr->next = frame; + } else { + sf->queue = frame; + } + frame->next = NULL; + sf->size += frame->datalen; + return x; + } + + return 0; + +} + +int ast_slinfactory_read(struct ast_slinfactory *sf, short *buf, size_t bytes) +{ + struct ast_frame *frame_ptr; + int sofar = 0, ineed, remain; + short *frame_data, *offset = buf; + + while (sofar < bytes) { + ineed = bytes - sofar; + + if (sf->holdlen) { + if ((sofar + sf->holdlen) <= ineed) { + memcpy(offset, sf->hold, sf->holdlen); + sofar += sf->holdlen; + offset += (sf->holdlen / sizeof(short)); + sf->holdlen = 0; + sf->offset = sf->hold; + } else { + remain = sf->holdlen - ineed; + memcpy(offset, sf->offset, ineed); + sofar += ineed; + sf->offset += (ineed / sizeof(short)); + sf->holdlen = remain; + } + continue; + } + + if ((frame_ptr = sf->queue)) { + sf->queue = frame_ptr->next; + frame_data = frame_ptr->data; + + if ((sofar + frame_ptr->datalen) <= ineed) { + memcpy(offset, frame_data, frame_ptr->datalen); + sofar += frame_ptr->datalen; + offset += (frame_ptr->datalen / sizeof(short)); + } else { + remain = frame_ptr->datalen - ineed; + memcpy(offset, frame_data, ineed); + sofar += ineed; + frame_data += (ineed / sizeof(short)); + memcpy(sf->hold, frame_data, remain); + sf->holdlen = remain; + } + ast_frfree(frame_ptr); + } else { + break; + } + } + + sf->size -= sofar; + return sofar; +} + + + + |