minor tweak and optimization for chanspy
authorAnthony Minessale II <anthmct@yahoo.com>
Thu, 31 Mar 2005 18:00:35 +0000 (18:00 +0000)
committerAnthony Minessale II <anthmct@yahoo.com>
Thu, 31 Mar 2005 18:00:35 +0000 (18:00 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@5317 65c4cc65-6c06-0410-ace0-fbb531ad65f3

apps/app_chanspy.c

index 4561d98..065578e 100755 (executable)
 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
-#define CS_BUFLEN 640
-
+#define CS_BUFLEN 1024
 
 static char *synopsis = "Tap into any type of asterisk channel and listen to audio";
 static char *app = "ChanSpy";
@@ -69,14 +67,28 @@ 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[CS_BUFLEN];
        struct ast_trans_pvt *trans0;
+
+       /* write frame */
+       int fmt1;
        struct ast_trans_pvt *trans1;
+       short buf1[CS_BUFLEN];
+       
+       /* muxed frame */
+       struct ast_frame frame;
+       short buf[CS_BUFLEN];
+
        int volfactor;
-       struct ast_channel_spy *spy;
+
 };
 
 /* Prototypes */
@@ -192,95 +204,122 @@ static void ast_flush_spy_queue(struct ast_channel_spy *spy)
 
 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[CS_BUFLEN], buf0[CS_BUFLEN], buf1[CS_BUFLEN];
+       struct ast_frame *f, *f0, *f1;
+       int x = 0, vf = 0;
+
        struct chanspy_translation_helper *csth = data;
-       int nc = 0, vf;
+
+       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);
        
-       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));
-                               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 (!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;
+       }
 
-               memset(buf, 0, sizeof(buf));
-               memset(buf0, 0, sizeof(buf0));
-               memset(buf1, 0, sizeof(buf1));
+       if (!csth->fmt1 && f1) {
+               csth->fmt1 = f1->subclass;
+       }
+
+       if (csth->fmt0 && csth->fmt0 != AST_FORMAT_SLINEAR && !csth->trans0) {
+               if (csth->fmt0 == csth->fmt1 && csth->trans1) {
+                       csth->trans0 = csth->trans1;
+               } else 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));
+                       return -1;
+               }
+       }
+       
+       if (csth->fmt1 && csth->fmt1 != AST_FORMAT_SLINEAR && !csth->trans1) {
+               if (csth->fmt1 == csth->fmt0 && csth->trans0) {
+                       csth->trans1 = csth->trans0;
+               } else 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));
+                       return -1;
+               }
+       }
+       
+       if (f0) {
                if (csth->trans0) {
                        if ((f = ast_translate(csth->trans0, f0, 0))) {
-                               framelen_a = f->datalen * sizeof(short);
-                               memcpy(buf0, f->data, framelen_a);
+                               memcpy(csth->buf0, f->data, f->datalen * sizeof(short));
                                ast_frfree(f);
-                       } else 
+                       } else {
                                return 0;
+                       }
                } else {
-                       framelen_a = f0->datalen * sizeof(short);
-                       memcpy(buf0, f0->data, framelen_a);
+                       memcpy(csth->buf0, f0->data, f0->datalen * sizeof(short));
                }
+       }
+       
+       if (f1) {
                if (csth->trans1) {
                        if ((f = ast_translate(csth->trans1, f1, 0))) {
-                               framelen_b = f->datalen * sizeof(short);
-                               memcpy(buf1, f->data, framelen_b);
+                               memcpy(csth->buf1, f->data, f->datalen * sizeof(short));
                                ast_frfree(f);
-                       } else 
+                       } else {
                                return 0;
+                       }
                } else {
-                       framelen_b = f1->datalen * sizeof(short);
-                       memcpy(buf1, f1->data, framelen_b);
+                       memcpy(csth->buf1, f1->data, f1->datalen * sizeof(short));
                }
-               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++) {
-                       if (vf < 0) {
-                               buf0[x] /= abs(vf);
-                               buf1[x] /= abs(vf);
-                       } else if (vf > 0) {
-                               buf0[x] *= vf;
-                               buf1[x] *= vf;
+       }
+
+       vf = get_volfactor(csth->volfactor);
+       vf = minmax(vf, 16);
+       for(x=0; x < len; x++) {
+               if (vf < 0) {
+                       if (f0) {
+                               csth->buf0[x] /= abs(vf);
+                       }
+                       if (f1) {
+                               csth->buf1[x] /= abs(vf);
+                       }
+               } else if (vf > 0) {
+                       if (f0) {
+                               csth->buf0[x] *= vf;
+                       }
+                       if (f1) {
+                               csth->buf1[x] *= vf;
                        }
-                       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) {
-                       return -1;
+               if (f0 && f1) {
+                       csth->buf[x] = ast_fit_in_short(csth->buf0[x] + csth->buf1[x]);
+               } else if (f0) {
+                       csth->buf[x] = csth->buf0[x];
+               } else if (f1) {
+                       csth->buf[x] = csth->buf1[x];
                }
        }
+
+       csth->frame.data = csth->buf;
+       ast_write(chan, &csth->frame);
        
-       if (f0)
+       if (f0) {
                ast_frfree(f0);
-       if (f1) 
+       }
+       if (f1) {
                ast_frfree(f1);
+       }
 
        return 0;
-
 }
 
 static struct ast_generator spygen = {
@@ -356,25 +395,25 @@ 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;
 
        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) {
+               while(csth.spy.status == CHANSPY_RUNNING && chan && !ast_check_hangup(chan) && spyee && !ast_check_hangup(spyee) && running == 1) {
                        res = ast_waitfordigit(chan, 100);
 
                        if (x == sizeof(inp)) {
@@ -406,16 +445,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;
 }
 
@@ -423,23 +462,27 @@ 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;
-       int chosen = 0;
+
 
        if (!(args = ast_strdupa((char *)data))) {
                ast_log(LOG_ERROR, "Out of memory!\n");
@@ -450,6 +493,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;