Version 0.1.1 from FTP
authorMark Spencer <markster@digium.com>
Thu, 16 Dec 1999 13:44:30 +0000 (13:44 +0000)
committerMark Spencer <markster@digium.com>
Thu, 16 Dec 1999 13:44:30 +0000 (13:44 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@139 65c4cc65-6c06-0410-ace0-fbb531ad65f3

13 files changed:
BUGS
channels/chan_ixj.c
channels/chan_vofr.c
codecs/mp3/Makefile [new file with mode: 0755]
formats/format_g723.c
formats/format_gsm.c [new file with mode: 0755]
formats/format_mp3.c
formats/format_wav.c
formats/format_wav_gsm.c [new file with mode: 0755]
formats/msgsm.h [new file with mode: 0755]
include/asterisk/channel_pvt.h
include/asterisk/io.h
io.c

diff --git a/BUGS b/BUGS
index 04fbe3e..495e20d 100755 (executable)
--- a/BUGS
+++ b/BUGS
@@ -2,8 +2,10 @@
   these bugs are in asterisk, and sometimes they relate to the products
   that asterisk uses.
 
-* The MP3 decoder is completely broken
-
 * The translator API may introduce warble in the case of going in both
   directions, but I haven't verified that.  The trouble should only enter
   in the case of mismatched frame lengths.
+
+* In general Asterisk is a very new program, and there are liable to be
+  many bugs yet to be discovered, so if you think you've found one, please
+  be sure to report it.
index 5f476cd..c8cdb91 100755 (executable)
@@ -3,7 +3,7 @@
  *
  * QuickNet Internet Phone Jack Channel
  * 
- * Copyright (C) 1999, Adtran Inc. and Linux Support Services, LLC
+ * Copyright (C) 1999, Mark Spencer
  *
  * Mark Spencer <markster@linux-support.net>
  *
@@ -60,7 +60,7 @@ static pthread_mutex_t monlock = PTHREAD_MUTEX_INITIALIZER;
    which are not currently in use.  */
 static pthread_t monitor_thread = -1;
 
-static int restart_monitor();
+static int restart_monitor(void);
 
 /* The private structures of the Phone Jack channels are linked for
    selecting outgoing channels */
@@ -129,7 +129,8 @@ static int ixj_call(struct ast_channel *ast, char *dest, int timeout)
        }
        /* When we call, it just works, really, there's no destination...  Just
           ring the phone and wait for someone to answer */
-       ast_log(LOG_DEBUG, "Ringing %s on %s (%d)\n", dest, ast->name, ast->fd);
+       if (option_debug)
+               ast_log(LOG_DEBUG, "Ringing %s on %s (%d)\n", dest, ast->name, ast->fd);
        ioctl(p->fd, IXJCTL_RING_START);
        ast->state = AST_STATE_RINGING;
        return 0;
@@ -139,7 +140,8 @@ static int ixj_hangup(struct ast_channel *ast)
 {
        struct ixj_pvt *p;
        p = ast->pvt->pvt;
-       ast_log(LOG_DEBUG, "ixj_hangup(%s)\n", ast->name);
+       if (option_debug)
+               ast_log(LOG_DEBUG, "ixj_hangup(%s)\n", ast->name);
        if (!ast->pvt->pvt) {
                ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
                return 0;
@@ -217,7 +219,8 @@ static int ixj_setup(struct ast_channel *ast)
 static int ixj_answer(struct ast_channel *ast)
 {
        ixj_setup(ast);
-       ast_log(LOG_DEBUG, "ixj_answer(%s)\n", ast->name);
+       if (option_debug)
+               ast_log(LOG_DEBUG, "ixj_answer(%s)\n", ast->name);
        ast->rings = 0;
        ast->state = AST_STATE_UP;
        return 0;
@@ -287,6 +290,14 @@ static struct ast_frame  *ixj_read(struct ast_channel *ast)
        res = read(p->fd, p->buf, IXJ_MAX_BUF);
        ast->blocking = 0;
        if (res < 0) {
+#if 0
+               if (errno == EAGAIN) {
+                       ast_log(LOG_WARNING, "Null frame received\n");
+                       p->fr.frametype = AST_FRAME_NULL;
+                       p->fr.subclass = 0;
+                       return &p->fr;
+               }
+#endif
                ast_log(LOG_WARNING, "Error reading: %s\n", strerror(errno));
                return NULL;
        }
@@ -486,6 +497,10 @@ static void ixj_check_exception(struct ixj_pvt *i)
                                ixj_new(i, AST_STATE_UP);
                                /* No need to restart monitor, we are the monitor */
                                if (i->owner) {
+                                       pthread_mutex_lock(&usecnt_lock);
+                                       usecnt--;
+                                       pthread_mutex_unlock(&usecnt_lock);
+                                       ast_update_use_count();
                                        ixj_setup(i->owner);
                                }
                        } else if (ast_exists_extension(NULL, "default", i->ext, 1)) {
@@ -494,10 +509,16 @@ static void ixj_check_exception(struct ixj_pvt *i)
                                strncpy(i->context, "default", sizeof(i->context));
                                ixj_new(i, AST_STATE_UP);
                                if (i->owner) {
+                                       pthread_mutex_lock(&usecnt_lock);
+                                       usecnt--;
+                                       pthread_mutex_unlock(&usecnt_lock);
+                                       ast_update_use_count();
                                        ixj_setup(i->owner);
                                }
                        } else if ((strlen(i->ext) >= ast_pbx_longest_extension(i->context)) &&
                                           (strlen(i->ext) >= ast_pbx_longest_extension("default"))) {
+                               if (option_debug)
+                                       ast_log(LOG_DEBUG, "%s is too long\n", i->ext);
                                /* It's not a valid extension, give a busy signal */
                                ioctl(i->fd, IXJCTL_BUSY);
                        }
@@ -512,18 +533,23 @@ static void ixj_check_exception(struct ixj_pvt *i)
                        if (i->mode == MODE_IMMEDIATE) {
                                ixj_new(i, AST_STATE_RING);
                        } else if (i->mode == MODE_DIALTONE) {
-#if 0
-                               /* XXX Bug in the Phone jack, you can't detect DTMF when playing a tone XXX */
-                               ioctl(i->fd, IXJCTL_DIALTONE);
-#else
+                               pthread_mutex_lock(&usecnt_lock);
+                               usecnt++;
+                               pthread_mutex_unlock(&usecnt_lock);
+                               ast_update_use_count();
                                /* Play the dialtone */
                                i->dialtone++;
                                ioctl(i->fd, IXJCTL_PLAY_STOP);
                                ioctl(i->fd, IXJCTL_PLAY_CODEC, ULAW);
                                ioctl(i->fd, IXJCTL_PLAY_START);
-#endif
                        }
                } else {
+                       if (i->dialtone) {
+                               pthread_mutex_lock(&usecnt_lock);
+                               usecnt--;
+                               pthread_mutex_unlock(&usecnt_lock);
+                               ast_update_use_count();
+                       }
                        memset(i->ext, 0, sizeof(i->ext));
                        ioctl(i->fd, IXJCTL_CPT_STOP);
                        ioctl(i->fd, IXJCTL_PLAY_STOP);
@@ -690,11 +716,13 @@ static int restart_monitor()
        return 0;
 }
 
-struct ixj_pvt *mkif(char *iface, int mode)
+static struct ixj_pvt *mkif(char *iface, int mode)
 {
        /* Make a ixj_pvt structure for this interface */
        struct ixj_pvt *tmp;
+#if 0
        int flags;      
+#endif
        
        tmp = malloc(sizeof(struct ixj_pvt));
        if (tmp) {
@@ -709,8 +737,10 @@ struct ixj_pvt *mkif(char *iface, int mode)
                ioctl(tmp->fd, IXJCTL_RING_STOP);
                ioctl(tmp->fd, IXJCTL_CPT_STOP);
                tmp->mode = mode;
+#if 0
                flags = fcntl(tmp->fd, F_GETFL);
                fcntl(tmp->fd, F_SETFL, flags | O_NONBLOCK);
+#endif
                tmp->owner = NULL;
                tmp->lastformat = -1;
                tmp->lastinput = -1;
index ea17df9..aee44ff 100755 (executable)
@@ -3,7 +3,7 @@
  *
  * Implementation of Voice over Frame Relay, Adtran Style
  * 
- * Copyright (C) 1999, Adtran Inc. and Linux Support Services, LLC
+ * Copyright (C) 1999, Mark Spencer
  *
  * Mark Spencer <markster@linux-support.net>
  *
@@ -55,7 +55,7 @@ static pthread_mutex_t monlock = PTHREAD_MUTEX_INITIALIZER;
    which are not currently in use.  */
 static pthread_t monitor_thread = -1;
 
-static int restart_monitor();
+static int restart_monitor(void);
 
 /* The private structures of the Adtran VoFR channels are linked for
    selecting outgoing channels */
@@ -558,6 +558,9 @@ static struct ast_frame  *vofr_read(struct ast_channel *ast)
                                fr->subclass = 0;
                                break;
                        }
+               case VOFR_SIGNAL_RING:
+                       ast->rings++;
+                       break;
                case VOFR_SIGNAL_UNKNOWN:
                        switch(vh->data[1]) {
                        case 0x1:
@@ -783,7 +786,21 @@ static int vofr_mini_packet(struct vofr_pvt *i, struct vofr_hdr *pkt, int len)
                switch(pkt->data[0]) {
                case VOFR_SIGNAL_RING:
                        /* If we get a RING, we definitely want to start a new thread */
-                       vofr_new(i, AST_STATE_RING);
+                       if (!i->owner)
+                               vofr_new(i, AST_STATE_RING);
+                       else
+                               ast_log(LOG_WARNING, "Got a ring, but there's an owner?\n");
+                       break;
+               case VOFR_SIGNAL_OFF_HOOK:
+                       /* Network termination, go off hook */
+#if 0
+                       ast_log(LOG_DEBUG, "Off hook\n");
+#endif
+                       vofr_xmit_signal(i, 0x10, 2);
+                       if (!i->owner)
+                               vofr_new(i, AST_STATE_UP);
+                       else
+                               ast_log(LOG_WARNING, "Got an offhook, but there's an owner?\n");
                        break;
                case VOFR_SIGNAL_ON_HOOK:
                        break;
@@ -896,7 +913,7 @@ static void *do_monitor(void *data)
        
 }
 
-static int restart_monitor()
+static int restart_monitor(void)
 {
        /* If we're supposed to be stopped -- stay stopped */
        if (monitor_thread == -2)
@@ -926,7 +943,7 @@ static int restart_monitor()
        return 0;
 }
 
-struct vofr_pvt *mkif(char *type, char *iface)
+static struct vofr_pvt *mkif(char *type, char *iface)
 {
        /* Make a vofr_pvt structure for this interface */
        struct vofr_pvt *tmp;
diff --git a/codecs/mp3/Makefile b/codecs/mp3/Makefile
new file mode 100755 (executable)
index 0000000..44ebc39
--- /dev/null
@@ -0,0 +1,37 @@
+#
+# LMC section
+
+CFLAGS+= -I../include -Iinclude -O6 -funroll-loops -finline-functions -Wall -Wno-missing-prototypes -Wno-missing-declarations -g
+RANLIB=ranlib
+
+# the XING decoder objs and dependencies:
+# This is kinda nasty, since there's C, C++, and asm, oh my!
+# of course, each needs different compilation methods. grr.
+XINGOBJX86 = src/x86gas.o
+
+XINGOBJS = src/cdct.o src/cupl3.o \
+  src/hwin.o src/iup.o src/l3init.o \
+  src/msis.o src/wavep.o src/csbt.o \
+  src/cwinm.o src/icdct.o src/mdct.o \
+  src/uph.o src/cup.o src/dec8.o \
+  src/isbt.o src/l3dq.o src/mhead.o \
+  src/upsf.o src/iwinm.o
+
+LIBMP3=libmp3.a
+ARFLAGS=cr
+
+XINGLMCOBJC += $(shell if uname -m | grep -q i.86; then echo src/x86gas.o; fi)
+
+#assembly lang code, if we need it
+
+XINGLMCOBJ = $(XINGOBJS)
+
+all: $(LIBMP3)
+
+$(LIBMP3): $(XINGOBJS)
+       $(AR) $(ARFLAGS) $(LIBMP3) $(XINGLMCOBJ)
+       $(RANLIB) $(LIBMP3)
+
+clean:
+       rm -f $(XINGOBJS)
+       rm -f $(LIBMP3)
index 8279870..3824e04 100755 (executable)
@@ -3,7 +3,7 @@
  *
  * Old-style G.723 frame/timestamp format.
  * 
- * Copyright (C) 1999, Adtran Inc. and Linux Support Services, LLC
+ * Copyright (C) 1999, Mark Spencer
  *
  * Mark Spencer <markster@linux-support.net>
  *
@@ -285,7 +285,7 @@ static int g723_write(struct ast_filestream *fs, struct ast_frame *f)
        return 0;
 }
 
-char *g723_getcomment(struct ast_filestream *s)
+static char *g723_getcomment(struct ast_filestream *s)
 {
        return NULL;
 }
diff --git a/formats/format_gsm.c b/formats/format_gsm.c
new file mode 100755 (executable)
index 0000000..6a06627
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * Asterisk -- A telephony toolkit for Linux.
+ *
+ * Save to raw, headerless GSM data.
+ * 
+ * Copyright (C) 1999, Mark Spencer
+ *
+ * Mark Spencer <markster@linux-support.net>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License
+ */
+#include <asterisk/channel.h>
+#include <asterisk/file.h>
+#include <asterisk/logger.h>
+#include <asterisk/sched.h>
+#include <asterisk/module.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+#include <endian.h>
+
+/* Some Ideas for this code came from makegsme.c by Jeffery Chilton */
+
+/* Portions of the conversion code are by guido@sienanet.it */
+
+struct ast_filestream {
+       void *reserved[AST_RESERVED_POINTERS];
+       /* Believe it or not, we must decode/recode to account for the
+          weird MS format */
+       /* This is what a filestream means to us */
+       int fd; /* Descriptor */
+       struct ast_channel *owner;
+       struct ast_frame fr;                            /* Frame information */
+       char waste[AST_FRIENDLY_OFFSET];        /* Buffer for sending frames, etc */
+       char empty;                                                     /* Empty character */
+       unsigned char gsm[33];                          /* Two Real GSM Frames */
+       int lasttimeout;
+       struct timeval last;
+       int adj;
+       struct ast_filestream *next;
+};
+
+
+static struct ast_filestream *glist = NULL;
+static pthread_mutex_t gsm_lock = PTHREAD_MUTEX_INITIALIZER;
+static int glistcnt = 0;
+
+static char *name = "gsm";
+static char *desc = "Raw GSM data";
+static char *exts = "gsm";
+
+static struct ast_filestream *gsm_open(int fd)
+{
+       /* We don't have any header to read or anything really, but
+          if we did, it would go here.  We also might want to check
+          and be sure it's a valid file.  */
+       struct ast_filestream *tmp;
+       if ((tmp = malloc(sizeof(struct ast_filestream)))) {
+               memset(tmp, 0, sizeof(struct ast_filestream));
+               if (pthread_mutex_lock(&gsm_lock)) {
+                       ast_log(LOG_WARNING, "Unable to lock gsm list\n");
+                       free(tmp);
+                       return NULL;
+               }
+               tmp->next = glist;
+               glist = tmp;
+               tmp->fd = fd;
+               tmp->owner = NULL;
+               tmp->fr.data = tmp->gsm;
+               tmp->fr.frametype = AST_FRAME_VOICE;
+               tmp->fr.subclass = AST_FORMAT_GSM;
+               /* datalen will vary for each frame */
+               tmp->fr.src = name;
+               tmp->fr.mallocd = 0;
+               tmp->lasttimeout = -1;
+               glistcnt++;
+               pthread_mutex_unlock(&gsm_lock);
+               ast_update_use_count();
+       }
+       return tmp;
+}
+
+static struct ast_filestream *gsm_rewrite(int fd, char *comment)
+{
+       /* We don't have any header to read or anything really, but
+          if we did, it would go here.  We also might want to check
+          and be sure it's a valid file.  */
+       struct ast_filestream *tmp;
+       if ((tmp = malloc(sizeof(struct ast_filestream)))) {
+               memset(tmp, 0, sizeof(struct ast_filestream));
+               if (pthread_mutex_lock(&gsm_lock)) {
+                       ast_log(LOG_WARNING, "Unable to lock gsm list\n");
+                       free(tmp);
+                       return NULL;
+               }
+               tmp->next = glist;
+               glist = tmp;
+               tmp->fd = fd;
+               tmp->owner = NULL;
+               tmp->lasttimeout = -1;
+               glistcnt++;
+               pthread_mutex_unlock(&gsm_lock);
+               ast_update_use_count();
+       } else
+               ast_log(LOG_WARNING, "Out of memory\n");
+       return tmp;
+}
+
+static struct ast_frame *gsm_read(struct ast_filestream *s)
+{
+       return NULL;
+}
+
+static void gsm_close(struct ast_filestream *s)
+{
+       struct ast_filestream *tmp, *tmpl = NULL;
+       if (pthread_mutex_lock(&gsm_lock)) {
+               ast_log(LOG_WARNING, "Unable to lock gsm list\n");
+               return;
+       }
+       tmp = glist;
+       while(tmp) {
+               if (tmp == s) {
+                       if (tmpl)
+                               tmpl->next = tmp->next;
+                       else
+                               glist = tmp->next;
+                       break;
+               }
+               tmpl = tmp;
+               tmp = tmp->next;
+       }
+       glistcnt--;
+       if (s->owner) {
+               s->owner->stream = NULL;
+               if (s->owner->streamid > -1)
+                       ast_sched_del(s->owner->sched, s->owner->streamid);
+               s->owner->streamid = -1;
+       }
+       pthread_mutex_unlock(&gsm_lock);
+       ast_update_use_count();
+       if (!tmp) 
+               ast_log(LOG_WARNING, "Freeing a filestream we don't seem to own\n");
+       close(s->fd);
+       free(s);
+}
+
+static int ast_read_callback(void *data)
+{
+       int retval = 0;
+       int res;
+       int delay = 20;
+       struct ast_filestream *s = data;
+       struct timeval tv;
+       /* Send a frame from the file to the appropriate channel */
+
+       s->fr.frametype = AST_FRAME_VOICE;
+       s->fr.subclass = AST_FORMAT_GSM;
+       s->fr.offset = AST_FRIENDLY_OFFSET;
+       s->fr.timelen = 20;
+       s->fr.datalen = 33;
+       s->fr.mallocd = 0;
+       s->fr.data = s->gsm;
+       if ((res = read(s->fd, s->gsm, 33)) != 33) {
+               if (res)
+                       ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
+               s->owner->streamid = -1;
+               return 0;
+       }
+       /* Lastly, process the frame */
+       if (ast_write(s->owner, &s->fr)) {
+               ast_log(LOG_WARNING, "Failed to write frame\n");
+               s->owner->streamid = -1;
+               return 0;
+       }
+       if (s->last.tv_usec || s->last.tv_usec) {
+               int ms;
+               gettimeofday(&tv, NULL);
+               ms = 1000 * (tv.tv_sec - s->last.tv_sec) + 
+                       (tv.tv_usec - s->last.tv_usec) / 1000;
+               s->last.tv_sec = tv.tv_sec;
+               s->last.tv_usec = tv.tv_usec;
+               if ((ms - delay) * (ms - delay) > 4) {
+                       /* Compensate if we're more than 2 ms off */
+                       s->adj -= (ms - delay);
+               }
+#if 0
+               fprintf(stdout, "Delay is %d, adjustment is %d, last was %d\n", delay, s->adj, ms);
+#endif
+               delay += s->adj;
+               if (delay < 1)
+                       delay = 1;
+       } else
+               gettimeofday(&s->last, NULL);
+       if (s->lasttimeout != delay) {
+               /* We'll install the next timeout now. */
+               s->owner->streamid = ast_sched_add(s->owner->sched,
+                               delay, ast_read_callback, s); 
+               s->lasttimeout = delay;
+       } else {
+               /* Just come back again at the same time */
+               retval = -1;
+       }
+       return retval;
+}
+
+static int gsm_apply(struct ast_channel *c, struct ast_filestream *s)
+{
+       /* Select our owner for this stream, and get the ball rolling. */
+       s->owner = c;
+       ast_read_callback(s);
+       return 0;
+}
+
+static int gsm_write(struct ast_filestream *fs, struct ast_frame *f)
+{
+       int res;
+       if (f->frametype != AST_FRAME_VOICE) {
+               ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
+               return -1;
+       }
+       if (f->subclass != AST_FORMAT_GSM) {
+               ast_log(LOG_WARNING, "Asked to write non-GSM frame (%d)!\n", f->subclass);
+               return -1;
+       }
+       if (f->datalen != 33) {
+               ast_log(LOG_WARNING, "Invalid data length, %d, should be 33\n", f->datalen);
+               return -1;
+       }
+       if ((res = write(fs->fd, f->data, f->datalen)) != f->datalen) {
+                       ast_log(LOG_WARNING, "Bad write (%d/33): %s\n", res, strerror(errno));
+                       return -1;
+       }
+       return 0;
+}
+
+static char *gsm_getcomment(struct ast_filestream *s)
+{
+       return NULL;
+}
+
+int load_module()
+{
+       return ast_format_register(name, exts, AST_FORMAT_GSM,
+                                                               gsm_open,
+                                                               gsm_rewrite,
+                                                               gsm_apply,
+                                                               gsm_write,
+                                                               gsm_read,
+                                                               gsm_close,
+                                                               gsm_getcomment);
+                                                               
+                                                               
+}
+
+int unload_module()
+{
+       struct ast_filestream *tmp, *tmpl;
+       if (pthread_mutex_lock(&gsm_lock)) {
+               ast_log(LOG_WARNING, "Unable to lock gsm list\n");
+               return -1;
+       }
+       tmp = glist;
+       while(tmp) {
+               if (tmp->owner)
+                       ast_softhangup(tmp->owner);
+               tmpl = tmp;
+               tmp = tmp->next;
+               free(tmpl);
+       }
+       pthread_mutex_unlock(&gsm_lock);
+       return ast_format_unregister(name);
+}      
+
+int usecount()
+{
+       int res;
+       if (pthread_mutex_lock(&gsm_lock)) {
+               ast_log(LOG_WARNING, "Unable to lock gsm list\n");
+               return -1;
+       }
+       res = glistcnt;
+       pthread_mutex_unlock(&gsm_lock);
+       return res;
+}
+
+char *description()
+{
+       return desc;
+}
+
index 811acbe..85abdbc 100755 (executable)
@@ -3,7 +3,7 @@
  *
  * Everybody's favorite format: MP3 Files!  Yay!
  * 
- * Copyright (C) 1999, Adtran Inc. and Linux Support Services, LLC
+ * Copyright (C) 1999, Mark Spencer
  *
  * Mark Spencer <markster@linux-support.net>
  *
@@ -26,8 +26,7 @@
 #include <sys/time.h>
 #include "../channels/adtranvofr.h"
 
-
-#define MP3_MAX_SIZE 1400
+#define MAX_FRAME_SIZE 1441
 
 struct ast_filestream {
        /* First entry MUST be reserved for the channel type */
@@ -36,9 +35,13 @@ struct ast_filestream {
        int fd; /* Descriptor */
        struct ast_channel *owner;
        struct ast_filestream *next;
-       struct ast_frame *fr;   /* Frame representation of buf */
-       char buf[sizeof(struct ast_frame) + MP3_MAX_SIZE + AST_FRIENDLY_OFFSET];        /* Buffer for sending frames, etc */
+       struct ast_frame fr;    /* Frame representation of buf */
+       char offset[AST_FRIENDLY_OFFSET];
+       unsigned char buf[MAX_FRAME_SIZE * 2];
+       int lasttimeout;
        int pos;
+       int adj;
+       struct timeval last;
 };
 
 
@@ -47,16 +50,10 @@ static pthread_mutex_t mp3_lock = PTHREAD_MUTEX_INITIALIZER;
 static int glistcnt = 0;
 
 static char *name = "mp3";
-static char *desc = "MPEG-2 Layer 3 File Format Support";
+static char *desc = "MPEG-1,2 Layer 3 File Format Support";
 static char *exts = "mp3|mpeg3";
 
-#if 0
-#define MP3_FRAMELEN 417
-#else
-#define MP3_FRAMELEN 400
-#endif
-#define MP3_OUTPUTLEN 2304     /* Bytes */
-#define MP3_TIMELEN ((MP3_OUTPUTLEN * 1000 / 16000) )
+#include "../codecs/mp3anal.h"
 
 static struct ast_filestream *mp3_open(int fd)
 {
@@ -74,13 +71,10 @@ static struct ast_filestream *mp3_open(int fd)
                glist = tmp;
                tmp->fd = fd;
                tmp->owner = NULL;
-               tmp->fr = (struct ast_frame *)tmp->buf;
-               tmp->fr->data = tmp->buf + sizeof(struct ast_frame);
-               tmp->fr->frametype = AST_FRAME_VOICE;
-               tmp->fr->subclass = AST_FORMAT_MP3;
-               /* datalen will vary for each frame */
-               tmp->fr->src = name;
-               tmp->fr->mallocd = 0;
+               tmp->lasttimeout = -1;
+               tmp->last.tv_usec = 0;
+               tmp->last.tv_sec = 0;
+               tmp->adj = 0;
                glistcnt++;
                pthread_mutex_unlock(&mp3_lock);
                ast_update_use_count();
@@ -104,7 +98,6 @@ static struct ast_filestream *mp3_rewrite(int fd, char *comment)
                glist = tmp;
                tmp->fd = fd;
                tmp->owner = NULL;
-               tmp->fr = NULL;
                glistcnt++;
                pthread_mutex_unlock(&mp3_lock);
                ast_update_use_count();
@@ -155,28 +148,67 @@ static void mp3_close(struct ast_filestream *s)
 static int ast_read_callback(void *data)
 {
        /* XXX Don't assume frames are this size XXX */
-       u_int16_t size=MP3_FRAMELEN;
        u_int32_t delay = -1;
        int res;
        struct ast_filestream *s = data;
-       /* Send a frame from the file to the appropriate channel */
-       /* Read the data into the buffer */
-       s->fr->offset = AST_FRIENDLY_OFFSET;
-       s->fr->datalen = size;
-       s->fr->data = s->buf + sizeof(struct ast_frame) + AST_FRIENDLY_OFFSET;
-       if ((res = read(s->fd, s->fr->data , size)) != size) {
-               ast_log(LOG_WARNING, "Short read (%d of %d bytes) (%s)!\n", res, size, strerror(errno));
+       int size;
+       int ms=0;
+       struct timeval tv;
+       if ((res = read(s->fd, s->buf , 4)) != 4) {
+               ast_log(LOG_WARNING, "Short read (%d of 4 bytes) (%s)!\n", res, strerror(errno));
                s->owner->streamid = -1;
                return 0;
        }
-       delay = MP3_TIMELEN;
-       s->fr->timelen = delay;
+       if (mp3_badheader(s->buf)) {
+               ast_log(LOG_WARNING, "Bad mp3 header\n");
+               return 0;
+       }
+       if ((size = mp3_framelen(s->buf)) < 0) {
+               ast_log(LOG_WARNING, "Unable to calculate frame size\n");
+               return 0;
+       }
+       if ((res = read(s->fd, s->buf + 4 , size - 4)) != size - 4) {
+               ast_log(LOG_WARNING, "Short read (%d of %d bytes) (%s)!\n", res, size - 4, strerror(errno));
+               s->owner->streamid = -1;
+               return 0;
+       }
+       /* Send a frame from the file to the appropriate channel */
+       /* Read the data into the buffer */
+       s->fr.offset = AST_FRIENDLY_OFFSET;
+       s->fr.frametype = AST_FRAME_VOICE;
+       s->fr.subclass = AST_FORMAT_MP3;
+       s->fr.mallocd = 0;
+       s->fr.src = name;
+       s->fr.datalen = size;
+       s->fr.data = s->buf;
+       delay = mp3_samples(s->buf) * 1000 / mp3_samplerate(s->buf);
+       if (s->last.tv_sec || s->last.tv_usec) {
+               /* To keep things running smoothly, we watch how close we're coming */
+               gettimeofday(&tv, NULL);
+               ms = ((tv.tv_usec - s->last.tv_usec) / 1000 + (tv.tv_sec - s->last.tv_sec) * 1000);
+               /* If we're within 2 milliseconds, that's close enough */
+               if ((ms - delay) * (ms - delay) > 4)
+                       s->adj -= (ms - delay);
+       }
+       s->fr.timelen = delay;
+#if 0
+       ast_log(LOG_DEBUG, "delay is %d, adjusting by %d, as last was %d\n", delay, s->adj, ms);
+#endif
+       delay += s->adj;
+       if (delay < 1)
+               delay = 1;
        /* Lastly, process the frame */
-       if (ast_write(s->owner, s->fr)) {
+       if (ast_write(s->owner, &s->fr)) {
                ast_log(LOG_WARNING, "Failed to write frame\n");
                s->owner->streamid = -1;
                return 0;
        }
+       gettimeofday(&s->last, NULL);
+       if (s->lasttimeout != delay) {
+               s->owner->streamid = ast_sched_add(s->owner->sched, delay, ast_read_callback, s);
+               s->lasttimeout = delay;
+               return 0;
+       }
        return -1;
 }
 
@@ -184,7 +216,6 @@ static int mp3_apply(struct ast_channel *c, struct ast_filestream *s)
 {
        /* Select our owner for this stream, and get the ball rolling. */
        s->owner = c;
-       s->owner->streamid = ast_sched_add(s->owner->sched, MP3_TIMELEN, ast_read_callback, s);
        ast_read_callback(s);
        return 0;
 }
@@ -192,10 +223,6 @@ static int mp3_apply(struct ast_channel *c, struct ast_filestream *s)
 static int mp3_write(struct ast_filestream *fs, struct ast_frame *f)
 {
        int res;
-       if (fs->fr) {
-               ast_log(LOG_WARNING, "Asked to write on a read stream??\n");
-               return -1;
-       }
        if (f->frametype != AST_FRAME_VOICE) {
                ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
                return -1;
@@ -211,7 +238,7 @@ static int mp3_write(struct ast_filestream *fs, struct ast_frame *f)
        return 0;
 }
 
-char *mp3_getcomment(struct ast_filestream *s)
+static char *mp3_getcomment(struct ast_filestream *s)
 {
        return NULL;
 }
index e3265d3..9ba4fdc 100755 (executable)
@@ -3,7 +3,7 @@
  *
  * Microsoft WAV File Format using libaudiofile 
  * 
- * Copyright (C) 1999, Adtran Inc. and Linux Support Services, LLC
+ * Copyright (C) 1999, Mark Spencer
  *
  * Mark Spencer <markster@linux-support.net>
  *
@@ -298,7 +298,7 @@ static int wav_write(struct ast_filestream *fs, struct ast_frame *f)
        return 0;
 }
 
-char *wav_getcomment(struct ast_filestream *s)
+static char *wav_getcomment(struct ast_filestream *s)
 {
        return NULL;
 }
diff --git a/formats/format_wav_gsm.c b/formats/format_wav_gsm.c
new file mode 100755 (executable)
index 0000000..b901a40
--- /dev/null
@@ -0,0 +1,586 @@
+/*
+ * Asterisk -- A telephony toolkit for Linux.
+ *
+ * Save GSM in the proprietary Microsoft format.
+ * 
+ * Copyright (C) 1999, Mark Spencer
+ *
+ * Mark Spencer <markster@linux-support.net>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License
+ */
+#include <asterisk/channel.h>
+#include <asterisk/file.h>
+#include <asterisk/logger.h>
+#include <asterisk/sched.h>
+#include <asterisk/module.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+#include <endian.h>
+#include "msgsm.h"
+
+/* Some Ideas for this code came from makewave.c by Jeffery Chilton */
+
+/* Portions of the conversion code are by guido@sienanet.it */
+
+struct ast_filestream {
+       void *reserved[AST_RESERVED_POINTERS];
+       /* Believe it or not, we must decode/recode to account for the
+          weird MS format */
+       /* This is what a filestream means to us */
+       int fd; /* Descriptor */
+       int bytes;
+       struct ast_channel *owner;
+       struct ast_frame fr;                            /* Frame information */
+       char waste[AST_FRIENDLY_OFFSET];        /* Buffer for sending frames, etc */
+       char empty;                                                     /* Empty character */
+       unsigned char gsm[66];                          /* Two Real GSM Frames */
+       int foffset;
+       int secondhalf;                                         /* Are we on the second half */
+       int lasttimeout;
+       struct timeval last;
+       int adj;
+       struct ast_filestream *next;
+};
+
+
+static struct ast_filestream *glist = NULL;
+static pthread_mutex_t wav_lock = PTHREAD_MUTEX_INITIALIZER;
+static int glistcnt = 0;
+
+static char *name = "wav49";
+static char *desc = "Microsoft WAV format (Proprietary GSM)";
+static char *exts = "WAV";
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define htoll(b) (b)
+#define htols(b) (b)
+#define ltohl(b) (b)
+#define ltohs(b) (b)
+#else
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define htoll(b)  \
+          (((((b)      ) & 0xFF) << 24) | \
+              ((((b) >>  8) & 0xFF) << 16) | \
+                  ((((b) >> 16) & 0xFF) <<  8) | \
+                  ((((b) >> 24) & 0xFF)      ))
+#define htols(b) \
+          (((((b)      ) & 0xFF) << 8) | \
+                  ((((b) >> 8) & 0xFF)      ))
+#define ltohl(b) htoll(b)
+#define ltohs(b) htols(b)
+#else
+#error "Endianess not defined"
+#endif
+#endif
+
+
+static int check_header(int fd)
+{
+       int type, size, formtype;
+       int fmt, hsize, fact;
+       short format, chans;
+       int freq;
+       int data;
+       if (read(fd, &type, 4) != 4) {
+               ast_log(LOG_WARNING, "Read failed (type)\n");
+               return -1;
+       }
+       if (read(fd, &size, 4) != 4) {
+               ast_log(LOG_WARNING, "Read failed (size)\n");
+               return -1;
+       }
+       size = ltohl(size);
+       if (read(fd, &formtype, 4) != 4) {
+               ast_log(LOG_WARNING, "Read failed (formtype)\n");
+               return -1;
+       }
+       if (memcmp(&type, "RIFF", 4)) {
+               ast_log(LOG_WARNING, "Does not begin with RIFF\n");
+               return -1;
+       }
+       if (memcmp(&formtype, "WAVE", 4)) {
+               ast_log(LOG_WARNING, "Does not contain WAVE\n");
+               return -1;
+       }
+       if (read(fd, &fmt, 4) != 4) {
+               ast_log(LOG_WARNING, "Read failed (fmt)\n");
+               return -1;
+       }
+       if (memcmp(&fmt, "fmt ", 4)) {
+               ast_log(LOG_WARNING, "Does not say fmt\n");
+               return -1;
+       }
+       if (read(fd, &hsize, 4) != 4) {
+               ast_log(LOG_WARNING, "Read failed (formtype)\n");
+               return -1;
+       }
+       if (ltohl(hsize) != 20) {
+               ast_log(LOG_WARNING, "Unexpected header size %d\n", ltohl(hsize));
+               return -1;
+       }
+       if (read(fd, &format, 2) != 2) {
+               ast_log(LOG_WARNING, "Read failed (format)\n");
+               return -1;
+       }
+       if (ltohs(format) != 49) {
+               ast_log(LOG_WARNING, "Not a GSM file %d\n", ltohs(format));
+               return -1;
+       }
+       if (read(fd, &chans, 2) != 2) {
+               ast_log(LOG_WARNING, "Read failed (format)\n");
+               return -1;
+       }
+       if (ltohs(chans) != 1) {
+               ast_log(LOG_WARNING, "Not in mono %d\n", ltohs(chans));
+               return -1;
+       }
+       if (read(fd, &freq, 4) != 4) {
+               ast_log(LOG_WARNING, "Read failed (freq)\n");
+               return -1;
+       }
+       if (ltohl(freq) != 8000) {
+               ast_log(LOG_WARNING, "Unexpected freqency %d\n", ltohl(freq));
+               return -1;
+       }
+       /* Ignore the byte frequency */
+       if (read(fd, &freq, 4) != 4) {
+               ast_log(LOG_WARNING, "Read failed (X_1)\n");
+               return -1;
+       }
+       /* Ignore the two weird fields */
+       if (read(fd, &freq, 4) != 4) {
+               ast_log(LOG_WARNING, "Read failed (X_2/X_3)\n");
+               return -1;
+       }
+       /* Ignore the byte frequency */
+       if (read(fd, &freq, 4) != 4) {
+               ast_log(LOG_WARNING, "Read failed (Y_1)\n");
+               return -1;
+       }
+       /* Check for the word fact */
+       if (read(fd, &fact, 4) != 4) {
+               ast_log(LOG_WARNING, "Read failed (fact)\n");
+               return -1;
+       }
+       if (memcmp(&fact, "fact", 4)) {
+               ast_log(LOG_WARNING, "Does not say fact\n");
+               return -1;
+       }
+       /* Ignore the "fact value" */
+       if (read(fd, &fact, 4) != 4) {
+               ast_log(LOG_WARNING, "Read failed (fact header)\n");
+               return -1;
+       }
+       if (read(fd, &fact, 4) != 4) {
+               ast_log(LOG_WARNING, "Read failed (fact value)\n");
+               return -1;
+       }
+       /* Check for the word data */
+       if (read(fd, &data, 4) != 4) {
+               ast_log(LOG_WARNING, "Read failed (data)\n");
+               return -1;
+       }
+       if (memcmp(&data, "data", 4)) {
+               ast_log(LOG_WARNING, "Does not say data\n");
+               return -1;
+       }
+       /* Ignore the data length */
+       if (read(fd, &data, 4) != 4) {
+               ast_log(LOG_WARNING, "Read failed (data)\n");
+               return -1;
+       }
+       return 0;
+}
+
+static int update_header(int fd, int bytes)
+{
+       int cur;
+       int datalen = htoll(bytes);
+       int filelen = htoll(52 + ((bytes + 1) & ~0x1));
+       cur = lseek(fd, 0, SEEK_CUR);
+       if (cur < 0) {
+               ast_log(LOG_WARNING, "Unable to find our position\n");
+               return -1;
+       }
+       if (lseek(fd, 4, SEEK_SET) != 4) {
+               ast_log(LOG_WARNING, "Unable to set our position\n");
+               return -1;
+       }
+       if (write(fd, &filelen, 4) != 4) {
+               ast_log(LOG_WARNING, "Unable to set write file size\n");
+               return -1;
+       }
+       if (lseek(fd, 56, SEEK_SET) != 56) {
+               ast_log(LOG_WARNING, "Unable to set our position\n");
+               return -1;
+       }
+       if (write(fd, &datalen, 4) != 4) {
+               ast_log(LOG_WARNING, "Unable to set write datalen\n");
+               return -1;
+       }
+       if (lseek(fd, cur, SEEK_SET) != cur) {
+               ast_log(LOG_WARNING, "Unable to return to position\n");
+               return -1;
+       }
+       return 0;
+}
+
+static int write_header(int fd)
+{
+       unsigned int hz=htoll(8000);
+       unsigned int bhz = htoll(1625);
+       unsigned int hs = htoll(20);
+       unsigned short fmt = htols(49);
+       unsigned short chans = htols(1);
+       unsigned int fhs = htoll(4);
+       unsigned int x_1 = htoll(65);
+       unsigned short x_2 = htols(2);
+       unsigned short x_3 = htols(320);
+       unsigned int y_1 = htoll(20160);
+       unsigned int size = htoll(0);
+       /* Write a GSM header, ignoring sizes which will be filled in later */
+       if (write(fd, "RIFF", 4) != 4) {
+               ast_log(LOG_WARNING, "Unable to write header\n");
+               return -1;
+       }
+       if (write(fd, &size, 4) != 4) {
+               ast_log(LOG_WARNING, "Unable to write header\n");
+               return -1;
+       }
+       if (write(fd, "WAVEfmt ", 8) != 8) {
+               ast_log(LOG_WARNING, "Unable to write header\n");
+               return -1;
+       }
+       if (write(fd, &hs, 4) != 4) {
+               ast_log(LOG_WARNING, "Unable to write header\n");
+               return -1;
+       }
+       if (write(fd, &fmt, 2) != 2) {
+               ast_log(LOG_WARNING, "Unable to write header\n");
+               return -1;
+       }
+       if (write(fd, &chans, 2) != 2) {
+               ast_log(LOG_WARNING, "Unable to write header\n");
+               return -1;
+       }
+       if (write(fd, &hz, 4) != 4) {
+               ast_log(LOG_WARNING, "Unable to write header\n");
+               return -1;
+       }
+       if (write(fd, &bhz, 4) != 4) {
+               ast_log(LOG_WARNING, "Unable to write header\n");
+               return -1;
+       }
+       if (write(fd, &x_1, 4) != 4) {
+               ast_log(LOG_WARNING, "Unable to write header\n");
+               return -1;
+       }
+       if (write(fd, &x_2, 2) != 2) {
+               ast_log(LOG_WARNING, "Unable to write header\n");
+               return -1;
+       }
+       if (write(fd, &x_3, 2) != 2) {
+               ast_log(LOG_WARNING, "Unable to write header\n");
+               return -1;
+       }
+       if (write(fd, "fact", 4) != 4) {
+               ast_log(LOG_WARNING, "Unable to write header\n");
+               return -1;
+       }
+       if (write(fd, &fhs, 4) != 4) {
+               ast_log(LOG_WARNING, "Unable to write header\n");
+               return -1;
+       }
+       if (write(fd, &y_1, 4) != 4) {
+               ast_log(LOG_WARNING, "Unable to write header\n");
+               return -1;
+       }
+       if (write(fd, "data", 4) != 4) {
+               ast_log(LOG_WARNING, "Unable to write header\n");
+               return -1;
+       }
+       if (write(fd, &size, 4) != 4) {
+               ast_log(LOG_WARNING, "Unable to write header\n");
+               return -1;
+       }
+       return 0;
+}
+
+static struct ast_filestream *wav_open(int fd)
+{
+       /* We don't have any header to read or anything really, but
+          if we did, it would go here.  We also might want to check
+          and be sure it's a valid file.  */
+       struct ast_filestream *tmp;
+       if ((tmp = malloc(sizeof(struct ast_filestream)))) {
+               memset(tmp, 0, sizeof(struct ast_filestream));
+               if (check_header(fd)) {
+                       free(tmp);
+                       return NULL;
+               }
+               if (pthread_mutex_lock(&wav_lock)) {
+                       ast_log(LOG_WARNING, "Unable to lock wav list\n");
+                       free(tmp);
+                       return NULL;
+               }
+               tmp->next = glist;
+               glist = tmp;
+               tmp->fd = fd;
+               tmp->owner = NULL;
+               tmp->fr.data = tmp->gsm;
+               tmp->fr.frametype = AST_FRAME_VOICE;
+               tmp->fr.subclass = AST_FORMAT_GSM;
+               /* datalen will vary for each frame */
+               tmp->fr.src = name;
+               tmp->fr.mallocd = 0;
+               tmp->secondhalf = 0;
+               tmp->lasttimeout = -1;
+               glistcnt++;
+               pthread_mutex_unlock(&wav_lock);
+               ast_update_use_count();
+       }
+       return tmp;
+}
+
+static struct ast_filestream *wav_rewrite(int fd, char *comment)
+{
+       /* We don't have any header to read or anything really, but
+          if we did, it would go here.  We also might want to check
+          and be sure it's a valid file.  */
+       struct ast_filestream *tmp;
+       if ((tmp = malloc(sizeof(struct ast_filestream)))) {
+               memset(tmp, 0, sizeof(struct ast_filestream));
+               if (write_header(fd)) {
+                       free(tmp);
+                       return NULL;
+               }
+               if (pthread_mutex_lock(&wav_lock)) {
+                       ast_log(LOG_WARNING, "Unable to lock wav list\n");
+                       free(tmp);
+                       return NULL;
+               }
+               tmp->next = glist;
+               glist = tmp;
+               tmp->fd = fd;
+               tmp->owner = NULL;
+               tmp->lasttimeout = -1;
+               glistcnt++;
+               pthread_mutex_unlock(&wav_lock);
+               ast_update_use_count();
+       } else
+               ast_log(LOG_WARNING, "Out of memory\n");
+       return tmp;
+}
+
+static struct ast_frame *wav_read(struct ast_filestream *s)
+{
+       return NULL;
+}
+
+static void wav_close(struct ast_filestream *s)
+{
+       struct ast_filestream *tmp, *tmpl = NULL;
+       char zero = 0;
+       if (pthread_mutex_lock(&wav_lock)) {
+               ast_log(LOG_WARNING, "Unable to lock wav list\n");
+               return;
+       }
+       tmp = glist;
+       while(tmp) {
+               if (tmp == s) {
+                       if (tmpl)
+                               tmpl->next = tmp->next;
+                       else
+                               glist = tmp->next;
+                       break;
+               }
+               tmpl = tmp;
+               tmp = tmp->next;
+       }
+       glistcnt--;
+       if (s->owner) {
+               s->owner->stream = NULL;
+               if (s->owner->streamid > -1)
+                       ast_sched_del(s->owner->sched, s->owner->streamid);
+               s->owner->streamid = -1;
+       }
+       pthread_mutex_unlock(&wav_lock);
+       ast_update_use_count();
+       if (!tmp) 
+               ast_log(LOG_WARNING, "Freeing a filestream we don't seem to own\n");
+       /* Pad to even length */
+       if (s->bytes & 0x1)
+               write(s->fd, &zero, 1);
+       close(s->fd);
+       free(s);
+}
+
+static int ast_read_callback(void *data)
+{
+       int retval = 0;
+       int res;
+       int delay = 20;
+       struct ast_filestream *s = data;
+       char msdata[66];
+       struct timeval tv;
+       /* Send a frame from the file to the appropriate channel */
+
+       s->fr.frametype = AST_FRAME_VOICE;
+       s->fr.subclass = AST_FORMAT_GSM;
+       s->fr.offset = AST_FRIENDLY_OFFSET;
+       s->fr.timelen = 20;
+       s->fr.datalen = 33;
+       s->fr.mallocd = 0;
+       if (s->secondhalf) {
+               /* Just return a frame based on the second GSM frame */
+               s->fr.data = s->gsm + 33;
+       } else {
+               if ((res = read(s->fd, msdata, 65)) != 65) {
+                       if (res && (res != 1))
+                               ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
+                       s->owner->streamid = -1;
+                       return 0;
+               }
+               /* Convert from MS format to two real GSM frames */
+               conv65(msdata, s->gsm);
+               s->fr.data = s->gsm;
+       }
+       s->secondhalf = !s->secondhalf;
+       /* Lastly, process the frame */
+       if (ast_write(s->owner, &s->fr)) {
+               ast_log(LOG_WARNING, "Failed to write frame\n");
+               s->owner->streamid = -1;
+               return 0;
+       }
+       if (s->last.tv_usec || s->last.tv_usec) {
+               int ms;
+               gettimeofday(&tv, NULL);
+               ms = 1000 * (tv.tv_sec - s->last.tv_sec) + 
+                       (tv.tv_usec - s->last.tv_usec) / 1000;
+               s->last.tv_sec = tv.tv_sec;
+               s->last.tv_usec = tv.tv_usec;
+               if ((ms - delay) * (ms - delay) > 4) {
+                       /* Compensate if we're more than 2 ms off */
+                       s->adj -= (ms - delay);
+               }
+#if 0
+               fprintf(stdout, "Delay is %d, adjustment is %d, last was %d\n", delay, s->adj, ms);
+#endif
+               delay += s->adj;
+               if (delay < 1)
+                       delay = 1;
+       } else
+               gettimeofday(&s->last, NULL);
+       if (s->lasttimeout != delay) {
+               /* We'll install the next timeout now. */
+               s->owner->streamid = ast_sched_add(s->owner->sched,
+                               delay, ast_read_callback, s); 
+               s->lasttimeout = delay;
+       } else {
+               /* Just come back again at the same time */
+               retval = -1;
+       }
+       return retval;
+}
+
+static int wav_apply(struct ast_channel *c, struct ast_filestream *s)
+{
+       /* Select our owner for this stream, and get the ball rolling. */
+       s->owner = c;
+       ast_read_callback(s);
+       return 0;
+}
+
+static int wav_write(struct ast_filestream *fs, struct ast_frame *f)
+{
+       int res;
+       char msdata[66];
+       if (f->frametype != AST_FRAME_VOICE) {
+               ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
+               return -1;
+       }
+       if (f->subclass != AST_FORMAT_GSM) {
+               ast_log(LOG_WARNING, "Asked to write non-GSM frame (%d)!\n", f->subclass);
+               return -1;
+       }
+       if (fs->secondhalf) {
+               memcpy(fs->gsm + 33, f->data, 33);
+               conv66(fs->gsm, msdata);
+               if ((res = write(fs->fd, msdata, 65)) != 65) {
+                       ast_log(LOG_WARNING, "Bad write (%d/65): %s\n", res, strerror(errno));
+                       return -1;
+               }
+               fs->bytes += 65;
+               update_header(fs->fd, fs->bytes);
+       } else {
+               /* Copy the data and do nothing */
+               memcpy(fs->gsm, f->data, 33);
+       }
+       fs->secondhalf = !fs->secondhalf;
+       return 0;
+}
+
+static char *wav_getcomment(struct ast_filestream *s)
+{
+       return NULL;
+}
+
+int load_module()
+{
+       return ast_format_register(name, exts, AST_FORMAT_GSM,
+                                                               wav_open,
+                                                               wav_rewrite,
+                                                               wav_apply,
+                                                               wav_write,
+                                                               wav_read,
+                                                               wav_close,
+                                                               wav_getcomment);
+                                                               
+                                                               
+}
+
+int unload_module()
+{
+       struct ast_filestream *tmp, *tmpl;
+       if (pthread_mutex_lock(&wav_lock)) {
+               ast_log(LOG_WARNING, "Unable to lock wav list\n");
+               return -1;
+       }
+       tmp = glist;
+       while(tmp) {
+               if (tmp->owner)
+                       ast_softhangup(tmp->owner);
+               tmpl = tmp;
+               tmp = tmp->next;
+               free(tmpl);
+       }
+       pthread_mutex_unlock(&wav_lock);
+       return ast_format_unregister(name);
+}      
+
+int usecount()
+{
+       int res;
+       if (pthread_mutex_lock(&wav_lock)) {
+               ast_log(LOG_WARNING, "Unable to lock wav list\n");
+               return -1;
+       }
+       res = glistcnt;
+       pthread_mutex_unlock(&wav_lock);
+       return res;
+}
+
+char *description()
+{
+       return desc;
+}
+
diff --git a/formats/msgsm.h b/formats/msgsm.h
new file mode 100755 (executable)
index 0000000..2513e72
--- /dev/null
@@ -0,0 +1,685 @@
+/* Conversion routines derived from code by guido@sienanet.it */
+
+#define GSM_MAGIC 0xD
+
+typedef unsigned char           gsm_byte;
+typedef unsigned char           wav_byte;
+typedef unsigned int                   uword;
+
+#define readGSM_33(c1) { \
+               gsm_byte *c = (c1); \
+        LARc[0]  = (*c++ & 0xF) << 2;           /* 1 */ \
+        LARc[0] |= (*c >> 6) & 0x3; \
+        LARc[1]  = *c++ & 0x3F; \
+        LARc[2]  = (*c >> 3) & 0x1F; \
+        LARc[3]  = (*c++ & 0x7) << 2; \
+        LARc[3] |= (*c >> 6) & 0x3; \
+        LARc[4]  = (*c >> 2) & 0xF; \
+        LARc[5]  = (*c++ & 0x3) << 2; \
+        LARc[5] |= (*c >> 6) & 0x3; \
+        LARc[6]  = (*c >> 3) & 0x7; \
+        LARc[7]  = *c++ & 0x7; \
+        Nc[0]  = (*c >> 1) & 0x7F; \
+        bc[0]  = (*c++ & 0x1) << 1; \
+        bc[0] |= (*c >> 7) & 0x1; \
+        Mc[0]  = (*c >> 5) & 0x3; \
+        xmaxc[0]  = (*c++ & 0x1F) << 1; \
+        xmaxc[0] |= (*c >> 7) & 0x1; \
+        xmc[0]  = (*c >> 4) & 0x7; \
+        xmc[1]  = (*c >> 1) & 0x7; \
+        xmc[2]  = (*c++ & 0x1) << 2; \
+        xmc[2] |= (*c >> 6) & 0x3; \
+        xmc[3]  = (*c >> 3) & 0x7; \
+        xmc[4]  = *c++ & 0x7; \
+        xmc[5]  = (*c >> 5) & 0x7; \
+        xmc[6]  = (*c >> 2) & 0x7; \
+        xmc[7]  = (*c++ & 0x3) << 1;            /* 10 */ \
+        xmc[7] |= (*c >> 7) & 0x1; \
+        xmc[8]  = (*c >> 4) & 0x7; \
+        xmc[9]  = (*c >> 1) & 0x7; \
+        xmc[10]  = (*c++ & 0x1) << 2; \
+        xmc[10] |= (*c >> 6) & 0x3; \
+        xmc[11]  = (*c >> 3) & 0x7; \
+        xmc[12]  = *c++ & 0x7; \
+        Nc[1]  = (*c >> 1) & 0x7F; \
+        bc[1]  = (*c++ & 0x1) << 1; \
+        bc[1] |= (*c >> 7) & 0x1; \
+        Mc[1]  = (*c >> 5) & 0x3; \
+        xmaxc[1]  = (*c++ & 0x1F) << 1; \
+        xmaxc[1] |= (*c >> 7) & 0x1; \
+        xmc[13]  = (*c >> 4) & 0x7; \
+        xmc[14]  = (*c >> 1) & 0x7; \
+        xmc[15]  = (*c++ & 0x1) << 2; \
+        xmc[15] |= (*c >> 6) & 0x3; \
+        xmc[16]  = (*c >> 3) & 0x7; \
+        xmc[17]  = *c++ & 0x7; \
+        xmc[18]  = (*c >> 5) & 0x7; \
+        xmc[19]  = (*c >> 2) & 0x7; \
+        xmc[20]  = (*c++ & 0x3) << 1; \
+        xmc[20] |= (*c >> 7) & 0x1; \
+        xmc[21]  = (*c >> 4) & 0x7; \
+        xmc[22]  = (*c >> 1) & 0x7; \
+        xmc[23]  = (*c++ & 0x1) << 2; \
+        xmc[23] |= (*c >> 6) & 0x3; \
+        xmc[24]  = (*c >> 3) & 0x7; \
+        xmc[25]  = *c++ & 0x7; \
+        Nc[2]  = (*c >> 1) & 0x7F; \
+        bc[2]  = (*c++ & 0x1) << 1;             /* 20 */ \
+        bc[2] |= (*c >> 7) & 0x1; \
+        Mc[2]  = (*c >> 5) & 0x3; \
+        xmaxc[2]  = (*c++ & 0x1F) << 1; \
+        xmaxc[2] |= (*c >> 7) & 0x1; \
+        xmc[26]  = (*c >> 4) & 0x7; \
+        xmc[27]  = (*c >> 1) & 0x7; \
+        xmc[28]  = (*c++ & 0x1) << 2; \
+        xmc[28] |= (*c >> 6) & 0x3; \
+        xmc[29]  = (*c >> 3) & 0x7; \
+        xmc[30]  = *c++ & 0x7; \
+        xmc[31]  = (*c >> 5) & 0x7; \
+        xmc[32]  = (*c >> 2) & 0x7; \
+        xmc[33]  = (*c++ & 0x3) << 1; \
+        xmc[33] |= (*c >> 7) & 0x1; \
+        xmc[34]  = (*c >> 4) & 0x7; \
+        xmc[35]  = (*c >> 1) & 0x7; \
+        xmc[36]  = (*c++ & 0x1) << 2; \
+        xmc[36] |= (*c >> 6) & 0x3; \
+        xmc[37]  = (*c >> 3) & 0x7; \
+        xmc[38]  = *c++ & 0x7; \
+        Nc[3]  = (*c >> 1) & 0x7F; \
+        bc[3]  = (*c++ & 0x1) << 1; \
+        bc[3] |= (*c >> 7) & 0x1; \
+        Mc[3]  = (*c >> 5) & 0x3; \
+        xmaxc[3]  = (*c++ & 0x1F) << 1; \
+        xmaxc[3] |= (*c >> 7) & 0x1; \
+        xmc[39]  = (*c >> 4) & 0x7; \
+        xmc[40]  = (*c >> 1) & 0x7; \
+        xmc[41]  = (*c++ & 0x1) << 2; \
+        xmc[41] |= (*c >> 6) & 0x3; \
+        xmc[42]  = (*c >> 3) & 0x7; \
+        xmc[43]  = *c++ & 0x7;                  /* 30  */ \
+        xmc[44]  = (*c >> 5) & 0x7; \
+        xmc[45]  = (*c >> 2) & 0x7; \
+        xmc[46]  = (*c++ & 0x3) << 1; \
+        xmc[46] |= (*c >> 7) & 0x1; \
+        xmc[47]  = (*c >> 4) & 0x7; \
+        xmc[48]  = (*c >> 1) & 0x7; \
+        xmc[49]  = (*c++ & 0x1) << 2; \
+        xmc[49] |= (*c >> 6) & 0x3; \
+        xmc[50]  = (*c >> 3) & 0x7; \
+        xmc[51]  = *c & 0x7;                    /* 33 */ \
+}
+
+static void conv66(gsm_byte * d, wav_byte * c) {
+       gsm_byte frame_chain;
+    unsigned int sr;
+       unsigned int    LARc[8], Nc[4], Mc[4], bc[4], xmaxc[4], xmc[13*4];
+       
+       readGSM_33(d);
+       sr = 0;
+       sr = (sr >> 6) | (LARc[0] << 10);
+       sr = (sr >> 6) | (LARc[1] << 10);
+       *c++ = sr >> 4;
+       sr = (sr >> 5) | (LARc[2] << 11);
+       *c++ = sr >> 7;
+       sr = (sr >> 5) | (LARc[3] << 11);
+       sr = (sr >> 4) | (LARc[4] << 12);
+       *c++ = sr >> 6;
+       sr = (sr >> 4) | (LARc[5] << 12);
+       sr = (sr >> 3) | (LARc[6] << 13);
+       *c++ = sr >> 7;
+       sr = (sr >> 3) | (LARc[7] << 13);
+       sr = (sr >> 7) | (Nc[0] << 9);
+       *c++ = sr >> 5;
+       sr = (sr >> 2) | (bc[0] << 14);
+       sr = (sr >> 2) | (Mc[0] << 14);
+       sr = (sr >> 6) | (xmaxc[0] << 10);
+       *c++ = sr >> 3;
+       sr = (sr >> 3 )|( xmc[0] << 13);
+       *c++ = sr >> 8;
+       sr = (sr >> 3 )|( xmc[1] << 13);
+       sr = (sr >> 3 )|( xmc[2] << 13);
+    sr = (sr >> 3 )|( xmc[3] << 13);
+    *c++ = sr >> 7;
+    sr = (sr >> 3 )|( xmc[4] << 13);
+    sr = (sr >> 3 )|( xmc[5] << 13);
+    sr = (sr >> 3 )|( xmc[6] << 13);
+    *c++ = sr >> 6;
+    sr = (sr >> 3 )|( xmc[7] << 13);
+    sr = (sr >> 3 )|( xmc[8] << 13);
+    *c++ = sr >> 8;
+    sr = (sr >> 3 )|( xmc[9] << 13);
+    sr = (sr >> 3 )|( xmc[10] << 13);
+    sr = (sr >> 3 )|( xmc[11] << 13);
+    *c++ = sr >> 7;
+    sr = (sr >> 3 )|( xmc[12] << 13);
+    sr = (sr >> 7 )|( Nc[1] << 9);
+    *c++ = sr >> 5;
+    sr = (sr >> 2 )|( bc[1] << 14);
+    sr = (sr >> 2 )|( Mc[1] << 14);
+    sr = (sr >> 6 )|( xmaxc[1] << 10);
+    *c++ = sr >> 3;
+    sr = (sr >> 3 )|( xmc[13] << 13);
+    *c++ = sr >> 8;
+    sr = (sr >> 3 )|( xmc[14] << 13);
+    sr = (sr >> 3 )|( xmc[15] << 13);
+    sr = (sr >> 3 )|( xmc[16] << 13);
+    *c++ = sr >> 7;
+    sr = (sr >> 3 )|( xmc[17] << 13);
+    sr = (sr >> 3 )|( xmc[18] << 13);
+    sr = (sr >> 3 )|( xmc[19] << 13);
+    *c++ = sr >> 6;
+    sr = (sr >> 3 )|( xmc[20] << 13);
+    sr = (sr >> 3 )|( xmc[21] << 13);
+    *c++ = sr >> 8;
+    sr = (sr >> 3 )|( xmc[22] << 13);
+    sr = (sr >> 3 )|( xmc[23] << 13);
+    sr = (sr >> 3 )|( xmc[24] << 13);
+    *c++ = sr >> 7;
+    sr = (sr >> 3 )|( xmc[25] << 13);
+    sr = (sr >> 7 )|( Nc[2] << 9);
+    *c++ = sr >> 5;
+    sr = (sr >> 2 )|( bc[2] << 14);
+    sr = (sr >> 2 )|( Mc[2] << 14);
+    sr = (sr >> 6 )|( xmaxc[2] << 10);
+    *c++ = sr >> 3;
+    sr = (sr >> 3 )|( xmc[26] << 13);
+    *c++ = sr >> 8;
+    sr = (sr >> 3 )|( xmc[27] << 13);
+    sr = (sr >> 3 )|( xmc[28] << 13);
+    sr = (sr >> 3 )|( xmc[29] << 13);
+    *c++ = sr >> 7;
+    sr = (sr >> 3 )|( xmc[30] << 13);
+    sr = (sr >> 3 )|( xmc[31] << 13);
+    sr = (sr >> 3 )|( xmc[32] << 13);
+    *c++ = sr >> 6;
+    sr = (sr >> 3 )|( xmc[33] << 13);
+    sr = (sr >> 3 )|( xmc[34] << 13);
+    *c++ = sr >> 8;
+    sr = (sr >> 3 )|( xmc[35] << 13);
+    sr = (sr >> 3 )|( xmc[36] << 13);
+    sr = (sr >> 3 )|( xmc[37] << 13);
+    *c++ = sr >> 7;
+    sr = (sr >> 3 )|( xmc[38] << 13);
+    sr = (sr >> 7 )|( Nc[3] << 9);
+    *c++ = sr >> 5;
+    sr = (sr >> 2 )|( bc[3] << 14);
+    sr = (sr >> 2 )|( Mc[3] << 14);
+    sr = (sr >> 6 )|( xmaxc[3] << 10);
+    *c++ = sr >> 3;
+    sr = (sr >> 3 )|( xmc[39] << 13);
+    *c++ = sr >> 8;
+    sr = (sr >> 3 )|( xmc[40] << 13);
+    sr = (sr >> 3 )|( xmc[41] << 13);
+    sr = (sr >> 3 )|( xmc[42] << 13);
+    *c++ = sr >> 7;
+    sr = (sr >> 3 )|( xmc[43] << 13);
+    sr = (sr >> 3 )|( xmc[44] << 13);
+    sr = (sr >> 3 )|( xmc[45] << 13);
+    *c++ = sr >> 6;
+    sr = (sr >> 3 )|( xmc[46] << 13);
+    sr = (sr >> 3 )|( xmc[47] << 13);
+    *c++ = sr >> 8;
+    sr = (sr >> 3 )|( xmc[48] << 13);
+    sr = (sr >> 3 )|( xmc[49] << 13);
+    sr = (sr >> 3 )|( xmc[50] << 13);
+    *c++ = sr >> 7;
+    sr = (sr >> 3 )|( xmc[51] << 13);
+    sr = sr >> 4;
+    *c = sr >> 8;
+    frame_chain = *c;
+    readGSM_33(d+33);// puts all the parameters into LARc etc.
+
+
+    sr = 0;
+//                      sr = (sr >> 4 )|( s->frame_chain << 12);
+    sr = (sr >> 4 )|( frame_chain << 12);
+
+    sr = (sr >> 6 )|( LARc[0] << 10);
+    *c++ = sr >> 6;
+    sr = (sr >> 6 )|( LARc[1] << 10);
+    *c++ = sr >> 8;
+    sr = (sr >> 5 )|( LARc[2] << 11);
+    sr = (sr >> 5 )|( LARc[3] << 11);
+    *c++ = sr >> 6;
+    sr = (sr >> 4 )|( LARc[4] << 12);
+    sr = (sr >> 4 )|( LARc[5] << 12);
+    *c++ = sr >> 6;
+    sr = (sr >> 3 )|( LARc[6] << 13);
+    sr = (sr >> 3 )|( LARc[7] << 13);
+    *c++ = sr >> 8;
+    sr = (sr >> 7 )|( Nc[0] << 9);
+    sr = (sr >> 2 )|( bc[0] << 14);
+    *c++ = sr >> 7;
+    sr = (sr >> 2 )|( Mc[0] << 14);
+    sr = (sr >> 6 )|( xmaxc[0] << 10);
+    *c++ = sr >> 7;
+    sr = (sr >> 3 )|( xmc[0] << 13);
+    sr = (sr >> 3 )|( xmc[1] << 13);
+    sr = (sr >> 3 )|( xmc[2] << 13);
+    *c++ = sr >> 6;
+    sr = (sr >> 3 )|( xmc[3] << 13);
+    sr = (sr >> 3 )|( xmc[4] << 13);
+    *c++ = sr >> 8;
+    sr = (sr >> 3 )|( xmc[5] << 13);
+    sr = (sr >> 3 )|( xmc[6] << 13);
+    sr = (sr >> 3 )|( xmc[7] << 13);
+    *c++ = sr >> 7;
+    sr = (sr >> 3 )|( xmc[8] << 13);
+    sr = (sr >> 3 )|( xmc[9] << 13);
+    sr = (sr >> 3 )|( xmc[10] << 13);
+    *c++ = sr >> 6;
+    sr = (sr >> 3 )|( xmc[11] << 13);
+    sr = (sr >> 3 )|( xmc[12] << 13);
+    *c++ = sr >> 8;
+    sr = (sr >> 7 )|( Nc[1] << 9);
+    sr = (sr >> 2 )|( bc[1] << 14);
+    *c++ = sr >> 7;
+    sr = (sr >> 2 )|( Mc[1] << 14);
+    sr = (sr >> 6 )|( xmaxc[1] << 10);
+    *c++ = sr >> 7;
+    sr = (sr >> 3 )|( xmc[13] << 13);
+    sr = (sr >> 3 )|( xmc[14] << 13);
+    sr = (sr >> 3 )|( xmc[15] << 13);
+    *c++ = sr >> 6;
+    sr = (sr >> 3 )|( xmc[16] << 13);
+    sr = (sr >> 3 )|( xmc[17] << 13);
+    *c++ = sr >> 8;
+    sr = (sr >> 3 )|( xmc[18] << 13);
+    sr = (sr >> 3 )|( xmc[19] << 13);
+    sr = (sr >> 3 )|( xmc[20] << 13);
+    *c++ = sr >> 7;
+    sr = (sr >> 3 )|( xmc[21] << 13);
+    sr = (sr >> 3 )|( xmc[22] << 13);
+    sr = (sr >> 3 )|( xmc[23] << 13);
+    *c++ = sr >> 6;
+    sr = (sr >> 3 )|( xmc[24] << 13);
+    sr = (sr >> 3 )|( xmc[25] << 13);
+    *c++ = sr >> 8;
+    sr = (sr >> 7 )|( Nc[2] << 9);
+    sr = (sr >> 2 )|( bc[2] << 14);
+    *c++ = sr >> 7;
+    sr = (sr >> 2 )|( Mc[2] << 14);
+    sr = (sr >> 6 )|( xmaxc[2] << 10);
+    *c++ = sr >> 7;
+    sr = (sr >> 3 )|( xmc[26] << 13);
+    sr = (sr >> 3 )|( xmc[27] << 13);
+    sr = (sr >> 3 )|( xmc[28] << 13);
+    *c++ = sr >> 6;
+    sr = (sr >> 3 )|( xmc[29] << 13);
+    sr = (sr >> 3 )|( xmc[30] << 13);
+    *c++ = sr >> 8;
+    sr = (sr >> 3 )|( xmc[31] << 13);
+    sr = (sr >> 3 )|( xmc[32] << 13);
+    sr = (sr >> 3 )|( xmc[33] << 13);
+    *c++ = sr >> 7;
+    sr = (sr >> 3 )|( xmc[34] << 13);
+    sr = (sr >> 3 )|( xmc[35] << 13);
+    sr = (sr >> 3 )|( xmc[36] << 13);
+    *c++ = sr >> 6;
+    sr = (sr >> 3 )|( xmc[37] << 13);
+    sr = (sr >> 3 )|( xmc[38] << 13);
+    *c++ = sr >> 8;
+    sr = (sr >> 7 )|( Nc[3] << 9);
+    sr = (sr >> 2 )|( bc[3] << 14);
+    *c++ = sr >> 7;
+    sr = (sr >> 2 )|( Mc[3] << 14);
+    sr = (sr >> 6 )|( xmaxc[3] << 10);
+    *c++ = sr >> 7;
+    sr = (sr >> 3 )|( xmc[39] << 13);
+    sr = (sr >> 3 )|( xmc[40] << 13);
+    sr = (sr >> 3 )|( xmc[41] << 13);
+    *c++ = sr >> 6;
+    sr = (sr >> 3 )|( xmc[42] << 13);
+    sr = (sr >> 3 )|( xmc[43] << 13);
+    *c++ = sr >> 8;
+    sr = (sr >> 3 )|( xmc[44] << 13);
+    sr = (sr >> 3 )|( xmc[45] << 13);
+    sr = (sr >> 3 )|( xmc[46] << 13);
+    *c++ = sr >> 7;
+    sr = (sr >> 3 )|( xmc[47] << 13);
+    sr = (sr >> 3 )|( xmc[48] << 13);
+    sr = (sr >> 3 )|( xmc[49] << 13);
+    *c++ = sr >> 6;
+    sr = (sr >> 3 )|( xmc[50] << 13);
+    sr = (sr >> 3 )|( xmc[51] << 13);
+    *c++ = sr >> 8;
+
+}
+
+#define writeGSM_33(c1) { \
+                               gsm_byte *c = (c1); \
+                *c++ =   ((GSM_MAGIC & 0xF) << 4)               /* 1 */ \
+                           | ((LARc[0] >> 2) & 0xF); \
+                *c++ =   ((LARc[0] & 0x3) << 6) \
+                           | (LARc[1] & 0x3F); \
+                *c++ =   ((LARc[2] & 0x1F) << 3) \
+                           | ((LARc[3] >> 2) & 0x7); \
+                *c++ =   ((LARc[3] & 0x3) << 6) \
+                       | ((LARc[4] & 0xF) << 2) \
+                       | ((LARc[5] >> 2) & 0x3); \
+                *c++ =   ((LARc[5] & 0x3) << 6) \
+                       | ((LARc[6] & 0x7) << 3) \
+                       | (LARc[7] & 0x7);   \
+                *c++ =   ((Nc[0] & 0x7F) << 1) \
+                       | ((bc[0] >> 1) & 0x1); \
+                *c++ =   ((bc[0] & 0x1) << 7) \
+                       | ((Mc[0] & 0x3) << 5) \
+                       | ((xmaxc[0] >> 1) & 0x1F); \
+                *c++ =   ((xmaxc[0] & 0x1) << 7) \
+                       | ((xmc[0] & 0x7) << 4) \
+                       | ((xmc[1] & 0x7) << 1) \
+                           | ((xmc[2] >> 2) & 0x1); \
+                *c++ =   ((xmc[2] & 0x3) << 6) \
+                       | ((xmc[3] & 0x7) << 3) \
+                       | (xmc[4] & 0x7); \
+                *c++ =   ((xmc[5] & 0x7) << 5)                  /* 10 */ \
+                       | ((xmc[6] & 0x7) << 2) \
+                       | ((xmc[7] >> 1) & 0x3); \
+                *c++ =   ((xmc[7] & 0x1) << 7) \
+                       | ((xmc[8] & 0x7) << 4) \
+                       | ((xmc[9] & 0x7) << 1) \
+                       | ((xmc[10] >> 2) & 0x1); \
+                *c++ =   ((xmc[10] & 0x3) << 6) \
+                       | ((xmc[11] & 0x7) << 3) \
+                       | (xmc[12] & 0x7); \
+                *c++ =   ((Nc[1] & 0x7F) << 1) \
+                       | ((bc[1] >> 1) & 0x1); \
+                *c++ =   ((bc[1] & 0x1) << 7) \
+                       | ((Mc[1] & 0x3) << 5) \
+                       | ((xmaxc[1] >> 1) & 0x1F);  \
+                *c++ =   ((xmaxc[1] & 0x1) << 7) \
+                       | ((xmc[13] & 0x7) << 4) \
+                           | ((xmc[14] & 0x7) << 1) \
+                       | ((xmc[15] >> 2) & 0x1); \
+                *c++ =   ((xmc[15] & 0x3) << 6) \
+                       | ((xmc[16] & 0x7) << 3) \
+                       | (xmc[17] & 0x7); \
+                *c++ =   ((xmc[18] & 0x7) << 5) \
+                       | ((xmc[19] & 0x7) << 2) \
+                       | ((xmc[20] >> 1) & 0x3); \
+                *c++ =   ((xmc[20] & 0x1) << 7) \
+                       | ((xmc[21] & 0x7) << 4) \
+                       | ((xmc[22] & 0x7) << 1) \
+                           | ((xmc[23] >> 2) & 0x1); \
+                *c++ =   ((xmc[23] & 0x3) << 6) \
+                       | ((xmc[24] & 0x7) << 3) \
+                           | (xmc[25] & 0x7); \
+                *c++ =   ((Nc[2] & 0x7F) << 1)                  /* 20 */ \
+                       | ((bc[2] >> 1) & 0x1); \
+                *c++ =   ((bc[2] & 0x1) << 7) \
+                       | ((Mc[2] & 0x3) << 5) \
+                       | ((xmaxc[2] >> 1) & 0x1F); \
+                *c++ =   ((xmaxc[2] & 0x1) << 7)   \
+                       | ((xmc[26] & 0x7) << 4) \
+                       | ((xmc[27] & 0x7) << 1) \
+                       | ((xmc[28] >> 2) & 0x1); \
+                *c++ =   ((xmc[28] & 0x3) << 6) \
+                       | ((xmc[29] & 0x7) << 3) \
+                       | (xmc[30] & 0x7); \
+                *c++ =   ((xmc[31] & 0x7) << 5) \
+                       | ((xmc[32] & 0x7) << 2) \
+                       | ((xmc[33] >> 1) & 0x3); \
+                *c++ =   ((xmc[33] & 0x1) << 7) \
+                       | ((xmc[34] & 0x7) << 4) \
+                       | ((xmc[35] & 0x7) << 1) \
+                       | ((xmc[36] >> 2) & 0x1); \
+                *c++ =   ((xmc[36] & 0x3) << 6) \
+                           | ((xmc[37] & 0x7) << 3) \
+                       | (xmc[38] & 0x7); \
+                *c++ =   ((Nc[3] & 0x7F) << 1) \
+                       | ((bc[3] >> 1) & 0x1); \
+                *c++ =   ((bc[3] & 0x1) << 7)  \
+                       | ((Mc[3] & 0x3) << 5) \
+                       | ((xmaxc[3] >> 1) & 0x1F); \
+                *c++ =   ((xmaxc[3] & 0x1) << 7) \
+                       | ((xmc[39] & 0x7) << 4) \
+                       | ((xmc[40] & 0x7) << 1) \
+                       | ((xmc[41] >> 2) & 0x1); \
+                *c++ =   ((xmc[41] & 0x3) << 6)                 /* 30 */ \
+                       | ((xmc[42] & 0x7) << 3) \
+                       | (xmc[43] & 0x7); \
+                *c++ =   ((xmc[44] & 0x7) << 5) \
+                       | ((xmc[45] & 0x7) << 2) \
+                       | ((xmc[46] >> 1) & 0x3); \
+                *c++ =   ((xmc[46] & 0x1) << 7) \
+                       | ((xmc[47] & 0x7) << 4) \
+                       | ((xmc[48] & 0x7) << 1) \
+                       | ((xmc[49] >> 2) & 0x1); \
+                *c++ =   ((xmc[49] & 0x3) << 6) \
+                       | ((xmc[50] & 0x7) << 3) \
+                           | (xmc[51] & 0x7); \
+}
+
+static void conv65( wav_byte * c, gsm_byte * d){
+
+                unsigned int sr = 0;
+                unsigned int frame_chain;
+                               unsigned int    LARc[8], Nc[4], Mc[4], bc[4], xmaxc[4], xmc[13*4];
+                        sr = *c++;
+                        LARc[0] = sr & 0x3f;  sr >>= 6;
+                        sr |= (uword)*c++ << 2;
+                        LARc[1] = sr & 0x3f;  sr >>= 6;
+                        sr |= (uword)*c++ << 4;
+                        LARc[2] = sr & 0x1f;  sr >>= 5;
+                        LARc[3] = sr & 0x1f;  sr >>= 5;
+                        sr |= (uword)*c++ << 2;
+                        LARc[4] = sr & 0xf;  sr >>= 4;
+                        LARc[5] = sr & 0xf;  sr >>= 4;
+                        sr |= (uword)*c++ << 2;                 /* 5 */
+                        LARc[6] = sr & 0x7;  sr >>= 3;
+                        LARc[7] = sr & 0x7;  sr >>= 3;
+                        sr |= (uword)*c++ << 4;
+                        Nc[0] = sr & 0x7f;  sr >>= 7;
+                        bc[0] = sr & 0x3;  sr >>= 2;
+                        Mc[0] = sr & 0x3;  sr >>= 2;
+                        sr |= (uword)*c++ << 1;
+                        xmaxc[0] = sr & 0x3f;  sr >>= 6;
+                        xmc[0] = sr & 0x7;  sr >>= 3;
+                        sr = *c++;
+                        xmc[1] = sr & 0x7;  sr >>= 3;
+                        xmc[2] = sr & 0x7;  sr >>= 3;
+                        sr |= (uword)*c++ << 2;
+                        xmc[3] = sr & 0x7;  sr >>= 3;
+                        xmc[4] = sr & 0x7;  sr >>= 3;
+                        xmc[5] = sr & 0x7;  sr >>= 3;
+                        sr |= (uword)*c++ << 1;                 /* 10 */
+                        xmc[6] = sr & 0x7;  sr >>= 3;
+                        xmc[7] = sr & 0x7;  sr >>= 3;
+                        xmc[8] = sr & 0x7;  sr >>= 3;
+                        sr = *c++;
+                        xmc[9] = sr & 0x7;  sr >>= 3;
+                        xmc[10] = sr & 0x7;  sr >>= 3;
+                        sr |= (uword)*c++ << 2;
+                        xmc[11] = sr & 0x7;  sr >>= 3;
+                        xmc[12] = sr & 0x7;  sr >>= 3;
+                        sr |= (uword)*c++ << 4;
+                        Nc[1] = sr & 0x7f;  sr >>= 7;
+                        bc[1] = sr & 0x3;  sr >>= 2;
+                        Mc[1] = sr & 0x3;  sr >>= 2;
+                        sr |= (uword)*c++ << 1;
+                        xmaxc[1] = sr & 0x3f;  sr >>= 6;
+                        xmc[13] = sr & 0x7;  sr >>= 3;
+                        sr = *c++;                              /* 15 */
+                        xmc[14] = sr & 0x7;  sr >>= 3;
+                        xmc[15] = sr & 0x7;  sr >>= 3;
+                        sr |= (uword)*c++ << 2;
+                        xmc[16] = sr & 0x7;  sr >>= 3;
+                        xmc[17] = sr & 0x7;  sr >>= 3;
+                        xmc[18] = sr & 0x7;  sr >>= 3;
+                        sr |= (uword)*c++ << 1;
+                        xmc[19] = sr & 0x7;  sr >>= 3;
+                        xmc[20] = sr & 0x7;  sr >>= 3;
+                        xmc[21] = sr & 0x7;  sr >>= 3;
+                        sr = *c++;
+                        xmc[22] = sr & 0x7;  sr >>= 3;
+                        xmc[23] = sr & 0x7;  sr >>= 3;
+                        sr |= (uword)*c++ << 2;
+                        xmc[24] = sr & 0x7;  sr >>= 3;
+                        xmc[25] = sr & 0x7;  sr >>= 3;
+                        sr |= (uword)*c++ << 4;                 /* 20 */
+                        Nc[2] = sr & 0x7f;  sr >>= 7;
+                        bc[2] = sr & 0x3;  sr >>= 2;
+                        Mc[2] = sr & 0x3;  sr >>= 2;
+                        sr |= (uword)*c++ << 1;
+                        xmaxc[2] = sr & 0x3f;  sr >>= 6;
+                        xmc[26] = sr & 0x7;  sr >>= 3;
+                        sr = *c++;
+                        xmc[27] = sr & 0x7;  sr >>= 3;
+                        xmc[28] = sr & 0x7;  sr >>= 3;
+                        sr |= (uword)*c++ << 2;
+                        xmc[29] = sr & 0x7;  sr >>= 3;
+                        xmc[30] = sr & 0x7;  sr >>= 3;
+                        xmc[31] = sr & 0x7;  sr >>= 3;
+                        sr |= (uword)*c++ << 1;
+                        xmc[32] = sr & 0x7;  sr >>= 3;
+                        xmc[33] = sr & 0x7;  sr >>= 3;
+                        xmc[34] = sr & 0x7;  sr >>= 3;
+                        sr = *c++;                              /* 25 */
+                        xmc[35] = sr & 0x7;  sr >>= 3;
+                        xmc[36] = sr & 0x7;  sr >>= 3;
+                        sr |= (uword)*c++ << 2;
+                        xmc[37] = sr & 0x7;  sr >>= 3;
+                        xmc[38] = sr & 0x7;  sr >>= 3;
+                        sr |= (uword)*c++ << 4;
+                        Nc[3] = sr & 0x7f;  sr >>= 7;
+                        bc[3] = sr & 0x3;  sr >>= 2;
+                        Mc[3] = sr & 0x3;  sr >>= 2;
+                        sr |= (uword)*c++ << 1;
+                        xmaxc[3] = sr & 0x3f;  sr >>= 6;
+                        xmc[39] = sr & 0x7;  sr >>= 3;
+                        sr = *c++;
+                        xmc[40] = sr & 0x7;  sr >>= 3;
+                        xmc[41] = sr & 0x7;  sr >>= 3;
+                        sr |= (uword)*c++ << 2;                 /* 30 */
+                        xmc[42] = sr & 0x7;  sr >>= 3;
+                        xmc[43] = sr & 0x7;  sr >>= 3;
+                        xmc[44] = sr & 0x7;  sr >>= 3;
+                        sr |= (uword)*c++ << 1;
+                        xmc[45] = sr & 0x7;  sr >>= 3;
+                        xmc[46] = sr & 0x7;  sr >>= 3;
+                        xmc[47] = sr & 0x7;  sr >>= 3;
+                        sr = *c++;
+                        xmc[49] = sr & 0x7;  sr >>= 3;
+                        sr |= (uword)*c++ << 2;
+                        xmc[50] = sr & 0x7;  sr >>= 3;
+                        xmc[51] = sr & 0x7;  sr >>= 3;
+
+                        frame_chain = sr & 0xf;
+
+
+                        writeGSM_33(d);// LARc etc. -> array of 33 GSM bytes
+
+
+                        sr = frame_chain;
+                        sr |= (uword)*c++ << 4;                 /* 1 */
+                        LARc[0] = sr & 0x3f;  sr >>= 6;
+                        LARc[1] = sr & 0x3f;  sr >>= 6;
+                        sr = *c++;
+                        LARc[2] = sr & 0x1f;  sr >>= 5;
+                        sr |= (uword)*c++ << 3;
+                        LARc[3] = sr & 0x1f;  sr >>= 5;
+                        LARc[4] = sr & 0xf;  sr >>= 4;
+                        sr |= (uword)*c++ << 2;
+                        LARc[5] = sr & 0xf;  sr >>= 4;
+                        LARc[6] = sr & 0x7;  sr >>= 3;
+                        LARc[7] = sr & 0x7;  sr >>= 3;
+                        sr = *c++;                              /* 5 */
+                        Nc[0] = sr & 0x7f;  sr >>= 7;
+                        sr |= (uword)*c++ << 1;
+                        bc[0] = sr & 0x3;  sr >>= 2;
+                        Mc[0] = sr & 0x3;  sr >>= 2;
+                        sr |= (uword)*c++ << 5;
+                        xmaxc[0] = sr & 0x3f;  sr >>= 6;
+                        xmc[0] = sr & 0x7;  sr >>= 3;
+                        xmc[1] = sr & 0x7;  sr >>= 3;
+                        sr |= (uword)*c++ << 1;
+                        xmc[2] = sr & 0x7;  sr >>= 3;
+                        xmc[3] = sr & 0x7;  sr >>= 3;
+                        xmc[4] = sr & 0x7;  sr >>= 3;
+                        sr = *c++;
+                        xmc[5] = sr & 0x7;  sr >>= 3;
+                        xmc[6] = sr & 0x7;  sr >>= 3;
+                        sr |= (uword)*c++ << 2;                 /* 10 */
+                        xmc[7] = sr & 0x7;  sr >>= 3;
+                        xmc[8] = sr & 0x7;  sr >>= 3;
+                        xmc[9] = sr & 0x7;  sr >>= 3;
+                        sr |= (uword)*c++ << 1;
+                        xmc[10] = sr & 0x7;  sr >>= 3;
+                        xmc[11] = sr & 0x7;  sr >>= 3;
+                        xmc[12] = sr & 0x7;  sr >>= 3;
+                        sr = *c++;
+                        Nc[1] = sr & 0x7f;  sr >>= 7;
+                        sr |= (uword)*c++ << 1;
+                        bc[1] = sr & 0x3;  sr >>= 2;
+                        Mc[1] = sr & 0x3;  sr >>= 2;
+                        sr |= (uword)*c++ << 5;
+                        xmaxc[1] = sr & 0x3f;  sr >>= 6;
+                        xmc[13] = sr & 0x7;  sr >>= 3;
+                        xmc[14] = sr & 0x7;  sr >>= 3;
+                        sr |= (uword)*c++ << 1;                 /* 15 */
+                        xmc[15] = sr & 0x7;  sr >>= 3;
+                        xmc[16] = sr & 0x7;  sr >>= 3;
+                        xmc[17] = sr & 0x7;  sr >>= 3;
+                        sr = *c++;
+                        xmc[18] = sr & 0x7;  sr >>= 3;
+                        xmc[19] = sr & 0x7;  sr >>= 3;
+                        sr |= (uword)*c++ << 2;
+                        xmc[20] = sr & 0x7;  sr >>= 3;
+                        xmc[21] = sr & 0x7;  sr >>= 3;
+                        xmc[22] = sr & 0x7;  sr >>= 3;
+                        sr |= (uword)*c++ << 1;
+                        xmc[23] = sr & 0x7;  sr >>= 3;
+                        xmc[24] = sr & 0x7;  sr >>= 3;
+                        xmc[25] = sr & 0x7;  sr >>= 3;
+                        sr = *c++;
+                        Nc[2] = sr & 0x7f;  sr >>= 7;
+                        sr |= (uword)*c++ << 1;                 /* 20 */
+                        bc[2] = sr & 0x3;  sr >>= 2;
+                        Mc[2] = sr & 0x3;  sr >>= 2;
+                        sr |= (uword)*c++ << 5;
+                        xmaxc[2] = sr & 0x3f;  sr >>= 6;
+                        xmc[26] = sr & 0x7;  sr >>= 3;
+                        xmc[27] = sr & 0x7;  sr >>= 3;
+                        sr |= (uword)*c++ << 1;
+                        xmc[28] = sr & 0x7;  sr >>= 3;
+                        xmc[29] = sr & 0x7;  sr >>= 3;
+                        xmc[30] = sr & 0x7;  sr >>= 3;
+                        sr = *c++;
+                        xmc[31] = sr & 0x7;  sr >>= 3;
+                        xmc[32] = sr & 0x7;  sr >>= 3;
+                        sr |= (uword)*c++ << 2;
+                        xmc[33] = sr & 0x7;  sr >>= 3;
+                        xmc[34] = sr & 0x7;  sr >>= 3;
+                        xmc[35] = sr & 0x7;  sr >>= 3;
+                        sr |= (uword)*c++ << 1;                 /* 25 */
+                        xmc[36] = sr & 0x7;  sr >>= 3;
+                        xmc[37] = sr & 0x7;  sr >>= 3;
+                        xmc[38] = sr & 0x7;  sr >>= 3;
+                        sr = *c++;
+                        Nc[3] = sr & 0x7f;  sr >>= 7;
+                        sr |= (uword)*c++ << 1;
+                        bc[3] = sr & 0x3;  sr >>= 2;
+                        Mc[3] = sr & 0x3;  sr >>= 2;
+                        sr |= (uword)*c++ << 5;
+                        xmaxc[3] = sr & 0x3f;  sr >>= 6;
+                        xmc[39] = sr & 0x7;  sr >>= 3;
+                        xmc[40] = sr & 0x7;  sr >>= 3;
+                        sr |= (uword)*c++ << 1;
+                        xmc[41] = sr & 0x7;  sr >>= 3;
+                        xmc[42] = sr & 0x7;  sr >>= 3;
+                        xmc[43] = sr & 0x7;  sr >>= 3;
+                        sr = *c++;                              /* 30 */
+                        xmc[44] = sr & 0x7;  sr >>= 3;
+                        xmc[45] = sr & 0x7;  sr >>= 3;
+                        sr |= (uword)*c++ << 2;
+                        xmc[46] = sr & 0x7;  sr >>= 3;
+                        xmc[47] = sr & 0x7;  sr >>= 3;
+                        xmc[48] = sr & 0x7;  sr >>= 3;
+                        sr |= (uword)*c++ << 1;
+                        xmc[49] = sr & 0x7;  sr >>= 3;
+                        xmc[50] = sr & 0x7;  sr >>= 3;
+                        xmc[51] = sr & 0x7;  sr >>= 3;
+                        writeGSM_33(d+33);
+
+}
index 6628e9d..bd75102 100755 (executable)
@@ -3,7 +3,7 @@
  *
  * Private channel definitions for channel implementations only.
  * 
- * Copyright (C) 1999, Adtran Inc. and Linux Support Services, LLC
+ * Copyright (C) 1999, Mark Spencer
  *
  * Mark Spencer <markster@linux-support.net>
  *
@@ -40,8 +40,8 @@ struct ast_channel_pvt {
 };
 
 /* Create a channel structure */
-struct ast_channel *ast_channel_alloc();
-#define ast_channel_free(a) free(a)
+struct ast_channel *ast_channel_alloc(void);
+void  ast_channel_free(struct ast_channel *);
 
 #if defined(__cplusplus) || defined(c_plusplus)
 }
index 64d039a..82060c2 100755 (executable)
@@ -3,7 +3,7 @@
  * 
  * Mark Spencer <markster@marko.net>
  *
- * Copyright(C) 1999, Adtran, Inc.
+ * Copyright(C) Mark Spencer
  * 
  * Distributed under the terms of the GNU General Public License (GPL) Version 2
  *
@@ -38,10 +38,10 @@ extern "C" {
 struct io_context;
 
 /* Create a context for I/O operations */
-struct io_context *io_context_create();
+extern struct io_context *io_context_create(void);
 
 /* Destroy a context for I/O operations */
-void io_context_destroy(struct io_context *ioc);
+extern void io_context_destroy(struct io_context *ioc);
 
 typedef int (*ast_io_cb)(int *id, int fd, short events, void *cbdata);
 #define AST_IO_CB(a) ((ast_io_cb)(a))
diff --git a/io.c b/io.c
index 2ec5b02..aef361c 100755 (executable)
--- a/io.c
+++ b/io.c
@@ -3,7 +3,7 @@
  * 
  * Mark Spencer <markster@marko.net>
  *
- * Copyright(C) 1999, Adtran, Inc.
+ * Copyright(C) Mark Spencer
  * 
  * Distributed under the terms of the GNU General Public License (GPL) Version 2
  *
@@ -58,7 +58,7 @@ struct io_context {
 };
 
 
-struct io_context *io_context_create()
+struct io_context *io_context_create(void)
 {
        /* Create an I/O context */
        struct io_context *tmp;