From 0ed94773955e5bb7072a863f1a0bba5d69ce7469 Mon Sep 17 00:00:00 2001
From: Mark Spencer <markster@digium.com>
Date: Thu, 16 Dec 1999 13:44:30 +0000
Subject: [PATCH] Version 0.1.1 from FTP

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@139 65c4cc65-6c06-0410-ace0-fbb531ad65f3
---
 BUGS                           |   6 +-
 channels/chan_ixj.c            |  52 ++-
 channels/chan_vofr.c           |  27 +-
 codecs/mp3/Makefile            |  37 ++
 formats/format_g723.c          |   4 +-
 formats/format_gsm.c           | 298 ++++++++++++++
 formats/format_mp3.c           | 103 +++--
 formats/format_wav.c           |   4 +-
 formats/format_wav_gsm.c       | 586 ++++++++++++++++++++++++++++
 formats/msgsm.h                | 685 +++++++++++++++++++++++++++++++++
 include/asterisk/channel_pvt.h |   6 +-
 include/asterisk/io.h          |   6 +-
 io.c                           |   4 +-
 13 files changed, 1750 insertions(+), 68 deletions(-)
 create mode 100755 codecs/mp3/Makefile
 create mode 100755 formats/format_gsm.c
 create mode 100755 formats/format_wav_gsm.c
 create mode 100755 formats/msgsm.h

diff --git a/BUGS b/BUGS
index 04fbe3e485..495e20da1d 100755
--- 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.
diff --git a/channels/chan_ixj.c b/channels/chan_ixj.c
index 5f476cdf64..c8cdb91dd7 100755
--- a/channels/chan_ixj.c
+++ b/channels/chan_ixj.c
@@ -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;
diff --git a/channels/chan_vofr.c b/channels/chan_vofr.c
index ea17df9519..aee44ff2ea 100755
--- a/channels/chan_vofr.c
+++ b/channels/chan_vofr.c
@@ -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
index 0000000000..44ebc39d1a
--- /dev/null
+++ b/codecs/mp3/Makefile
@@ -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)
diff --git a/formats/format_g723.c b/formats/format_g723.c
index 827987049a..3824e04e72 100755
--- a/formats/format_g723.c
+++ b/formats/format_g723.c
@@ -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
index 0000000000..6a06627fb2
--- /dev/null
+++ b/formats/format_gsm.c
@@ -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;
+}
+
diff --git a/formats/format_mp3.c b/formats/format_mp3.c
index 811acbe149..85abdbc1b9 100755
--- a/formats/format_mp3.c
+++ b/formats/format_mp3.c
@@ -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;
 }
diff --git a/formats/format_wav.c b/formats/format_wav.c
index e3265d379b..9ba4fdc22a 100755
--- a/formats/format_wav.c
+++ b/formats/format_wav.c
@@ -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
index 0000000000..b901a40288
--- /dev/null
+++ b/formats/format_wav_gsm.c
@@ -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
index 0000000000..2513e72b15
--- /dev/null
+++ b/formats/msgsm.h
@@ -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);
+
+}
diff --git a/include/asterisk/channel_pvt.h b/include/asterisk/channel_pvt.h
index 6628e9d5fe..bd75102e5e 100755
--- a/include/asterisk/channel_pvt.h
+++ b/include/asterisk/channel_pvt.h
@@ -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)
 }
diff --git a/include/asterisk/io.h b/include/asterisk/io.h
index 64d039a511..82060c20dd 100755
--- a/include/asterisk/io.h
+++ b/include/asterisk/io.h
@@ -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 2ec5b02184..aef361c642 100755
--- 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;
-- 
GitLab