add slinfactory object, and change app_chanspy to use it (bug #4724)
authorKevin P. Fleming <kpfleming@digium.com>
Wed, 20 Jul 2005 00:53:21 +0000 (00:53 +0000)
committerKevin P. Fleming <kpfleming@digium.com>
Wed, 20 Jul 2005 00:53:21 +0000 (00:53 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@6177 65c4cc65-6c06-0410-ace0-fbb531ad65f3

Makefile
apps/app_chanspy.c
include/asterisk/slinfactory.h [new file with mode: 0755]
slinfactory.c [new file with mode: 0755]

index 2efea26..5da4ff7 100755 (executable)
--- a/Makefile
+++ b/Makefile
@@ -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
index 7ed00cd..5bc8c79 100755 (executable)
@@ -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 (executable)
index 0000000..95c655c
--- /dev/null
@@ -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 (executable)
index 0000000..f6abe7b
--- /dev/null
@@ -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;
+}
+
+
+
+