X-Git-Url: http://git.asterisk.org/gitweb/?p=asterisk%2Fasterisk.git;a=blobdiff_plain;f=apps%2Fapp_chanspy.c;h=c7ea3aa95c39da8e1fd9f3c4478ca40b83365cfd;hp=6e28a0341ba2b3ecc0979cc0ec97d181c4169976;hb=7d2b59410d8171867baa3bcf4cdef033b5c4179b;hpb=ba6613e7693fedee536afeeb8b6f0ea62c969048;ds=sidebyside diff --git a/apps/app_chanspy.c b/apps/app_chanspy.c index 6e28a03..c7ea3aa 100755 --- a/apps/app_chanspy.c +++ b/apps/app_chanspy.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -32,14 +31,12 @@ AST_MUTEX_DEFINE_STATIC(modlock); #define ast_fit_in_short(in) (in < -32768 ? -32768 : in > 32767 ? 32767 : in) -#define find_smallest_of_three(a, b, c) ((a < b && a < c) ? a : (b < a && b < c) ? b : c) #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 #define minmax(x,y) x ? (x > y) ? y : ((x < (y * -1)) ? (y * -1) : x) : 0 - static char *synopsis = "Tap into any type of asterisk channel and listen to audio"; static char *app = "ChanSpy"; static char *desc = " Chanspy([][|])\n\n" @@ -70,18 +67,37 @@ AST_DECLARE_OPTIONS(chanspy_opts,{ }); STANDARD_LOCAL_USER; - 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; - struct ast_channel_spy *spy; }; /* Prototypes */ static struct ast_channel *local_get_channel_by_name(char *name); +static struct ast_channel *local_get_channel_begin_name(char *name); static struct ast_channel *local_channel_walk(struct ast_channel *chan); static void spy_release(struct ast_channel *chan, void *data); static void *spy_alloc(struct ast_channel *chan, void *params); @@ -117,23 +133,50 @@ static struct ast_channel *local_channel_walk(struct ast_channel *chan) return ret; } +static struct ast_channel *local_get_channel_begin_name(char *name) +{ + struct ast_channel *chan, *ret = NULL; + ast_mutex_lock(&modlock); + chan = local_channel_walk(NULL); + while (chan) { + if (!strncmp(chan->name, name, strlen(name))) { + ret = chan; + break; + } + chan = local_channel_walk(chan); + } + ast_mutex_unlock(&modlock); + + return ret; +} + + static void spy_release(struct ast_channel *chan, void *data) { struct chanspy_translation_helper *csth = data; - int same=0; - same = (csth->trans0 == csth->trans1) ? 1 : 0; if (csth->trans0) { ast_translator_free_path(csth->trans0); csth->trans0 = NULL; } - if (same) - return; 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; } @@ -171,98 +214,212 @@ 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 *f0, *f1, write_frame, *f; - int x=0, framelen_a = 0, framelen_b = 0, size = 0; - short buf[320], buf0[320], buf1[320]; + struct ast_frame *f, *f0, *f1; + int x, vf, dlen, maxsamp, loops; struct chanspy_translation_helper *csth = data; - int nc = 0, vf; + + 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; + } + + 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; + } - 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 (f0 && f1) { - if (!csth->trans0) { - if (f0->subclass != AST_FORMAT_SLINEAR && (csth->trans0 = ast_translator_build_path(AST_FORMAT_SLINEAR, f0->subclass)) == NULL) { - ast_log(LOG_WARNING, "Cannot build a path from %s to slin\n", ast_getformatname(f0->subclass)); + if (!f0 && !f1) { + return 0; + } + + if (f0 && csth->fmt0 && csth->fmt0 != f0->subclass) { + ast_translator_free_path(csth->trans0); + csth->trans0 = NULL; + csth->fmt0 = csth->fmt0; + } + + if (f1 && csth->fmt1 && csth->fmt1 != f1->subclass) { + ast_translator_free_path(csth->trans1); + csth->trans1 = NULL; + csth->fmt1 = csth->fmt1; + } + + if (!csth->fmt0 && f0) { + csth->fmt0 = f0->subclass; + } + + if (!csth->fmt1 && f1) { + csth->fmt1 = f1->subclass; + } + + 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; } - if (!csth->trans1) { - if (f1->subclass == f0->subclass) { - csth->trans1 = csth->trans0; - } else if (f1->subclass != AST_FORMAT_SLINEAR && (csth->trans1 = ast_translator_build_path(AST_FORMAT_SLINEAR, f1->subclass)) == NULL) { - ast_log(LOG_WARNING, "Cannot build a path from %s to slin\n", ast_getformatname(f1->subclass)); - return -1; - } - + } + 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; } } - - memset(buf, 0, sizeof(buf)); - memset(buf0, 0, sizeof(buf0)); - memset(buf1, 0, sizeof(buf1)); - if (csth->trans0) { - if ((f = ast_translate(csth->trans0, f0, 0))) { - framelen_a = f->datalen * sizeof(short); - memcpy(buf0, f->data, framelen_a); - ast_frfree(f); - } else - return 0; - } else { - framelen_a = f0->datalen * sizeof(short); - memcpy(buf0, f0->data, framelen_a); + + 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 { + memcpy(csth->buf0, f0->data, f0->datalen); + maxsamp = f0->samples; + } } - if (csth->trans1) { - if ((f = ast_translate(csth->trans1, f1, 0))) { - framelen_b = f->datalen * sizeof(short); - memcpy(buf1, f->data, framelen_b); - ast_frfree(f); - } else - return 0; - } else { - framelen_b = f1->datalen * sizeof(short); - memcpy(buf1, f1->data, framelen_b); + + 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))) { + csth->spy.status = CHANSPY_DONE; + return -1; + } + } else { + if (!realloc(csth->buf1, f->datalen)) { + 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 { + memcpy(csth->buf1, f1->data, f1->datalen); + if (f1->samples > maxsamp) { + maxsamp = f1->samples; + } + } } - size = find_smallest_of_three(len, framelen_a, framelen_b); vf = get_volfactor(csth->volfactor); vf = minmax(vf, 16); - for(x=0; x < size; x++) { + + 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; + } + + for(x=0; x < maxsamp; x++) { if (vf < 0) { - buf0[x] /= abs(vf); - buf1[x] /= abs(vf); + if (f0) { + csth->buf0[x] /= abs(vf); + } + if (f1) { + csth->buf1[x] /= abs(vf); + } } else if (vf > 0) { - buf0[x] *= vf; - buf1[x] *= vf; + if (f0) { + csth->buf0[x] *= vf; + } + if (f1) { + csth->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]; + } + } else if (f0 && x < csth->len0) { + csth->buf[x] = csth->buf0[x]; + } else if (f1 && x < csth->len1) { + csth->buf[x] = csth->buf1[x]; } - buf[x] = ast_fit_in_short(buf0[x] + buf1[x]); } - memset(&write_frame, 0, sizeof(write_frame)); - write_frame.frametype = AST_FRAME_VOICE; - write_frame.subclass = AST_FORMAT_SLINEAR; - write_frame.datalen = size; - write_frame.samples = size; - write_frame.data = buf; - write_frame.offset = 0; - ast_write(chan, &write_frame); - } else { - nc++; - if(nc > 1) { + + 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)) { + csth->spy.status = CHANSPY_DONE; return -1; } - } - - if (f0) - ast_frfree(f0); - if (f1) - ast_frfree(f1); - return 0; + if (f0) { + ast_frfree(f0); + } + if (f1) { + ast_frfree(f1); + } + if (loops > 10) { + ast_log(LOG_WARNING, "Too Many Loops Bailing Out...."); + break; + } + } while (csth->samples < csth->rsamples); + + return 0; } static struct ast_generator spygen = { @@ -312,7 +469,7 @@ static void stop_spying(struct ast_channel *chan, struct ast_channel_spy *spy) return; } count++; - if(count > 10) { + if (count > 10) { return; } sched_yield(); @@ -338,27 +495,43 @@ static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, int int running = 1, res = 0, x = 0; char inp[24]; char *name=NULL; - struct ast_channel_spy spy; + struct ast_frame *f; if (chan && !ast_check_hangup(chan) && spyee && !ast_check_hangup(spyee)) { memset(inp, 0, sizeof(inp)); name = ast_strdupa(spyee->name); if (option_verbose >= 2) ast_verbose(VERBOSE_PREFIX_2 "Spying on channel %s\n", name); - - memset(&spy, 0, sizeof(struct ast_channel_spy)); - spy.status = CHANSPY_RUNNING; - ast_mutex_init(&spy.lock); - start_spying(spyee, chan, &spy); - + memset(&csth, 0, sizeof(csth)); + csth.spy.status = CHANSPY_RUNNING; + ast_mutex_init(&csth.spy.lock); csth.volfactor = *volfactor; - csth.spy = &spy; + csth.frame.frametype = AST_FRAME_VOICE; + csth.frame.subclass = AST_FORMAT_SLINEAR; + csth.frame.datalen = 320; + csth.frame.samples = 160; + start_spying(spyee, chan, &csth.spy); ast_activate_generator(chan, &spygen, &csth); - while(spy.status == CHANSPY_RUNNING && chan && !ast_check_hangup(chan) && spyee && !ast_check_hangup(spyee) && running == 1) { - res = ast_waitfordigit(chan, 100); - + while(csth.spy.status == CHANSPY_RUNNING && + chan && !ast_check_hangup(chan) && + spyee && + !ast_check_hangup(spyee) + && running == 1 && + (res = ast_waitfor(chan, -1) > -1)) { + if ((f = ast_read(chan))) { + res = 0; + if (f->frametype == AST_FRAME_DTMF) { + res = f->subclass; + } + ast_frfree(f); + if (!res) { + continue; + } + } else { + break; + } if (x == sizeof(inp)) { x = 0; } @@ -388,16 +561,16 @@ static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, int } } ast_deactivate_generator(chan); - stop_spying(spyee, &spy); + stop_spying(spyee, &csth.spy); - if (option_verbose >= 2) + if (option_verbose >= 2) { ast_verbose(VERBOSE_PREFIX_2 "Done Spying on channel %s\n", name); - - ast_flush_spy_queue(&spy); + } + ast_flush_spy_queue(&csth.spy); } else { running = 0; } - ast_mutex_destroy(&spy.lock); + ast_mutex_destroy(&csth.spy.lock); return running; } @@ -405,22 +578,26 @@ static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, int static int chanspy_exec(struct ast_channel *chan, void *data) { - int res=-1; struct localuser *u; struct ast_channel *peer=NULL, *prev=NULL; - char *ptr=NULL; - char name[AST_NAME_STRLEN], peer_name[AST_NAME_STRLEN]; - int count=0, waitms=100, num=0; - char *args; + char name[AST_NAME_STRLEN], + peer_name[AST_NAME_STRLEN], + *args, + *ptr = NULL, + *options = NULL, + *spec = NULL, + *argv[5], + *mygroup = NULL; + int res = -1, + volfactor = 0, + silent = 0, + argc = 0, + bronly = 0, + chosen = 0, + count=0, + waitms = 100, + num = 0; struct ast_flags flags; - char *options=NULL; - char *spec = NULL; - int volfactor=0; - int silent=0; - int argc = 0; - char *argv[5]; - char *mygroup = NULL; - int bronly = 0; if (!(args = ast_strdupa((char *)data))) { @@ -432,6 +609,7 @@ static int chanspy_exec(struct ast_channel *chan, void *data) ast_log(LOG_ERROR, "Could Not Set Read Format.\n"); return -1; } + if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) { ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); return -1; @@ -456,17 +634,17 @@ static int chanspy_exec(struct ast_channel *chan, void *data) if (options) { char *opts[2]; ast_parseoptions(chanspy_opts, &flags, opts, options); - if (ast_test_flag(&flags, OPTION_GROUP)) - mygroup = opts[0]; + if (ast_test_flag(&flags, OPTION_GROUP)) { + mygroup = opts[1]; + } silent = ast_test_flag(&flags, OPTION_QUIET); bronly = ast_test_flag(&flags, OPTION_BRIDGED); if (ast_test_flag(&flags, OPTION_VOLUME) && opts[1]) { - if (sscanf(opts[1], "%d", &volfactor) != 1) - ast_log(LOG_NOTICE, "volfactor must be a number between -16 and 16\n"); - else if (volfactor > 16) - volfactor = 16; - else if (volfactor < -16) - volfactor = -16; + if (sscanf(opts[0], "%d", &volfactor) != 1) + ast_log(LOG_NOTICE, "volfactor must be a number between -4 and 4\n"); + else { + volfactor = minmax(volfactor, 4); + } } } @@ -492,19 +670,21 @@ static int chanspy_exec(struct ast_channel *chan, void *data) while(peer) { if (peer != chan) { char *group = NULL; + int igrp = 1; - if (peer == prev) { + if (peer == prev && !chosen) { break; } - - group = pbx_builtin_getvar_helper(chan, "SPYGROUP"); - - if (mygroup && group && strcmp(group, mygroup)) { - continue; + chosen = 0; + group = pbx_builtin_getvar_helper(peer, "SPYGROUP"); + if (mygroup) { + if (!group || strcmp(mygroup, group)) { + igrp = 0; + } } - if (!spec || ((strlen(spec) < strlen(peer->name) && - !strncasecmp(peer->name, spec, strlen(spec))))) { - + + if (igrp && (!spec || ((strlen(spec) < strlen(peer->name) && + !strncasecmp(peer->name, spec, strlen(spec)))))) { if (peer && (!bronly || ast_bridged_channel(peer)) && !ast_check_hangup(peer) && !ast_test_flag(peer, AST_FLAG_SPYING)) { int x = 0; @@ -514,7 +694,7 @@ static int chanspy_exec(struct ast_channel *chan, void *data) *ptr = '\0'; ptr++; for (x = 0 ; x < strlen(peer_name) ; x++) { - if(peer_name[x] == '/') { + if (peer_name[x] == '/') { break; } peer_name[x] = tolower(peer_name[x]); @@ -540,17 +720,17 @@ static int chanspy_exec(struct ast_channel *chan, void *data) ALL_DONE(u, -1); } else if (res > 1 && spec) { snprintf(name, AST_NAME_STRLEN, "%s/%d", spec, res); - if (!silent) - ast_say_digits(chan, res, "", chan->language); - peer=local_get_channel_by_name(name); + if ((peer = local_get_channel_begin_name(name))) { + chosen = 1; + } continue; } } } } - - if ((peer = local_channel_walk(peer)) == NULL) + if ((peer = local_channel_walk(peer)) == NULL) { break; + } } waitms = count ? 100 : 5000; }