diff --exclude .svn -urN asterisk-1.2.9.1/Makefile 1.2.9.1/Makefile
--- asterisk-1.2.9.1/Makefile	2006-04-30 16:27:56.000000000 +0200
+++ 1.2.9.1/Makefile	2006-06-12 15:49:58.000000000 +0200
@@ -19,7 +19,7 @@
 # CROSS_COMPILE=/opt/montavista/pro/devkit/arm/xscale_be/bin/xscale_be-
 # CROSS_COMPILE_BIN=/opt/montavista/pro/devkit/arm/xscale_be/bin/
 # CROSS_COMPILE_TARGET=/opt/montavista/pro/devkit/arm/xscale_be/target
-CC=$(CROSS_COMPILE)gcc
+CC=$(CROSS_COMPILE)gcc-3.4
 HOST_CC=gcc
 # CROSS_ARCH=Linux
 # CROSS_PROC=arm
@@ -46,7 +46,7 @@
 #K6OPT  = -DK6OPT
 
 #Tell gcc to optimize the code
-OPTIMIZE+=-O6
+OPTIMIZE+=-O0
 endif
 
 #Overwite config files on "make samples"
@@ -76,6 +76,9 @@
 # Uncomment next one to enable ast_frame tracing (for debugging)
 TRACE_FRAMES = #-DTRACE_FRAMES
 
+# Uncomment next one to enable the asterisk generic jitterbuffer
+GENERIC_JB = -DAST_JB
+
 # Uncomment next one to enable malloc debugging
 # You can view malloc debugging with:
 #   *CLI> show memory allocations [filename]
@@ -329,6 +332,7 @@
 
 ASTCFLAGS+= $(DEBUG_THREADS)
 ASTCFLAGS+= $(TRACE_FRAMES)
+ASTCFLAGS+= $(GENERIC_JB)
 ASTCFLAGS+= $(MALLOC_DEBUG)
 ASTCFLAGS+= $(BUSYDETECT)
 ASTCFLAGS+= $(OPTIONS)
@@ -343,7 +347,7 @@
 	cdr.o tdd.o acl.o rtp.o manager.o asterisk.o \
 	dsp.o chanvars.o indications.o autoservice.o db.o privacy.o \
 	astmm.o enum.o srv.o dns.o aescrypt.o aestab.o aeskey.o \
-	utils.o plc.o jitterbuf.o dnsmgr.o devicestate.o \
+	utils.o plc.o jitterbuf.o scx_jitterbuf.o abstract_jb.o dnsmgr.o devicestate.o \
 	netsock.o slinfactory.o ast_expr2.o ast_expr2f.o \
 	cryptostub.o
 
diff --exclude .svn -urN asterisk-1.2.9.1/abstract_jb.c 1.2.9.1/abstract_jb.c
--- asterisk-1.2.9.1/abstract_jb.c	1970-01-01 01:00:00.000000000 +0100
+++ 1.2.9.1/abstract_jb.c	2006-06-12 15:49:58.000000000 +0200
@@ -0,0 +1,887 @@
+/*
+ * abstract_jb: common implementation-independent jitterbuffer stuff
+ *
+ * Copyright (C) 2005, Attractel OOD
+ *
+ * Contributors:
+ * Slav Klenov <slav@securax.org>
+ *
+ * Copyright on this file is disclaimed to Digium for inclusion in Asterisk
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Common implementation-independent jitterbuffer stuff.
+ * 
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision: 1.1 $")
+
+#include "asterisk/frame.h"
+#include "asterisk/channel.h"
+#include "asterisk/logger.h"
+#include "asterisk/term.h"
+#include "asterisk/options.h"
+#include "asterisk/utils.h"
+
+#ifdef AST_JB
+
+#include "asterisk/abstract_jb.h"
+#include "scx_jitterbuf.h"
+#include "jitterbuf.h"
+
+
+/* Internal jb flags */
+#define JB_USE (1 << 0)
+#define JB_TIMEBASE_INITIALIZED (1 << 1)
+#define JB_CREATED (1 << 2)
+
+
+/* Hooks for the abstract jb implementation */
+
+/* Create */
+typedef void * (*jb_create_impl)(struct ast_jb_conf *general_config, long resynch_threshold);
+/* Destroy */
+typedef void (*jb_destroy_impl)(void *jb);
+/* Put first frame */
+typedef int (*jb_put_first_impl)(void *jb, struct ast_frame *fin, long now);
+/* Put frame */
+typedef int (*jb_put_impl)(void *jb, struct ast_frame *fin, long now);
+/* Get frame for now */
+typedef int (*jb_get_impl)(void *jb, struct ast_frame **fout, long now, long interpl);
+/* Get next */
+typedef long (*jb_next_impl)(void *jb);
+/* Remove first frame */
+typedef int (*jb_remove_impl)(void *jb, struct ast_frame **fout);
+/* Force resynch */
+typedef void (*jb_force_resynch_impl)(void *jb);
+
+
+/*!
+ * \brief Jitterbuffer implementation private struct.
+ */
+struct ast_jb_impl
+{
+	char name[AST_JB_IMPL_NAME_SIZE];
+	jb_create_impl create;
+	jb_destroy_impl destroy;
+	jb_put_first_impl put_first;
+	jb_put_impl put;
+	jb_get_impl get;
+	jb_next_impl next;
+	jb_remove_impl remove;
+	jb_force_resynch_impl force_resync;
+};
+
+/* Implementation functions */
+/* scx */
+static void * jb_create_scx(struct ast_jb_conf *general_config, long resynch_threshold);
+static void jb_destroy_scx(void *jb);
+static int jb_put_first_scx(void *jb, struct ast_frame *fin, long now);
+static int jb_put_scx(void *jb, struct ast_frame *fin, long now);
+static int jb_get_scx(void *jb, struct ast_frame **fout, long now, long interpl);
+static long jb_next_scx(void *jb);
+static int jb_remove_scx(void *jb, struct ast_frame **fout);
+static void jb_force_resynch_scx(void *jb);
+/* stevek */
+static void * jb_create_stevek(struct ast_jb_conf *general_config, long resynch_threshold);
+static void jb_destroy_stevek(void *jb);
+static int jb_put_first_stevek(void *jb, struct ast_frame *fin, long now);
+static int jb_put_stevek(void *jb, struct ast_frame *fin, long now);
+static int jb_get_stevek(void *jb, struct ast_frame **fout, long now, long interpl);
+static long jb_next_stevek(void *jb);
+static int jb_remove_stevek(void *jb, struct ast_frame **fout);
+static void jb_force_resynch_stevek(void *jb);
+
+/* Available jb implementations */
+static struct ast_jb_impl avail_impl[] = 
+{
+	{
+		.name = "fixed",
+		.create = jb_create_scx,
+		.destroy = jb_destroy_scx,
+		.put_first = jb_put_first_scx,
+		.put = jb_put_scx,
+		.get = jb_get_scx,
+		.next = jb_next_scx,
+		.remove = jb_remove_scx,
+		.force_resync = jb_force_resynch_scx
+	},
+	{
+		.name = "adaptive",
+		.create = jb_create_stevek,
+		.destroy = jb_destroy_stevek,
+		.put_first = jb_put_first_stevek,
+		.put = jb_put_stevek,
+		.get = jb_get_stevek,
+		.next = jb_next_stevek,
+		.remove = jb_remove_stevek,
+		.force_resync = jb_force_resynch_stevek
+	}
+};
+
+static int default_impl = 0;
+
+
+/* Abstract return codes */
+#define JB_IMPL_OK 0
+#define JB_IMPL_DROP 1
+#define JB_IMPL_INTERP 2
+#define JB_IMPL_NOFRAME 3
+
+/* Translations between impl and abstract return codes */
+static int scx_to_abstract_code[] =
+	{JB_IMPL_OK, JB_IMPL_DROP, JB_IMPL_INTERP, JB_IMPL_NOFRAME};
+static int stevek_to_abstract_code[] =
+	{JB_IMPL_OK, JB_IMPL_NOFRAME, JB_IMPL_NOFRAME, JB_IMPL_INTERP, JB_IMPL_DROP, JB_IMPL_OK};
+
+/* JB_GET actions (used only for the frames log) */
+static char *jb_get_actions[] = {"Delivered", "Dropped", "Interpolated", "No"};
+
+/* Macros for JB logs */
+/*#define jb_verbose(...) ast_verbose(VERBOSE_PREFIX_3 " ***[JB LOG]*** " __VA_ARGS__)*/
+#define jb_verbose(...) if(1){\
+	char tmp[192];\
+	char msg[128];\
+	snprintf(msg, sizeof(msg), VERBOSE_PREFIX_3 "***[JB LOG]*** " __VA_ARGS__);\
+	ast_verbose("%s\n", term_color(tmp, msg, COLOR_BRGREEN, 0, sizeof(tmp)));}
+
+/* Macros for the frame log files */
+#define jb_framelog(...) \
+if(jb->logfile) \
+{ \
+	fprintf(jb->logfile, __VA_ARGS__); \
+	fflush(jb->logfile); \
+} \
+
+
+/* Internal utility functions */
+static void jb_choose_impl(struct ast_channel *chan);
+static void jb_get_and_deliver(struct ast_channel *chan);
+static int create_jb(struct ast_channel *chan, struct ast_frame *first_frame);
+static long get_now(struct ast_jb *jb, struct timeval *tv);
+
+
+/* Interface ast jb functions impl */
+
+
+static void jb_choose_impl(struct ast_channel *chan)
+{
+	struct ast_jb *jb = &chan->jb;
+	struct ast_jb_conf *jbconf = &jb->conf;
+	struct ast_jb_impl *test_impl;
+	int i, avail_impl_count = sizeof(avail_impl) / sizeof(avail_impl[0]);
+	
+	jb->impl = &avail_impl[default_impl];
+	
+	if(*jbconf->impl == '\0')
+	{
+		return;
+	}
+		
+	for(i=0; i<avail_impl_count; i++)
+	{
+		test_impl = &avail_impl[i];
+		if(strcmp(jbconf->impl, test_impl->name) == 0)
+		{
+			jb->impl = test_impl;
+			return;
+		}
+	}
+}
+
+
+void ast_jb_do_usecheck(struct ast_channel *c0, struct ast_channel *c1)
+{
+	struct ast_jb *jb0 = &c0->jb;
+	struct ast_jb *jb1 = &c1->jb;
+	struct ast_jb_conf *conf0 = &jb0->conf;
+	struct ast_jb_conf *conf1 = &jb1->conf;
+	int c0_wants_jitter = c0->tech->properties & AST_CHAN_TP_WANTSJITTER;
+	int c0_creates_jitter = c0->tech->properties & AST_CHAN_TP_CREATESJITTER;
+	int c0_jb_enabled = ast_test_flag(conf0, AST_JB_ENABLED);
+	int c0_force_jb = ast_test_flag(conf0, AST_JB_FORCED);
+	int c0_jb_timebase_initialized = ast_test_flag(jb0, JB_TIMEBASE_INITIALIZED);
+	int c0_jb_created = ast_test_flag(jb0, JB_CREATED);
+	int c1_wants_jitter = c1->tech->properties & AST_CHAN_TP_WANTSJITTER;
+	int c1_creates_jitter = c1->tech->properties & AST_CHAN_TP_CREATESJITTER;
+	int c1_jb_enabled = ast_test_flag(conf1, AST_JB_ENABLED);
+	int c1_force_jb = ast_test_flag(conf1, AST_JB_FORCED);
+	int c1_jb_timebase_initialized = ast_test_flag(jb1, JB_TIMEBASE_INITIALIZED);
+	int c1_jb_created = ast_test_flag(jb1, JB_CREATED);
+	
+	if(((!c0_wants_jitter && c1_creates_jitter) || (c0_force_jb && c1_creates_jitter) && c0_jb_enabled))
+	{
+		ast_set_flag(jb0, JB_USE);
+		if(!c0_jb_timebase_initialized)
+		{
+			if(c1_jb_timebase_initialized)
+			{
+				memcpy(&jb0->timebase, &jb1->timebase, sizeof(struct timeval));
+			}
+			else
+			{
+				gettimeofday(&jb0->timebase, NULL);
+			}
+			ast_set_flag(jb0, JB_TIMEBASE_INITIALIZED);
+		}
+		
+		if(!c0_jb_created)
+		{
+			jb_choose_impl(c0);
+		}
+	}
+	
+	if(((!c1_wants_jitter && c0_creates_jitter) || (c1_force_jb && c0_creates_jitter)) && c1_jb_enabled)
+	{
+		ast_set_flag(jb1, JB_USE);
+		if(!c1_jb_timebase_initialized)
+		{
+			if(c0_jb_timebase_initialized)
+			{
+				memcpy(&jb1->timebase, &jb0->timebase, sizeof(struct timeval));
+			}
+			else
+			{
+				gettimeofday(&jb1->timebase, NULL);
+			}
+			ast_set_flag(jb1, JB_TIMEBASE_INITIALIZED);
+		}
+		
+		if(!c1_jb_created)
+		{
+			jb_choose_impl(c1);
+		}
+	}
+}
+
+
+int ast_jb_get_when_to_wakeup(struct ast_channel *c0, struct ast_channel *c1, int time_left)
+{
+	struct ast_jb *jb0 = &c0->jb;
+	struct ast_jb *jb1 = &c1->jb;
+	int c0_use_jb = ast_test_flag(jb0, JB_USE);
+	int c0_jb_is_created = ast_test_flag(jb0, JB_CREATED);
+	int c1_use_jb = ast_test_flag(jb1, JB_USE);
+	int c1_jb_is_created = ast_test_flag(jb1, JB_CREATED);
+	int wait, wait0, wait1;
+	struct timeval tv_now;
+	
+	if(time_left == 0)
+	{
+		/* No time left - the bridge will be retried */
+		/* TODO: Test disable this */
+		/*return 0;*/
+	}
+	
+	if(time_left < 0)
+	{
+		time_left = INT_MAX;
+	}
+	
+	gettimeofday(&tv_now, NULL);
+	
+	wait0 = (c0_use_jb && c0_jb_is_created) ? jb0->next - get_now(jb0, &tv_now) : time_left;
+	wait1 = (c1_use_jb && c1_jb_is_created) ? jb1->next - get_now(jb1, &tv_now) : time_left;
+	
+	wait = wait0 < wait1 ? wait0 : wait1;
+	wait = wait < time_left ? wait : time_left;
+	
+	if(wait == INT_MAX)
+	{
+		wait = -1;
+	}
+	else if(wait < 1)
+	{
+		/* don't let wait=0, because this can cause the pbx thread to loop without any sleeping at all */
+		wait = 1;
+	}
+	
+	return wait;
+}
+
+
+int ast_jb_put(struct ast_channel *chan, struct ast_frame *f)
+{
+	struct ast_jb *jb = &chan->jb;
+	struct ast_jb_impl *jbimpl = jb->impl;
+	void *jbobj = jb->jbobj;
+	struct ast_frame *frr;
+	long now = 0;
+	
+	if(!ast_test_flag(jb, JB_USE))
+	{
+		return -1;
+	}
+	
+	if(f->frametype != AST_FRAME_VOICE)
+	{
+		if(f->frametype == AST_FRAME_DTMF && ast_test_flag(jb, JB_CREATED))
+		{
+			jb_framelog("JB_PUT {now=%ld}: Received DTMF frame. Force resynching jb...\n", now);
+			jbimpl->force_resync(jbobj);
+		}
+		
+		return -1;
+	}
+	
+	/* We consider an enabled jitterbuffer should receive frames with valid timing info. */
+	if(!f->has_timing_info || f->len < 2 || f->ts < 0)
+	{
+		ast_log(LOG_WARNING, "Recieved frame with invalid timing info: "
+			"has_timing_info=%d, len=%ld, ts=%ld\n", f->has_timing_info, f->len, f->ts);
+		return -1;
+	}
+	
+	if(f->mallocd & AST_MALLOCD_HDR)
+	{
+		frr = ast_frdup(f);
+	}
+	else
+	{
+		frr = ast_frisolate(f);
+	}
+	if(frr == NULL)
+	{
+		ast_log(LOG_ERROR, "Failed to isolate frame for the jitterbuffer on channel '%s'\n", chan->name);
+		return -1;
+	}
+	
+	if(!ast_test_flag(jb, JB_CREATED))
+	{
+		if(create_jb(chan, frr))
+		{
+			ast_frfree(frr);
+			/* Disable the jitterbuffer */
+			ast_clear_flag(jb, JB_USE);
+			return -1;
+		}
+		
+		ast_set_flag(jb, JB_CREATED);
+		return 0;
+	}
+	else
+	{
+		now = get_now(jb, NULL);
+		if(jbimpl->put(jbobj, frr, now) != JB_IMPL_OK)
+		{
+			jb_framelog("JB_PUT {now=%ld}: Dropped frame with ts=%ld and len=%ld\n", now, frr->ts, frr->len);
+			ast_frfree(frr);
+			/*return -1;*/
+			/* TODO: Check this fix - should return 0 here, because the dropped frame shouldn't 
+			   be delivered at all */
+			return 0;
+		}
+		
+		jb->next = jbimpl->next(jbobj);
+		
+		jb_framelog("JB_PUT {now=%ld}: Queued frame with ts=%ld and len=%ld\n", now, frr->ts, frr->len);
+		
+		return 0;
+	}
+}
+
+
+void ast_jb_get_and_deliver(struct ast_channel *c0, struct ast_channel *c1)
+{
+	struct ast_jb *jb0 = &c0->jb;
+	struct ast_jb *jb1 = &c1->jb;
+	int c0_use_jb = ast_test_flag(jb0, JB_USE);
+	int c0_jb_is_created = ast_test_flag(jb0, JB_CREATED);
+	int c1_use_jb = ast_test_flag(jb1, JB_USE);
+	int c1_jb_is_created = ast_test_flag(jb1, JB_CREATED);
+	
+	if(c0_use_jb && c0_jb_is_created)
+	{
+		jb_get_and_deliver(c0);
+	}
+	
+	if(c1_use_jb && c1_jb_is_created)
+	{
+		jb_get_and_deliver(c1);
+	}
+}
+
+
+static void jb_get_and_deliver(struct ast_channel *chan)
+{
+	struct ast_jb *jb = &chan->jb;
+	struct ast_jb_impl *jbimpl = jb->impl;
+	void *jbobj = jb->jbobj;
+	struct ast_frame *f, finterp;
+	long now;
+	int interpolation_len, res;
+	
+	now = get_now(jb, NULL);
+	jb->next = jbimpl->next(jbobj);
+	if(now < jb->next)
+	{
+		jb_framelog("\tJB_GET {now=%ld}: now < next=%ld\n", now, jb->next);
+		return;
+	}
+	
+	while(now >= jb->next)
+	{
+		interpolation_len = ast_codec_interp_len(jb->last_format);
+		
+		res = jbimpl->get(jbobj, &f, now, interpolation_len);
+		
+		switch(res)
+		{
+		case JB_IMPL_OK:
+			/* deliver the frame */
+			ast_write(chan, f);
+		case JB_IMPL_DROP:
+			jb_framelog("\tJB_GET {now=%ld}: %s frame with ts=%ld and len=%ld\n",
+				now, jb_get_actions[res], f->ts, f->len);
+			jb->last_format = f->subclass;
+			ast_frfree(f);
+			break;
+		case JB_IMPL_INTERP:
+			/* interpolate a frame */
+			f = &finterp;
+			f->frametype = AST_FRAME_VOICE;
+			f->subclass = jb->last_format;
+			f->datalen  = 0;
+			f->samples  = interpolation_len * 8;
+			f->mallocd  = 0;
+			f->src  = "JB interpolation";
+			f->data  = NULL;
+			f->delivery = ast_tvadd(jb->timebase, ast_samp2tv(jb->next, 1000));
+			f->offset=AST_FRIENDLY_OFFSET;
+			/* deliver the interpolated frame */
+			ast_write(chan, f);
+			jb_framelog("\tJB_GET {now=%ld}: Interpolated frame with len=%d\n", now, interpolation_len);
+			break;
+		case JB_IMPL_NOFRAME:
+			ast_log(LOG_WARNING,
+				"JB_IMPL_NOFRAME is retuned from the %s jb when now=%ld >= next=%ld, jbnext=%ld!\n",
+				jbimpl->name, now, jb->next, jbimpl->next(jbobj));
+			jb_framelog("\tJB_GET {now=%ld}: No frame for now!?\n", now);
+			return;
+		default:
+			ast_log(LOG_ERROR, "This should never happen!\n");
+			CRASH;
+			break;
+		}
+		
+		jb->next = jbimpl->next(jbobj);
+	}
+}
+
+
+static int create_jb(struct ast_channel *chan, struct ast_frame *frr)
+{
+	struct ast_jb *jb = &chan->jb;
+	struct ast_jb_conf *jbconf = &jb->conf;
+	struct ast_jb_impl *jbimpl = jb->impl;
+	void *jbobj;
+	struct ast_channel *bridged;
+	long now;
+	char logfile_pathname[20 + AST_JB_IMPL_NAME_SIZE + 2*AST_CHANNEL_NAME + 1];
+	char name1[AST_CHANNEL_NAME], name2[AST_CHANNEL_NAME], *tmp;
+	int res;
+
+	jbobj = jb->jbobj = jbimpl->create(jbconf, jbconf->resync_threshold);
+	if(jbobj == NULL)
+	{
+		ast_log(LOG_WARNING, "Failed to create jitterbuffer on channel '%s'\n", chan->name);
+		return -1;
+	}
+	
+	now = get_now(jb, NULL);
+	res = jbimpl->put_first(jbobj, frr, now);
+	
+	/* The result of putting the first frame should not differ from OK. However, its possible
+	   some implementations (i.e. stevek's when resynch_threshold is specified) to drop it. */
+	if(res != JB_IMPL_OK)
+	{
+		ast_log(LOG_WARNING, "Failed to put first frame in the jitterbuffer on channel '%s'\n", chan->name);
+		/*
+		jbimpl->destroy(jbobj);
+		return -1;
+		*/
+	}
+	
+	/* Init next */
+	jb->next = jbimpl->next(jbobj);
+	
+	/* Init last format for a first time. */
+	jb->last_format = frr->subclass;
+	
+	/* Create a frame log file */
+	if(ast_test_flag(jbconf, AST_JB_LOG))
+	{
+		snprintf(name2, sizeof(name2), "%s", chan->name);
+		tmp = strchr(name2, '/');
+		if(tmp != NULL)
+		{
+			*tmp = '#';
+		}
+		bridged = ast_bridged_channel(chan);
+		if(bridged == NULL)
+		{
+			/* We should always have bridged chan if a jitterbuffer is in use */
+			CRASH;
+		}
+		snprintf(name1, sizeof(name1), "%s", bridged->name);
+		tmp = strchr(name1, '/');
+		if(tmp != NULL)
+		{
+			*tmp = '#';
+		}
+		snprintf(logfile_pathname, sizeof(logfile_pathname),
+			"/tmp/ast_%s_jb_%s--%s.log", jbimpl->name, name1, name2);
+		jb->logfile = fopen(logfile_pathname, "w+b");
+		
+		if(jb->logfile == NULL)
+		{
+			ast_log(LOG_WARNING, "Failed to create frame log file with pathname '%s'\n", logfile_pathname);
+		}
+		
+		if(res == JB_IMPL_OK)
+		{
+			jb_framelog("JB_PUT_FIRST {now=%ld}: Queued frame with ts=%ld and len=%ld\n",
+				now, frr->ts, frr->len);
+		}
+		else
+		{
+			jb_framelog("JB_PUT_FIRST {now=%ld}: Dropped frame with ts=%ld and len=%ld\n",
+				now, frr->ts, frr->len);
+		}
+	}
+	
+	jb_verbose("%s jitterbuffer created on channel %s", jbimpl->name, chan->name);
+	
+	/* Free the frame if it has not been queued in the jb */
+	if(res != JB_IMPL_OK)
+	{
+		ast_frfree(frr);
+	}
+	
+	return 0;
+}
+
+
+void ast_jb_destroy(struct ast_channel *chan)
+{
+	struct ast_jb *jb = &chan->jb;
+	struct ast_jb_impl *jbimpl = jb->impl;
+	void *jbobj = jb->jbobj;
+	struct ast_frame *f;
+
+	if(jb->logfile != NULL)
+	{
+		fclose(jb->logfile);
+		jb->logfile = NULL;
+	}
+	
+	if(ast_test_flag(jb, JB_CREATED))
+	{
+		/* Remove and free all frames still queued in jb */
+		while(jbimpl->remove(jbobj, &f) == JB_IMPL_OK)
+		{
+			ast_frfree(f);
+		}
+		
+		jbimpl->destroy(jbobj);
+		jb->jbobj = NULL;
+		
+		ast_clear_flag(jb, JB_CREATED);
+		
+		jb_verbose("%s jitterbuffer destroyed on channel %s", jbimpl->name, chan->name);
+	}
+}
+
+
+static long get_now(struct ast_jb *jb, struct timeval *tv)
+{
+	struct timeval now;
+	
+	if(tv == NULL)
+	{
+		tv = &now;
+		gettimeofday(tv, NULL);
+	}
+	
+	return (long) ((tv->tv_sec - jb->timebase.tv_sec) * 1000) +
+		(long) ((double) (tv->tv_usec - jb->timebase.tv_usec) / 1000.0);
+	
+	/* TODO: For asterisk complience, we should use: */
+	/* return ast_tvdiff_ms(*tv, jb->timebase); */
+}
+
+
+int ast_jb_read_conf(struct ast_jb_conf *conf, char *varname, char *value)
+{
+	int prefixlen = sizeof(AST_JB_CONF_PREFIX) - 1;
+	char *name;
+	int tmp;
+	
+	if(memcmp(AST_JB_CONF_PREFIX, varname, prefixlen) != 0)
+	{
+		return -1;
+	}
+	
+	name = varname + prefixlen;
+	
+	if(strcmp(name, AST_JB_CONF_ENABLE) == 0)
+	{
+		if(ast_true(value))
+		{
+			conf->flags |= AST_JB_ENABLED;
+		}
+	}
+	else if(strcmp(name, AST_JB_CONF_FORCE) == 0)
+	{
+		if(ast_true(value))
+		{
+			conf->flags |= AST_JB_FORCED;
+		}
+	}
+	else if(strcmp(name, AST_JB_CONF_MAX_SIZE) == 0)
+	{
+		if((tmp = atoi(value)) > 0)
+		{
+			conf->max_size = tmp;
+		}
+	}
+	else if(strcmp(name, AST_JB_CONF_RESYNCH_THRESHOLD) == 0)
+	{
+		if((tmp = atoi(value)) > 0)
+		{
+			conf->resync_threshold = tmp;
+		}
+	}
+	else if(strcmp(name, AST_JB_CONF_IMPL) == 0)
+	{
+		if(*value)
+		{
+			snprintf(conf->impl, sizeof(conf->impl), "%s", value);
+		}
+	}
+	else if(strcmp(name, AST_JB_CONF_LOG) == 0)
+	{
+		if(ast_true(value))
+		{
+			conf->flags |= AST_JB_LOG;
+		}
+	}
+	else
+	{
+		return -1;
+	}
+	
+	return 0;
+}
+
+
+void ast_jb_configure(struct ast_channel *chan, struct ast_jb_conf *conf)
+{
+	struct ast_jb *jb = &chan->jb;
+	struct ast_jb_conf *jbconf = &jb->conf;
+	
+	memcpy(jbconf, conf, sizeof(struct ast_jb_conf));
+}
+
+
+void ast_jb_get_config(struct ast_channel *chan, struct ast_jb_conf *conf)
+{
+	struct ast_jb *jb = &chan->jb;
+	struct ast_jb_conf *jbconf = &jb->conf;
+	
+	memcpy(conf, jbconf, sizeof(struct ast_jb_conf));
+}
+
+
+/* Implementation functions */
+
+/* scx */
+
+static void * jb_create_scx(struct ast_jb_conf *general_config, long resynch_threshold)
+{
+	struct scx_jb_conf conf;
+	
+	conf.jbsize = general_config->max_size;
+	conf.resync_threshold = resynch_threshold;
+	
+	return scx_jb_new(&conf);
+}
+
+
+static void jb_destroy_scx(void *jb)
+{
+	struct scx_jb *scxjb = (struct scx_jb *) jb;
+	
+	/* destroy the jb */
+	scx_jb_destroy(scxjb);
+}
+
+
+static int jb_put_first_scx(void *jb, struct ast_frame *fin, long now)
+{
+	struct scx_jb *scxjb = (struct scx_jb *) jb;
+	int res;
+	
+	res = scx_jb_put_first(scxjb, fin, fin->len, fin->ts, now);
+	
+	return scx_to_abstract_code[res];
+}
+
+
+static int jb_put_scx(void *jb, struct ast_frame *fin, long now)
+{
+	struct scx_jb *scxjb = (struct scx_jb *) jb;
+	int res;
+	
+	res = scx_jb_put(scxjb, fin, fin->len, fin->ts, now);
+	
+	return scx_to_abstract_code[res];
+}
+
+
+static int jb_get_scx(void *jb, struct ast_frame **fout, long now, long interpl)
+{
+	struct scx_jb *scxjb = (struct scx_jb *) jb;
+	struct scx_jb_frame frame;
+	int res;
+	
+	res = scx_jb_get(scxjb, &frame, now, interpl);
+	*fout = frame.data;
+	
+	return scx_to_abstract_code[res];
+}
+
+
+static long jb_next_scx(void *jb)
+{
+	struct scx_jb *scxjb = (struct scx_jb *) jb;
+	
+	return scx_jb_next(scxjb);
+}
+
+
+static int jb_remove_scx(void *jb, struct ast_frame **fout)
+{
+	struct scx_jb *scxjb = (struct scx_jb *) jb;
+	struct scx_jb_frame frame;
+	int res;
+	
+	res = scx_jb_remove(scxjb, &frame);
+	*fout = frame.data;
+	
+	return scx_to_abstract_code[res];
+}
+
+
+static void jb_force_resynch_scx(void *jb)
+{
+	struct scx_jb *scxjb = (struct scx_jb *) jb;
+	
+	scx_jb_set_force_resynch(scxjb);
+}
+
+
+/* stevek */
+
+static void * jb_create_stevek(struct ast_jb_conf *general_config, long resynch_threshold)
+{
+	jb_conf jbconf;
+	jitterbuf *stevekjb;
+
+	stevekjb = jb_new();
+	if(stevekjb != NULL)
+	{
+		jbconf.max_jitterbuf = general_config->max_size;
+		jbconf.resync_threshold = general_config->resync_threshold;
+		jbconf.max_contig_interp = 10;
+		jb_setconf(stevekjb, &jbconf);
+	}
+	
+	return stevekjb;
+}
+
+
+static void jb_destroy_stevek(void *jb)
+{
+	jitterbuf *stevekjb = (jitterbuf *) jb;
+	
+	jb_destroy(stevekjb);
+}
+
+
+static int jb_put_first_stevek(void *jb, struct ast_frame *fin, long now)
+{
+	return jb_put_stevek(jb, fin, now);
+}
+
+
+static int jb_put_stevek(void *jb, struct ast_frame *fin, long now)
+{
+	jitterbuf *stevekjb = (jitterbuf *) jb;
+	int res;
+	
+	res = jb_put(stevekjb, fin, JB_TYPE_VOICE, fin->len, fin->ts, now);
+	
+	return stevek_to_abstract_code[res];
+}
+
+
+static int jb_get_stevek(void *jb, struct ast_frame **fout, long now, long interpl)
+{
+	jitterbuf *stevekjb = (jitterbuf *) jb;
+	jb_frame frame;
+	int res;
+	
+	res = jb_get(stevekjb, &frame, now, interpl);
+	*fout = frame.data;
+	
+	return stevek_to_abstract_code[res];
+}
+
+
+static long jb_next_stevek(void *jb)
+{
+	jitterbuf *stevekjb = (jitterbuf *) jb;
+	
+	return jb_next(stevekjb);
+}
+
+
+static int jb_remove_stevek(void *jb, struct ast_frame **fout)
+{
+	jitterbuf *stevekjb = (jitterbuf *) jb;
+	jb_frame frame;
+	int res;
+	
+	res = jb_getall(stevekjb, &frame);
+	*fout = frame.data;
+	
+	return stevek_to_abstract_code[res];
+}
+
+
+static void jb_force_resynch_stevek(void *jb)
+{
+}
+
+
+#endif /* AST_JB */
+
+
diff --exclude .svn -urN asterisk-1.2.9.1/apps/Makefile 1.2.9.1/apps/Makefile
--- asterisk-1.2.9.1/apps/Makefile	2006-04-30 15:38:22.000000000 +0200
+++ 1.2.9.1/apps/Makefile	2006-06-12 15:49:55.000000000 +0200
@@ -54,6 +54,10 @@
 APPS+=app_osplookup.so
 endif
 
+ifneq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/local/include/spandsp.h $(CROSS_COMPILE_TARGET)/usr/include/spandsp.h),)
+APPS+=app_rxfax.so app_txfax.so
+endif
+
 ifeq ($(findstring BSD,${OSARCH}),BSD)
 CFLAGS+=-I$(CROSS_COMPILE_TARGET)/usr/local/include -L$(CROSS_COMPILE_TARGET)/usr/local/lib
 endif
@@ -102,6 +106,12 @@
 app_curl.so: app_curl.o
 	$(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} $(CURLLIBS)
 
+app_rxfax.so : app_rxfax.o
+	$(CC) $(SOLINK) -o $@ $< -lspandsp -ltiff
+
+app_txfax.so : app_txfax.o
+	$(CC) $(SOLINK) -o $@ $< -lspandsp -ltiff
+
 app_sql_postgres.o: app_sql_postgres.c
 	$(CC) -pipe -I$(CROSS_COMPILE_TARGET)/usr/local/pgsql/include -I$(CROSS_COMPILE_TARGET)/usr/include/postgresql $(CFLAGS) -c -o app_sql_postgres.o app_sql_postgres.c
 
diff --exclude .svn -urN asterisk-1.2.9.1/apps/app_rxfax.c 1.2.9.1/apps/app_rxfax.c
--- asterisk-1.2.9.1/apps/app_rxfax.c	1970-01-01 01:00:00.000000000 +0100
+++ 1.2.9.1/apps/app_rxfax.c	2006-06-12 15:49:55.000000000 +0200
@@ -0,0 +1,386 @@
+/*
+ * Asterisk -- A telephony toolkit for Linux.
+ *
+ * Trivial application to receive a TIFF FAX file
+ * 
+ * Copyright (C) 2003, Steve Underwood
+ *
+ * Steve Underwood <steveu@coppice.org>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License
+ */
+ 
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <errno.h>
+#include <tiffio.h>
+
+#include <spandsp.h>
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision:$")
+
+#include "asterisk/lock.h"
+#include "asterisk/file.h"
+#include "asterisk/logger.h"
+#include "asterisk/channel.h"
+#include "asterisk/pbx.h"
+#include "asterisk/module.h"
+#include "asterisk/translate.h"
+#include "asterisk/dsp.h"
+#include "asterisk/manager.h"
+
+static char *tdesc = "Trivial FAX Receive Application";
+
+static char *app = "RxFAX";
+
+static char *synopsis = "Receive a FAX to a file";
+
+static char *descrip = 
+"  RxFAX(filename[|caller][|debug]): Receives a FAX from the channel into the\n"
+"given filename. If the file exists it will be overwritten. The file\n"
+"should be in TIFF/F format.\n"
+"The \"caller\" option makes the application behave as a calling machine,\n"
+"rather than the answering machine. The default behaviour is to behave as\n"
+"an answering machine.\n"
+"Uses LOCALSTATIONID to identify itself to the remote end.\n"
+"     LOCALHEADERINFO to generate a header line on each page.\n"
+"Sets REMOTESTATIONID to the sender CSID.\n"
+"     FAXPAGES to the number of pages received.\n"
+"     FAXBITRATE to the transmition rate.\n"
+"     FAXRESOLUTION to the resolution.\n"
+"Returns -1 when the user hangs up.\n"
+"Returns 0 otherwise.\n";
+
+STANDARD_LOCAL_USER;
+
+LOCAL_USER_DECL;
+
+#define MAX_BLOCK_SIZE 240
+
+static void span_message(int level, const char *msg)
+{
+    int ast_level;
+    
+    if (level == SPAN_LOG_WARNING)
+        ast_level = __LOG_WARNING;
+    else if (level == SPAN_LOG_WARNING)
+        ast_level = __LOG_WARNING;
+    else
+        ast_level = __LOG_DEBUG;
+    ast_log(ast_level, __FILE__, __LINE__, __PRETTY_FUNCTION__, msg);
+}
+/*- End of function --------------------------------------------------------*/
+
+static void t30_flush(t30_state_t *s, int which)
+{
+    //TODO:
+}
+/*- End of function --------------------------------------------------------*/
+
+static void phase_e_handler(t30_state_t *s, void *user_data, int result)
+{
+    struct ast_channel *chan;
+    t30_stats_t t;
+    char local_ident[21];
+    char far_ident[21];
+    char buf[11];
+    
+    chan = (struct ast_channel *) user_data;
+    if (result == T30_ERR_OK)
+    {
+        t30_get_transfer_statistics(s, &t);
+        t30_get_far_ident(s, far_ident);
+        t30_get_local_ident(s, local_ident);
+        ast_log(LOG_DEBUG, "==============================================================================\n");
+        ast_log(LOG_DEBUG, "Fax successfully received.\n");
+        ast_log(LOG_DEBUG, "Remote station id: %s\n", far_ident);
+        ast_log(LOG_DEBUG, "Local station id:  %s\n", local_ident);
+        ast_log(LOG_DEBUG, "Pages transferred: %i\n", t.pages_transferred);
+        ast_log(LOG_DEBUG, "Image resolution:  %i x %i\n", t.column_resolution, t.row_resolution);
+        ast_log(LOG_DEBUG, "Transfer Rate:     %i\n", t.bit_rate);
+        ast_log(LOG_DEBUG, "==============================================================================\n");
+        manager_event(EVENT_FLAG_CALL,
+                      "FaxReceived", "Channel: %s\nExten: %s\nCallerID: %s\nRemoteStationID: %s\nLocalStationID: %s\nPagesTransferred: %i\nResolution: %i\nTransferRate: %i\nFileName: %s\n",
+                      chan->name,
+                      chan->exten,
+                      (chan->cid.cid_num)  ?  chan->cid.cid_num  :  "",
+                      far_ident,
+                      local_ident,
+                      t.pages_transferred,
+                      t.row_resolution,
+                      t.bit_rate,
+                      s->rx_file);
+        pbx_builtin_setvar_helper(chan, "REMOTESTATIONID", far_ident);
+        snprintf(buf, sizeof(buf), "%i", t.pages_transferred);
+        pbx_builtin_setvar_helper(chan, "FAXPAGES", buf);
+        snprintf(buf, sizeof(buf), "%i", t.row_resolution);
+        pbx_builtin_setvar_helper(chan, "FAXRESOLUTION", buf);
+        snprintf(buf, sizeof(buf), "%i", t.bit_rate);
+        pbx_builtin_setvar_helper(chan, "FAXBITRATE", buf);
+    }
+    else
+    {
+        ast_log(LOG_DEBUG, "==============================================================================\n");
+        ast_log(LOG_DEBUG, "Fax receive not successful - result (%d) %s.\n", result, t30_completion_code_to_str(result));
+        ast_log(LOG_DEBUG, "==============================================================================\n");
+    }
+}
+/*- End of function --------------------------------------------------------*/
+
+static void phase_d_handler(t30_state_t *s, void *user_data, int result)
+{
+    struct ast_channel *chan;
+    t30_stats_t t;
+    
+    chan = (struct ast_channel *) user_data;
+    if (result)
+    {
+        t30_get_transfer_statistics(s, &t);
+        ast_log(LOG_DEBUG, "==============================================================================\n");
+        ast_log(LOG_DEBUG, "Pages transferred:  %i\n", t.pages_transferred);
+        ast_log(LOG_DEBUG, "Image size:         %i x %i\n", t.columns, t.rows);
+        ast_log(LOG_DEBUG, "Image resolution    %i x %i\n", t.column_resolution, t.row_resolution);
+        ast_log(LOG_DEBUG, "Transfer Rate:      %i\n", t.bit_rate);
+        ast_log(LOG_DEBUG, "Bad rows            %i\n", t.bad_rows);
+        ast_log(LOG_DEBUG, "Longest bad row run %i\n", t.longest_bad_row_run);
+        ast_log(LOG_DEBUG, "Compression type    %i\n", t.encoding);
+        ast_log(LOG_DEBUG, "Image size (bytes)  %i\n", t.image_size);
+        ast_log(LOG_DEBUG, "==============================================================================\n");
+    }
+}
+/*- End of function --------------------------------------------------------*/
+
+static int rxfax_exec(struct ast_channel *chan, void *data)
+{
+    int res = 0;
+    char template_file[256];
+    char target_file[256];
+    char *s;
+    char *t;
+    char *v;
+    char *x;
+    int option;
+    int len;
+    int i;
+    t30_state_t fax;
+    int calling_party;
+    int verbose;
+    int samples;
+
+    struct localuser *u;
+    struct ast_frame *inf = NULL;
+    struct ast_frame outf;
+
+    int original_read_fmt;
+    int original_write_fmt;
+    
+    uint8_t __buf[sizeof(uint16_t)*MAX_BLOCK_SIZE + 2*AST_FRIENDLY_OFFSET];
+    uint8_t *buf = __buf + AST_FRIENDLY_OFFSET;
+
+    if (chan == NULL)
+    {
+        ast_log(LOG_WARNING, "Fax receive channel is NULL. Giving up.\n");
+        return -1;
+    }
+
+    span_set_message_handler(span_message);
+
+    /* The next few lines of code parse out the filename and header from the input string */
+    if (data == NULL)
+    {
+        /* No data implies no filename or anything is present */
+        ast_log(LOG_WARNING, "Rxfax requires an argument (filename)\n");
+        return -1;
+    }
+    
+    calling_party = FALSE;
+    verbose = FALSE;
+    target_file[0] = '\0';
+
+    for (option = 0, v = s = data;  v;  option++, s++)
+    {
+        t = s;
+        v = strchr(s, '|');
+        s = (v)  ?  v  :  s + strlen(s);
+        strncpy((char *) buf, t, s - t);
+        buf[s - t] = '\0';
+        if (option == 0)
+        {
+            /* The first option is always the file name */
+            len = s - t;
+            if (len > 255)
+                len = 255;
+            strncpy(target_file, t, len);
+            target_file[len] = '\0';
+            /* Allow the use of %d in the file name for a wild card of sorts, to
+               create a new file with the specified name scheme */
+            if ((x = strchr(target_file, '%'))  &&  x[1] == 'd')
+            {
+                strcpy(template_file, target_file);
+                i = 0;
+                do
+                {
+                    snprintf(target_file, 256, template_file, 1);
+                    i++;
+                }
+                while (ast_fileexists(target_file, "", chan->language) != -1);
+            }
+        }
+        else if (strncmp("caller", t, s - t) == 0)
+        {
+            calling_party = TRUE;
+        }
+        else if (strncmp("debug", t, s - t) == 0)
+        {
+            verbose = TRUE;
+        }
+    }
+
+    /* Done parsing */
+
+    LOCAL_USER_ADD(u);
+
+    if (chan->_state != AST_STATE_UP)
+    {
+        /* Shouldn't need this, but checking to see if channel is already answered
+         * Theoretically asterisk should already have answered before running the app */
+        res = ast_answer(chan);
+    }
+    
+    if (!res)
+    {
+        original_read_fmt = chan->readformat;
+        if (original_read_fmt != AST_FORMAT_SLINEAR)
+        {
+            res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
+            if (res < 0)
+            {
+                ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n");
+                return -1;
+            }
+        }
+        original_write_fmt = chan->writeformat;
+        if (original_write_fmt != AST_FORMAT_SLINEAR)
+        {
+            res = ast_set_write_format(chan, AST_FORMAT_SLINEAR);
+            if (res < 0)
+            {
+                ast_log(LOG_WARNING, "Unable to set to linear write mode, giving up\n");
+                res = ast_set_read_format(chan, original_read_fmt);
+                if (res)
+                    ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
+                return -1;
+            }
+        }
+        fax_init(&fax, calling_party, NULL);
+        if (verbose)
+            fax.logging.level = SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW;
+        x = pbx_builtin_getvar_helper(chan, "LOCALSTATIONID");
+        if (x  &&  x[0])
+            t30_set_local_ident(&fax, x);
+        x = pbx_builtin_getvar_helper(chan, "LOCALHEADERINFO");
+        if (x  &&  x[0])
+            t30_set_header_info(&fax, x);
+        t30_set_rx_file(&fax, target_file, -1);
+        //t30_set_phase_b_handler(&fax, phase_b_handler, chan);
+        t30_set_phase_d_handler(&fax, phase_d_handler, chan);
+        t30_set_phase_e_handler(&fax, phase_e_handler, chan);
+        while (ast_waitfor(chan, -1) > -1)
+        {
+            inf = ast_read(chan);
+            if (inf == NULL)
+            {
+                res = -1;
+                break;
+            }
+            if (inf->frametype == AST_FRAME_VOICE)
+            {
+                if (fax_rx(&fax, inf->data, inf->samples))
+                    break;
+                samples = (inf->samples <= MAX_BLOCK_SIZE)  ?  inf->samples  :  MAX_BLOCK_SIZE;
+                len = fax_tx(&fax, (int16_t *) &buf[AST_FRIENDLY_OFFSET], samples);
+                if (len)
+                {
+                    memset(&outf, 0, sizeof(outf));
+                    outf.frametype = AST_FRAME_VOICE;
+                    outf.subclass = AST_FORMAT_SLINEAR;
+                    outf.datalen = len*sizeof(int16_t);
+                    outf.samples = len;
+                    outf.data = &buf[AST_FRIENDLY_OFFSET];
+                    outf.offset = AST_FRIENDLY_OFFSET;
+                    outf.src = "RxFAX";
+                    if (ast_write(chan, &outf) < 0)
+                    {
+                        ast_log(LOG_WARNING, "Unable to write frame to channel; %s\n", strerror(errno));
+                        break;
+                    }
+                }
+            }
+            ast_frfree(inf);
+        }
+        if (inf == NULL)
+        {
+            ast_log(LOG_DEBUG, "Got hangup\n");
+            res = -1;
+        }
+        if (original_read_fmt != AST_FORMAT_SLINEAR)
+        {
+            res = ast_set_read_format(chan, original_read_fmt);
+            if (res)
+                ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
+        }
+        if (original_write_fmt != AST_FORMAT_SLINEAR)
+        {
+            res = ast_set_write_format(chan, original_write_fmt);
+            if (res)
+                ast_log(LOG_WARNING, "Unable to restore write format on '%s'\n", chan->name);
+        }
+        fax_release(&fax);
+    }
+    else
+    {
+        ast_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name);
+    }
+    LOCAL_USER_REMOVE(u);
+    return res;
+}
+/*- End of function --------------------------------------------------------*/
+
+int unload_module(void)
+{
+    STANDARD_HANGUP_LOCALUSERS;
+    return ast_unregister_application(app);
+}
+/*- End of function --------------------------------------------------------*/
+
+int load_module(void)
+{
+    return ast_register_application(app, rxfax_exec, synopsis, descrip);
+}
+
+char *description(void)
+{
+    return tdesc;
+}
+/*- End of function --------------------------------------------------------*/
+
+int usecount(void)
+{
+    int res;
+    STANDARD_USECOUNT(res);
+    return res;
+}
+/*- End of function --------------------------------------------------------*/
+
+char *key(void)
+{
+    return ASTERISK_GPL_KEY;
+}
+/*- End of function --------------------------------------------------------*/
+/*- End of file ------------------------------------------------------------*/
diff --exclude .svn -urN asterisk-1.2.9.1/apps/app_txfax.c 1.2.9.1/apps/app_txfax.c
--- asterisk-1.2.9.1/apps/app_txfax.c	1970-01-01 01:00:00.000000000 +0100
+++ 1.2.9.1/apps/app_txfax.c	2006-06-12 15:49:55.000000000 +0200
@@ -0,0 +1,313 @@
+/*
+ * Asterisk -- A telephony toolkit for Linux.
+ *
+ * Trivial application to send a TIFF file as a FAX
+ * 
+ * Copyright (C) 2003, Steve Underwood
+ *
+ * Steve Underwood <steveu@coppice.org>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License
+ */
+ 
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <errno.h>
+#include <tiffio.h>
+
+#include <spandsp.h>
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision:$")
+
+#include "asterisk/lock.h"
+#include "asterisk/file.h"
+#include "asterisk/logger.h"
+#include "asterisk/channel.h"
+#include "asterisk/pbx.h"
+#include "asterisk/module.h"
+#include "asterisk/translate.h"
+
+static char *tdesc = "Trivial FAX Transmit Application";
+
+static char *app = "TxFAX";
+
+static char *synopsis = "Send a FAX file";
+
+static char *descrip = 
+"  TxFAX(filename[|caller][|debug]):  Send a given TIFF file to the channel as a FAX.\n"
+"The \"caller\" option makes the application behave as a calling machine,\n"
+"rather than the answering machine. The default behaviour is to behave as\n"
+"an answering machine.\n"
+"Uses LOCALSTATIONID to identify itself to the remote end.\n"
+"     LOCALHEADERINFO to generate a header line on each page.\n"
+"Sets REMOTESTATIONID to the receiver CSID.\n"
+"Returns -1 when the user hangs up, or if the file does not exist.\n"
+"Returns 0 otherwise.\n";
+
+STANDARD_LOCAL_USER;
+
+LOCAL_USER_DECL;
+
+#define MAX_BLOCK_SIZE 240
+
+static void span_message(int level, const char *msg)
+{
+    int ast_level;
+    
+    if (level == SPAN_LOG_WARNING)
+        ast_level = __LOG_WARNING;
+    else if (level == SPAN_LOG_WARNING)
+        ast_level = __LOG_WARNING;
+    else
+        ast_level = __LOG_DEBUG;
+    ast_log(ast_level, __FILE__, __LINE__, __PRETTY_FUNCTION__, msg);
+}
+/*- End of function --------------------------------------------------------*/
+
+static void t30_flush(t30_state_t *s, int which)
+{
+    //TODO:
+}
+/*- End of function --------------------------------------------------------*/
+
+static void phase_e_handler(t30_state_t *s, void *user_data, int result)
+{
+    struct ast_channel *chan;
+    char far_ident[21];
+    
+    chan = (struct ast_channel *) user_data;
+    if (result == T30_ERR_OK)
+    {
+        t30_get_far_ident(s, far_ident);
+        pbx_builtin_setvar_helper(chan, "REMOTESTATIONID", far_ident);
+    }
+    else
+    {
+        ast_log(LOG_DEBUG, "==============================================================================\n");
+        ast_log(LOG_DEBUG, "Fax send not successful - result (%d) %s.\n", result, t30_completion_code_to_str(result));
+        ast_log(LOG_DEBUG, "==============================================================================\n");
+    }
+}
+/*- End of function --------------------------------------------------------*/
+
+static int txfax_exec(struct ast_channel *chan, void *data)
+{
+    int res = 0;
+    char source_file[256];
+    char *x;
+    char *s;
+    char *t;
+    char *v;
+    int option;
+    int len;
+    t30_state_t fax;
+    int calling_party;
+    int verbose;
+    int samples;
+    
+    struct localuser *u;
+    struct ast_frame *inf = NULL;
+    struct ast_frame outf;
+
+    int original_read_fmt;
+    int original_write_fmt;
+    
+    uint8_t __buf[sizeof(uint16_t)*MAX_BLOCK_SIZE + 2*AST_FRIENDLY_OFFSET];
+    uint8_t *buf = __buf + AST_FRIENDLY_OFFSET;
+
+    if (chan == NULL)
+    {
+        ast_log(LOG_WARNING, "Fax transmit channel is NULL. Giving up.\n");
+        return -1;
+    }
+
+    span_set_message_handler(span_message);
+
+    /* The next few lines of code parse out the filename and header from the input string */
+    if (data == NULL)
+    {
+        /* No data implies no filename or anything is present */
+        ast_log(LOG_WARNING, "Txfax requires an argument (filename)\n");
+        return -1;
+    }
+    
+    calling_party = FALSE;
+    verbose = FALSE;
+    source_file[0] = '\0'; 
+
+    for (option = 0, v = s = data;  v;  option++, s++)
+    {
+        t = s;
+        v = strchr(s, '|');
+        s = (v)  ?  v  :  s + strlen(s);
+        strncpy((char *) buf, t, s - t);
+        buf[s - t] = '\0';
+        if (option == 0)
+        {
+            /* The first option is always the file name */
+            len = s - t;
+            if (len > 255)
+                len = 255;
+            strncpy(source_file, t, len);
+            source_file[len] = '\0';
+        }
+        else if (strncmp("caller", t, s - t) == 0)
+        {
+            calling_party = TRUE;
+        }
+        else if (strncmp("debug", t, s - t) == 0)
+        {
+            verbose = TRUE;
+        }
+    }
+
+    /* Done parsing */
+
+    LOCAL_USER_ADD(u);
+
+    if (chan->_state != AST_STATE_UP)
+    {
+        /* Shouldn't need this, but checking to see if channel is already answered
+         * Theoretically asterisk should already have answered before running the app */
+        res = ast_answer(chan);
+    }
+    
+    if (!res)
+    {
+        original_read_fmt = chan->readformat;
+        if (original_read_fmt != AST_FORMAT_SLINEAR)
+        {
+            res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
+            if (res < 0)
+            {
+                ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n");
+                return -1;
+            }
+        }
+        original_write_fmt = chan->writeformat;
+        if (original_write_fmt != AST_FORMAT_SLINEAR)
+        {
+            res = ast_set_write_format(chan, AST_FORMAT_SLINEAR);
+            if (res < 0)
+            {
+                ast_log(LOG_WARNING, "Unable to set to linear write mode, giving up\n");
+                res = ast_set_read_format(chan, original_read_fmt);
+                if (res)
+                    ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
+                return -1;
+            }
+        }
+        fax_init(&fax, calling_party, NULL);
+        if (verbose)
+	    fax.logging.level = SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW;
+
+        x = pbx_builtin_getvar_helper(chan, "LOCALSTATIONID");
+        if (x  &&  x[0])
+            t30_set_local_ident(&fax, x);
+        x = pbx_builtin_getvar_helper(chan, "LOCALHEADERINFO");
+        if (x  &&  x[0])
+            t30_set_header_info(&fax, x);
+        t30_set_tx_file(&fax, source_file, -1, -1);
+        //t30_set_phase_b_handler(&fax, phase_b_handler, chan);
+        //t30_set_phase_d_handler(&fax, phase_d_handler, chan);
+        t30_set_phase_e_handler(&fax, phase_e_handler, chan);
+        while (ast_waitfor(chan, -1) > -1)
+        {
+            inf = ast_read(chan);
+            if (inf == NULL)
+            {
+                res = -1;
+                break;
+            }
+            if (inf->frametype == AST_FRAME_VOICE)
+            {
+                if (fax_rx(&fax, inf->data, inf->samples))
+                    break;
+                samples = (inf->samples <= MAX_BLOCK_SIZE)  ?  inf->samples  :  MAX_BLOCK_SIZE;
+                len = fax_tx(&fax, (int16_t *) &buf[AST_FRIENDLY_OFFSET], samples);
+                if (len)
+                {
+                    memset(&outf, 0, sizeof(outf));
+                    outf.frametype = AST_FRAME_VOICE;
+                    outf.subclass = AST_FORMAT_SLINEAR;
+                    outf.datalen = len*sizeof(int16_t);
+                    outf.samples = len;
+                    outf.data = &buf[AST_FRIENDLY_OFFSET];
+                    outf.offset = AST_FRIENDLY_OFFSET;
+                    if (ast_write(chan, &outf) < 0)
+                    {
+                        ast_log(LOG_WARNING, "Unable to write frame to channel; %s\n", strerror(errno));
+                        break;
+                    }
+                }
+            }
+            ast_frfree(inf);
+        }
+        if (inf == NULL)
+        {
+            ast_log(LOG_DEBUG, "Got hangup\n");
+            res = -1;
+        }
+        if (original_read_fmt != AST_FORMAT_SLINEAR)
+        {
+            res = ast_set_read_format(chan, original_read_fmt);
+            if (res)
+                ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
+        }
+        if (original_write_fmt != AST_FORMAT_SLINEAR)
+        {
+            res = ast_set_write_format(chan, original_write_fmt);
+            if (res)
+                ast_log(LOG_WARNING, "Unable to restore write format on '%s'\n", chan->name);
+        }
+        fax_release(&fax);
+    }
+    else
+    {
+        ast_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name);
+    }
+    LOCAL_USER_REMOVE(u);
+    return res;
+}
+/*- End of function --------------------------------------------------------*/
+
+int unload_module(void)
+{
+    STANDARD_HANGUP_LOCALUSERS;
+    return ast_unregister_application(app);
+}
+/*- End of function --------------------------------------------------------*/
+
+int load_module(void)
+{
+    return ast_register_application(app, txfax_exec, synopsis, descrip);
+}
+/*- End of function --------------------------------------------------------*/
+
+char *description(void)
+{
+    return tdesc;
+}
+/*- End of function --------------------------------------------------------*/
+
+int usecount(void)
+{
+    int res;
+
+    STANDARD_USECOUNT(res);
+    return res;
+}
+/*- End of function --------------------------------------------------------*/
+
+char *key(void)
+{
+    return ASTERISK_GPL_KEY;
+}
+/*- End of function --------------------------------------------------------*/
+/*- End of file ------------------------------------------------------------*/
diff --exclude .svn -urN asterisk-1.2.9.1/channel.c 1.2.9.1/channel.c
--- asterisk-1.2.9.1/channel.c	2006-06-01 22:27:50.000000000 +0200
+++ 1.2.9.1/channel.c	2006-06-12 15:49:58.000000000 +0200
@@ -956,6 +956,11 @@
 	while ((vardata = AST_LIST_REMOVE_HEAD(headp, entries)))
 		ast_var_delete(vardata);
 
+#ifdef AST_JB
+	/* Destroy the jitterbuffer */
+	ast_jb_destroy(chan);
+#endif /* AST_JB */
+
 	free(chan);
 	ast_mutex_unlock(&chlock);
 
@@ -3228,6 +3233,10 @@
 	int watch_c1_dtmf;
 	void *pvt0, *pvt1;
 	int to;
+#ifdef AST_JB
+	/* Indicates whether a frame was queued into a jitterbuffer */
+	int frame_put_in_jb;
+#endif /* AST_JB */
 	
 	cs[0] = c0;
 	cs[1] = c1;
@@ -3238,6 +3247,11 @@
 	watch_c0_dtmf = config->flags & AST_BRIDGE_DTMF_CHANNEL_0;
 	watch_c1_dtmf = config->flags & AST_BRIDGE_DTMF_CHANNEL_1;
 
+#ifdef AST_JB
+	/* Check the need of a jitterbuffer for each channel */
+	ast_jb_do_usecheck(c0, c1);
+#endif /* AST_JB */
+
 	for (;;) {
 		if ((c0->tech_pvt != pvt0) || (c1->tech_pvt != pvt1) ||
 		    (o0nativeformats != c0->nativeformats) ||
@@ -3254,8 +3268,17 @@
 			}
 		} else
 			to = -1;
+#ifdef AST_JB
+		/* Calculate the appropriate max sleep interval - in general, this is the time,
+		   left to the closest jb delivery moment */
+		to = ast_jb_get_when_to_wakeup(c0, c1, to);
+#endif /* AST_JB */
 		who = ast_waitfor_n(cs, 2, &to);
 		if (!who) {
+#ifdef AST_JB
+			/* No frame received within the specified timeout - check if we have to deliver now */
+			ast_jb_get_and_deliver(c0, c1);
+#endif /* AST_JB */
 			ast_log(LOG_DEBUG, "Nobody there, continuing...\n"); 
 			if (c0->_softhangup == AST_SOFTHANGUP_UNBRIDGE || c1->_softhangup == AST_SOFTHANGUP_UNBRIDGE) {
 				if (c0->_softhangup == AST_SOFTHANGUP_UNBRIDGE)
@@ -3276,6 +3299,11 @@
 			break;
 		}
 
+#ifdef AST_JB
+		/* Try add the frame info the who's bridged channel jitterbuff */
+		frame_put_in_jb = !ast_jb_put((who == c0) ? c1 : c0, f);
+#endif /* AST_JB */
+
 		if ((f->frametype == AST_FRAME_CONTROL) && !(config->flags & AST_BRIDGE_IGNORE_SIGS)) {
 			if ((f->subclass == AST_CONTROL_HOLD) || (f->subclass == AST_CONTROL_UNHOLD) ||
 			    (f->subclass == AST_CONTROL_VIDUPDATE)) {
@@ -3313,7 +3341,18 @@
 				last = who;
 #endif
 tackygoto:
+#ifdef AST_JB
+				/* Write immediately frames, not passed through jb */
+				if(!frame_put_in_jb)
+				{
+					ast_write((who == c0) ? c1 : c0, f);
+				}
+				
+				/* Check if we have to deliver now */
+				ast_jb_get_and_deliver(c0, c1);
+#else /* AST_JB */
 				ast_write((who == c0) ? c1 : c0, f);
+#endif /* AST_JB */
 			}
 		}
 		ast_frfree(f);
diff --exclude .svn -urN asterisk-1.2.9.1/channels/chan_iax2.c 1.2.9.1/channels/chan_iax2.c
--- asterisk-1.2.9.1/channels/chan_iax2.c	2006-06-06 17:48:00.000000000 +0200
+++ 1.2.9.1/channels/chan_iax2.c	2006-06-12 15:49:55.000000000 +0200
@@ -1414,6 +1414,9 @@
 	  the IAX thread with the iaxsl lock held. */
 	struct iax_frame *fr = data;
 	fr->retrans = -1;
+#ifdef AST_JB
+	fr->af.has_timing_info = 0;
+#endif /* AST_JB */
 	if (iaxs[fr->callno] && !ast_test_flag(iaxs[fr->callno], IAX_ALREADYGONE))
 		iax2_queue_frame(fr->callno, &fr->af);
 	/* Free our iax frame */
diff --exclude .svn -urN asterisk-1.2.9.1/channels/chan_sip.c 1.2.9.1/channels/chan_sip.c
--- asterisk-1.2.9.1/channels/chan_sip.c	2006-05-25 19:18:01.000000000 +0200
+++ 1.2.9.1/channels/chan_sip.c	2006-06-13 11:08:36.000000000 +0200
@@ -141,6 +141,19 @@
 #define DEBUG_READ	0			/* Recieved data	*/
 #define DEBUG_SEND	1			/* Transmit data	*/
 
+#ifdef AST_JB
+#include "asterisk/abstract_jb.h"
+/* Global jitterbuffer configuration - by default, jb is disabled */
+static struct ast_jb_conf default_jbconf =
+{
+	.flags = 0,
+	.max_size = -1,
+	.resync_threshold = -1,
+	.impl = ""
+};
+static struct ast_jb_conf global_jbconf;
+#endif /* AST_JB */
+
 static const char desc[] = "Session Initiation Protocol (SIP)";
 static const char channeltype[] = "SIP";
 static const char config[] = "sip.conf";
@@ -697,6 +710,9 @@
 	struct ast_variable *chanvars;		/*!< Channel variables to set for call */
 	struct sip_pvt *next;			/*!< Next call in chain */
 	struct sip_invite_param *options;	/*!< Options for INVITE */
+#ifdef AST_JB
+	struct ast_jb_conf jbconf;
+#endif /* AST_JB */
 } *iflist = NULL;
 
 #define FLAG_RESPONSE (1 << 0)
@@ -936,7 +952,11 @@
 	.type = channeltype,
 	.description = "Session Initiation Protocol (SIP)",
 	.capabilities = ((AST_FORMAT_MAX_AUDIO << 1) - 1),
+#ifdef AST_JB
+	.properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER,
+#else /* AST_JB */
 	.properties = AST_CHAN_TP_WANTSJITTER,
+#endif /* AST_JB */
 	.requester = sip_request_call,
 	.devicestate = sip_devicestate,
 	.call = sip_call,
@@ -2857,6 +2877,14 @@
 	for (v = i->chanvars ; v ; v = v->next)
 		pbx_builtin_setvar_helper(tmp,v->name,v->value);
 				
+#ifdef AST_JB
+	/* Configure the new channel jb */
+	if(tmp != NULL && i != NULL && i->rtp != NULL)
+	{
+		ast_jb_configure(tmp, &i->jbconf);
+	}
+#endif /* AST_JB */
+				
 	return tmp;
 }
 
@@ -3138,6 +3166,11 @@
 		p->noncodeccapability |= AST_RTP_DTMF;
 	strcpy(p->context, default_context);
 
+#ifdef AST_JB
+	/* Assign default jb conf to the new sip_pvt */
+	memcpy(&p->jbconf, &global_jbconf, sizeof(struct ast_jb_conf));
+#endif /* AST_JB */
+
 	/* Add to active dialog list */
 	ast_mutex_lock(&iflock);
 	p->next = iflist;
@@ -5794,7 +5827,7 @@
 	if (contact)
 		ast_copy_string(peer->fullcontact, contact, sizeof(peer->fullcontact));
 
-	if (option_verbose > 2)
+	if (option_verbose > 3)
 		ast_verbose(VERBOSE_PREFIX_3 "SIP Seeding peer from astdb: '%s' at %s@%s:%d for %d\n",
 			    peer->name, peer->username, ast_inet_ntoa(iabuf, sizeof(iabuf), in), port, expiry);
 
@@ -5953,7 +5986,7 @@
 		p->sipoptions = 0;
 		p->lastms = 0;
 
-		if (option_verbose > 2)
+		if (option_verbose > 3)
 			ast_verbose(VERBOSE_PREFIX_3 "Unregistered SIP '%s'\n", p->name);
 			manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: SIP/%s\r\nPeerStatus: Unregistered\r\n", p->name);
 		return PARSE_REGISTER_UPDATE;
@@ -6024,7 +6057,7 @@
 	manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: SIP/%s\r\nPeerStatus: Registered\r\n", p->name);
 	if (inaddrcmp(&p->addr, &oldsin)) {
 		sip_poke_peer(p);
-		if (option_verbose > 2)
+		if (option_verbose > 3)
 			ast_verbose(VERBOSE_PREFIX_3 "Registered SIP '%s' at %s port %d expires %d\n", p->name, ast_inet_ntoa(iabuf, sizeof(iabuf), p->addr.sin_addr), ntohs(p->addr.sin_port), expiry);
 		register_peer_exten(p, 1);
 	}
@@ -12541,6 +12574,11 @@
 	tos = 0;
 	expiry = DEFAULT_EXPIRY;
 	global_allowguest = 1;
+	
+#ifdef AST_JB
+	/* Copy the default jb config over global_jbconf */
+	memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
+#endif /* AST_JB */
 
 	/* Read the [general] config section of sip.conf (or from realtime config) */
 	v = ast_variable_browse(cfg, "general");
@@ -12549,6 +12587,14 @@
 			v = v->next;
 			continue;
 		}
+#ifdef AST_JB
+		/* handle jb conf */
+		if(ast_jb_read_conf(&global_jbconf, v->name, v->value) == 0)
+		{
+			v = v->next;
+			continue;
+		}
+#endif /* AST_JB */
 
 		/* Create the interface list */
 		if (!strcasecmp(v->name, "context")) {
diff --exclude .svn -urN asterisk-1.2.9.1/channels/chan_zap.c 1.2.9.1/channels/chan_zap.c
--- asterisk-1.2.9.1/channels/chan_zap.c	2006-05-31 22:26:17.000000000 +0200
+++ 1.2.9.1/channels/chan_zap.c	2006-06-12 15:49:55.000000000 +0200
@@ -97,6 +97,19 @@
 #include "asterisk/utils.h"
 #include "asterisk/transcap.h"
 
+#ifdef AST_JB
+#include "asterisk/abstract_jb.h"
+/* Global jitterbuffer configuration - by default, jb is disabled */
+static struct ast_jb_conf default_jbconf =
+{
+	.flags = 0,
+	.max_size = -1,
+	.resync_threshold = -1,
+	.impl = ""
+};
+static struct ast_jb_conf global_jbconf;
+#endif /* AST_JB */
+
 #ifndef ZT_SIG_EM_E1
 #error "Your zaptel is too old.  please cvs update"
 #endif
@@ -686,6 +699,9 @@
 #endif	
 	int polarity;
 	int dsp_features;
+#ifdef AST_JB
+	struct ast_jb_conf jbconf;
+#endif /* AST_JB */
 
 } *iflist = NULL, *ifend = NULL;
 
@@ -5149,6 +5165,13 @@
 		}
 	} else
 		ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
+#ifdef AST_JB
+	/* Configure the new channel jb */
+	if(tmp != NULL && i != NULL)
+	{
+		ast_jb_configure(tmp, &i->jbconf);
+	}
+#endif /* AST_JB */
 	return tmp;
 }
 
@@ -6869,6 +6892,10 @@
 		for (x=0;x<3;x++)
 			tmp->subs[x].zfd = -1;
 		tmp->channel = channel;
+#ifdef AST_JB
+		/* Assign default jb conf to the new zt_pvt */
+		memcpy(&tmp->jbconf, &global_jbconf, sizeof(struct ast_jb_conf));
+#endif /* AST_JB */
 	}
 
 	if (tmp) {
@@ -10135,6 +10162,9 @@
 {
 	struct ast_config *cfg;
 	struct ast_variable *v;
+#ifdef AST_JB
+	struct ast_variable *vjb;
+#endif /* AST_JB */
 	struct zt_pvt *tmp;
 	char *chan;
 	char *c;
@@ -10227,6 +10257,17 @@
 	}
 #endif
 	v = ast_variable_browse(cfg, "channels");
+#ifdef AST_JB
+	/* Copy the default jb config over global_jbconf */
+	memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
+	/* Traverse all variables to handle jb conf */
+	vjb = v;
+	while(vjb)
+	{
+		ast_jb_read_conf(&global_jbconf, vjb->name, vjb->value);
+		vjb = vjb->next;
+	}
+#endif /* AST_JB */
 	while(v) {
 		/* Create the interface list */
 		if (!strcasecmp(v->name, "channel")
diff --exclude .svn -urN asterisk-1.2.9.1/codecs/Makefile 1.2.9.1/codecs/Makefile
--- asterisk-1.2.9.1/codecs/Makefile	2005-11-29 19:24:39.000000000 +0100
+++ 1.2.9.1/codecs/Makefile	2006-06-12 15:49:58.000000000 +0200
@@ -118,6 +118,9 @@
 codec_lpc10.so: codec_lpc10.o $(LIBLPC10)
 	$(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} $(LIBLPC10) -lm
 
+codec_g726.so: codec_g726.o
+	$(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} -lspandsp -lm
+
 %.so : %.o
 	$(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB}
 
diff --exclude .svn -urN asterisk-1.2.9.1/codecs/codec_g726.c 1.2.9.1/codecs/codec_g726.c
--- asterisk-1.2.9.1/codecs/codec_g726.c	2005-11-29 19:24:39.000000000 +0100
+++ 1.2.9.1/codecs/codec_g726.c	2006-06-12 15:49:58.000000000 +0200
@@ -1,18 +1,9 @@
 /*
  * Asterisk -- An open source telephony toolkit.
  *
- * Copyright (C) 1999 - 2005, Digium, Inc.
+ * Copyright (C) 2006 Steve Underwood <steveu@coppice.org>
  *
- * Mark Spencer <markster@digium.com>
- *
- * Based on frompcm.c and topcm.c from the Emiliano MIPL browser/
- * interpreter.  See http://www.bsdtelephony.com.mx
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
+ * Based on the g726 code for Asterisk by Mark Spencer <markster@digium.com>
  *
  * This program is free software, distributed under the terms of
  * the GNU General Public License Version 2. See the LICENSE file
@@ -34,6 +25,8 @@
 #include <string.h>
 #include <unistd.h>
 
+#include <spandsp.h>
+
 #include "asterisk.h"
 
 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 7221 $")
@@ -46,651 +39,44 @@
 #include "asterisk/translate.h"
 #include "asterisk/channel.h"
 
-#define WANT_ASM
-#include "log2comp.h"
-
-/* define NOT_BLI to use a faster but not bit-level identical version */
-/* #define NOT_BLI */
-
-#if defined(NOT_BLI)
-#	if defined(_MSC_VER)
-typedef __int64 sint64;
-#	elif defined(__GNUC__)
-typedef long long sint64;
-#	else
-#		error 64-bit integer type is not defined for your compiler/platform
-#	endif
-#endif
-
-#define BUFFER_SIZE   8096	/* size for the translation buffers */
-#define BUF_SHIFT	5
+#define BUFFER_SIZE   8096	/* Size for the translation buffers */
 
 AST_MUTEX_DEFINE_STATIC(localuser_lock);
 static int localusecnt = 0;
 
-static char *tdesc = "ITU G.726-32kbps G726 Transcoder";
+static const char *tdesc = "ITU G.726-32kbps G.726 transcoder";
 
 static int useplc = 0;
 
-/* Sample frame data */
-
-#include "slin_g726_ex.h"
-#include "g726_slin_ex.h"
-
-/*
- * The following is the definition of the state structure
- * used by the G.721/G.723 encoder and decoder to preserve their internal
- * state between successive calls.  The meanings of the majority
- * of the state structure fields are explained in detail in the
- * CCITT Recommendation G.721.  The field names are essentially indentical
- * to variable names in the bit level description of the coding algorithm
- * included in this Recommendation.
- */
-struct g726_state {
-	long yl;	/* Locked or steady state step size multiplier. */
-	int yu;		/* Unlocked or non-steady state step size multiplier. */
-	int dms;	/* Short term energy estimate. */
-	int dml;	/* Long term energy estimate. */
-	int ap;		/* Linear weighting coefficient of 'yl' and 'yu'. */
-
-	int a[2];	/* Coefficients of pole portion of prediction filter.
-				 * stored as fixed-point 1==2^14 */
-	int b[6];	/* Coefficients of zero portion of prediction filter.
-				 * stored as fixed-point 1==2^14 */
-	int pk[2];	/* Signs of previous two samples of a partially
-			 * reconstructed signal.
-			 */
-	int dq[6];  /* Previous 6 samples of the quantized difference signal
-				 * stored as fixed point 1==2^12,
-				 * or in internal floating point format */
-	int sr[2];	/* Previous 2 samples of the quantized difference signal
-				 * stored as fixed point 1==2^12,
-				 * or in internal floating point format */
-	int td;	/* delayed tone detect, new in 1988 version */
-};
-
-
-
-static int qtab_721[7] = {-124, 80, 178, 246, 300, 349, 400};
-/*
- * Maps G.721 code word to reconstructed scale factor normalized log
- * magnitude values.
- */
-static int _dqlntab[16] = {-2048, 4, 135, 213, 273, 323, 373, 425,
-				425, 373, 323, 273, 213, 135, 4, -2048};
-
-/* Maps G.721 code word to log of scale factor multiplier. */
-static int _witab[16] = {-12, 18, 41, 64, 112, 198, 355, 1122,
-				1122, 355, 198, 112, 64, 41, 18, -12};
-/*
- * Maps G.721 code words to a set of values whose long and short
- * term averages are computed and then compared to give an indication
- * how stationary (steady state) the signal is.
- */
-static int _fitab[16] = {0, 0, 0, 0x200, 0x200, 0x200, 0x600, 0xE00,
-				0xE00, 0x600, 0x200, 0x200, 0x200, 0, 0, 0};
-
-/* Deprecated
-static int power2[15] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80,
-			0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000};
-*/
-
-/*
- * g72x_init_state()
- *
- * This routine initializes and/or resets the g726_state structure
- * pointed to by 'state_ptr'.
- * All the initial state values are specified in the CCITT G.721 document.
- */
-static void g726_init_state(struct g726_state *state_ptr)
-{
-	int		cnta;
-
-	state_ptr->yl = 34816;
-	state_ptr->yu = 544;
-	state_ptr->dms = 0;
-	state_ptr->dml = 0;
-	state_ptr->ap = 0;
-	for (cnta = 0; cnta < 2; cnta++)
-	{
-		state_ptr->a[cnta] = 0;
-		state_ptr->pk[cnta] = 0;
-#ifdef NOT_BLI
-		state_ptr->sr[cnta] = 1;
-#else
-		state_ptr->sr[cnta] = 32;
-#endif
-	}
-	for (cnta = 0; cnta < 6; cnta++)
-	{
-		state_ptr->b[cnta] = 0;
-#ifdef NOT_BLI
-		state_ptr->dq[cnta] = 1;
-#else
-		state_ptr->dq[cnta] = 32;
-#endif
-	}
-	state_ptr->td = 0;
-}
-
-/*
- * quan()
- *
- * quantizes the input val against the table of integers.
- * It returns i if table[i - 1] <= val < table[i].
- *
- * Using linear search for simple coding.
- */
-static int quan(int val, int *table, int size)
+/* 10ms of linear silence, at 8k samples/second */
+static const int16_t slin_g726_ex[] =
 {
-	int		i;
-
-	for (i = 0; i < size && val >= *table; ++i, ++table)
-		;
-	return (i);
-}
-
-#ifdef NOT_BLI /* faster non-identical version */
-
-/*
- * predictor_zero()
- *
- * computes the estimated signal from 6-zero predictor.
- *
- */
-static int predictor_zero(struct g726_state *state_ptr)
-{	/* divide by 2 is necessary here to handle negative numbers correctly */
-	int i;
-	sint64 sezi;
-	for (sezi = 0, i = 0; i < 6; i++)			/* ACCUM */
-		sezi += (sint64)state_ptr->b[i] * state_ptr->dq[i];
-	return (int)(sezi >> 13) / 2 /* 2^14 */;
-}
-
-/*
- * predictor_pole()
- *
- * computes the estimated signal from 2-pole predictor.
- *
- */
-static int predictor_pole(struct g726_state *state_ptr)
-{	/* divide by 2 is necessary here to handle negative numbers correctly */
-	return (int)(((sint64)state_ptr->a[1] * state_ptr->sr[1] +
-	              (sint64)state_ptr->a[0] * state_ptr->sr[0]) >> 13) / 2 /* 2^14 */;
-}
-
-#else /* NOT_BLI - identical version */
-/*
- * fmult()
- *
- * returns the integer product of the fixed-point number "an" (1==2^12) and
- * "floating point" representation (4-bit exponent, 6-bit mantessa) "srn".
- */
-static int fmult(int an, int srn)
-{
-	int		anmag, anexp, anmant;
-	int		wanexp, wanmant;
-	int		retval;
-
-	anmag = (an > 0) ? an : ((-an) & 0x1FFF);
-	anexp = ilog2(anmag) - 5;
-	anmant = (anmag == 0) ? 32 :
-	    (anexp >= 0) ? anmag >> anexp : anmag << -anexp;
-	wanexp = anexp + ((srn >> 6) & 0xF) - 13;
-
-	wanmant = (anmant * (srn & 077) + 0x30) >> 4;
-	retval = (wanexp >= 0) ? ((wanmant << wanexp) & 0x7FFF) :
-	    (wanmant >> -wanexp);
-
-	return (((an ^ srn) < 0) ? -retval : retval);
-}
-
-static int predictor_zero(struct g726_state *state_ptr)
-{
-	int		i;
-	int		sezi;
-	for (sezi = 0, i = 0; i < 6; i++)			/* ACCUM */
-		sezi += fmult(state_ptr->b[i] >> 2, state_ptr->dq[i]);
-	return sezi;
-}
-
-static int predictor_pole(struct g726_state *state_ptr)
-{
-	return (fmult(state_ptr->a[1] >> 2, state_ptr->sr[1]) +
-			fmult(state_ptr->a[0] >> 2, state_ptr->sr[0]));
-}
-
-#endif /* NOT_BLI */
-
-/*
- * step_size()
- *
- * computes the quantization step size of the adaptive quantizer.
- *
- */
-static int step_size(struct g726_state *state_ptr)
-{
-	int		y;
-	int		dif;
-	int		al;
-
-	if (state_ptr->ap >= 256)
-		return (state_ptr->yu);
-	else {
-		y = state_ptr->yl >> 6;
-		dif = state_ptr->yu - y;
-		al = state_ptr->ap >> 2;
-		if (dif > 0)
-			y += (dif * al) >> 6;
-		else if (dif < 0)
-			y += (dif * al + 0x3F) >> 6;
-		return (y);
-	}
-}
-
-/*
- * quantize()
- *
- * Given a raw sample, 'd', of the difference signal and a
- * quantization step size scale factor, 'y', this routine returns the
- * ADPCM codeword to which that sample gets quantized.  The step
- * size scale factor division operation is done in the log base 2 domain
- * as a subtraction.
- */
-static int quantize(
-	int		d,	/* Raw difference signal sample */
-	int		y,	/* Step size multiplier */
-	int		*table,	/* quantization table */
-	int		size)	/* table size of integers */
-{
-	int		dqm;	/* Magnitude of 'd' */
-	int		exp;	/* Integer part of base 2 log of 'd' */
-	int		mant;	/* Fractional part of base 2 log */
-	int		dl;		/* Log of magnitude of 'd' */
-	int		dln;	/* Step size scale factor normalized log */
-	int		i;
-
-	/*
-	 * LOG
-	 *
-	 * Compute base 2 log of 'd', and store in 'dl'.
-	 */
-	dqm = abs(d);
-	exp = ilog2(dqm);
-	if (exp < 0)
-		exp = 0;
-	mant = ((dqm << 7) >> exp) & 0x7F;	/* Fractional portion. */
-	dl = (exp << 7) | mant;
-
-	/*
-	 * SUBTB
-	 *
-	 * "Divide" by step size multiplier.
-	 */
-	dln = dl - (y >> 2);
-
-	/*
-	 * QUAN
-	 *
-	 * Obtain codword i for 'd'.
-	 */
-	i = quan(dln, table, size);
-	if (d < 0)			/* take 1's complement of i */
-		return ((size << 1) + 1 - i);
-	else if (i == 0)		/* take 1's complement of 0 */
-		return ((size << 1) + 1); /* new in 1988 */
-	else
-		return (i);
-}
-
-/*
- * reconstruct()
- *
- * Returns reconstructed difference signal 'dq' obtained from
- * codeword 'i' and quantization step size scale factor 'y'.
- * Multiplication is performed in log base 2 domain as addition.
- */
-static int reconstruct(
-	int		sign,	/* 0 for non-negative value */
-	int		dqln,	/* G.72x codeword */
-	int		y)	/* Step size multiplier */
-{
-	int		dql;	/* Log of 'dq' magnitude */
-	int		dex;	/* Integer part of log */
-	int		dqt;
-	int		dq;	/* Reconstructed difference signal sample */
-
-	dql = dqln + (y >> 2);	/* ADDA */
-
-	if (dql < 0) {
-#ifdef NOT_BLI
-		return (sign) ? -1 : 1;
-#else
-		return (sign) ? -0x8000 : 0;
-#endif
-	} else {		/* ANTILOG */
-		dex = (dql >> 7) & 15;
-		dqt = 128 + (dql & 127);
-#ifdef NOT_BLI
-		dq = ((dqt << 19) >> (14 - dex));
-		return (sign) ? -dq : dq;
-#else
-		dq = (dqt << 7) >> (14 - dex);
-		return (sign) ? (dq - 0x8000) : dq;
-#endif
-	}
-}
-
-/*
- * update()
- *
- * updates the state variables for each output code
- */
-static void update(
-	int		code_size,	/* distinguish 723_40 with others */
-	int		y,		/* quantizer step size */
-	int		wi,		/* scale factor multiplier */
-	int		fi,		/* for long/short term energies */
-	int		dq,		/* quantized prediction difference */
-	int		sr,		/* reconstructed signal */
-	int		dqsez,		/* difference from 2-pole predictor */
-	struct g726_state *state_ptr)	/* coder state pointer */
-{
-	int		cnt;
-	int		mag;		/* Adaptive predictor, FLOAT A */
-#ifndef NOT_BLI
-	int		exp;
-#endif
-	int		a2p=0;		/* LIMC */
-	int		a1ul;		/* UPA1 */
-	int		pks1;		/* UPA2 */
-	int		fa1;
-	int		tr;			/* tone/transition detector */
-	int		ylint, thr2, dqthr;
-	int		ylfrac, thr1;
-	int		pk0;
-
-	pk0 = (dqsez < 0) ? 1 : 0;	/* needed in updating predictor poles */
-
-#ifdef NOT_BLI
-	mag = abs(dq / 0x1000); /* prediction difference magnitude */
-#else
-	mag = dq & 0x7FFF;		/* prediction difference magnitude */
-#endif
-	/* TRANS */
-	ylint = state_ptr->yl >> 15;	/* exponent part of yl */
-	ylfrac = (state_ptr->yl >> 10) & 0x1F;	/* fractional part of yl */
-	thr1 = (32 + ylfrac) << ylint;		/* threshold */
-	thr2 = (ylint > 9) ? 31 << 10 : thr1;	/* limit thr2 to 31 << 10 */
-	dqthr = (thr2 + (thr2 >> 1)) >> 1;	/* dqthr = 0.75 * thr2 */
-	if (state_ptr->td == 0)		/* signal supposed voice */
-		tr = 0;
-	else if (mag <= dqthr)		/* supposed data, but small mag */
-		tr = 0;			/* treated as voice */
-	else				/* signal is data (modem) */
-		tr = 1;
-
-	/*
-	 * Quantizer scale factor adaptation.
-	 */
-
-	/* FUNCTW & FILTD & DELAY */
-	/* update non-steady state step size multiplier */
-	state_ptr->yu = y + ((wi - y) >> 5);
-
-	/* LIMB */
-	if (state_ptr->yu < 544)	/* 544 <= yu <= 5120 */
-		state_ptr->yu = 544;
-	else if (state_ptr->yu > 5120)
-		state_ptr->yu = 5120;
-
-	/* FILTE & DELAY */
-	/* update steady state step size multiplier */
-	state_ptr->yl += state_ptr->yu + ((-state_ptr->yl) >> 6);
-
-	/*
-	 * Adaptive predictor coefficients.
-	 */
-	if (tr == 1) {			/* reset a's and b's for modem signal */
-		state_ptr->a[0] = 0;
-		state_ptr->a[1] = 0;
-		state_ptr->b[0] = 0;
-		state_ptr->b[1] = 0;
-		state_ptr->b[2] = 0;
-		state_ptr->b[3] = 0;
-		state_ptr->b[4] = 0;
-		state_ptr->b[5] = 0;
-	} else {			/* update a's and b's */
-		pks1 = pk0 ^ state_ptr->pk[0];		/* UPA2 */
-
-		/* update predictor pole a[1] */
-		a2p = state_ptr->a[1] - (state_ptr->a[1] >> 7);
-		if (dqsez != 0) {
-			fa1 = (pks1) ? state_ptr->a[0] : -state_ptr->a[0];
-			if (fa1 < -8191)	/* a2p = function of fa1 */
-				a2p -= 0x100;
-			else if (fa1 > 8191)
-				a2p += 0xFF;
-			else
-				a2p += fa1 >> 5;
-
-			if (pk0 ^ state_ptr->pk[1])
-				/* LIMC */
-				if (a2p <= -12160)
-					a2p = -12288;
-				else if (a2p >= 12416)
-					a2p = 12288;
-				else
-					a2p -= 0x80;
-			else if (a2p <= -12416)
-				a2p = -12288;
-			else if (a2p >= 12160)
-				a2p = 12288;
-			else
-				a2p += 0x80;
-		}
-
-		/* TRIGB & DELAY */
-		state_ptr->a[1] = a2p;
-
-		/* UPA1 */
-		/* update predictor pole a[0] */
-		state_ptr->a[0] -= state_ptr->a[0] >> 8;
-		if (dqsez != 0) {
-			if (pks1 == 0)
-				state_ptr->a[0] += 192;
-			else
-				state_ptr->a[0] -= 192;
-		}
-		/* LIMD */
-		a1ul = 15360 - a2p;
-		if (state_ptr->a[0] < -a1ul)
-			state_ptr->a[0] = -a1ul;
-		else if (state_ptr->a[0] > a1ul)
-			state_ptr->a[0] = a1ul;
-
-		/* UPB : update predictor zeros b[6] */
-		for (cnt = 0; cnt < 6; cnt++) {
-			if (code_size == 5)		/* for 40Kbps G.723 */
-				state_ptr->b[cnt] -= state_ptr->b[cnt] >> 9;
-			else			/* for G.721 and 24Kbps G.723 */
-				state_ptr->b[cnt] -= state_ptr->b[cnt] >> 8;
-			if (mag)
-			{	/* XOR */
-				if ((dq ^ state_ptr->dq[cnt]) >= 0)
-					state_ptr->b[cnt] += 128;
-				else
-					state_ptr->b[cnt] -= 128;
-			}
-		}
-	}
-
-	for (cnt = 5; cnt > 0; cnt--)
-		state_ptr->dq[cnt] = state_ptr->dq[cnt-1];
-#ifdef NOT_BLI
-	state_ptr->dq[0] = dq;
-#else
-	/* FLOAT A : convert dq[0] to 4-bit exp, 6-bit mantissa f.p. */
-	if (mag == 0) {
-		state_ptr->dq[0] = (dq >= 0) ? 0x20 : 0x20 - 0x400;
-	} else {
-		exp = ilog2(mag) + 1;
-		state_ptr->dq[0] = (dq >= 0) ?
-		    (exp << 6) + ((mag << 6) >> exp) :
-		    (exp << 6) + ((mag << 6) >> exp) - 0x400;
-	}
-#endif
-
-	state_ptr->sr[1] = state_ptr->sr[0];
-#ifdef NOT_BLI
-	state_ptr->sr[0] = sr;
-#else
-	/* FLOAT B : convert sr to 4-bit exp., 6-bit mantissa f.p. */
-	if (sr == 0) {
-		state_ptr->sr[0] = 0x20;
-	} else if (sr > 0) {
-		exp = ilog2(sr) + 1;
-		state_ptr->sr[0] = (exp << 6) + ((sr << 6) >> exp);
-	} else if (sr > -0x8000) {
-		mag = -sr;
-		exp = ilog2(mag) + 1;
-		state_ptr->sr[0] =  (exp << 6) + ((mag << 6) >> exp) - 0x400;
-	} else
-		state_ptr->sr[0] = 0x20 - 0x400;
-#endif
-
-	/* DELAY A */
-	state_ptr->pk[1] = state_ptr->pk[0];
-	state_ptr->pk[0] = pk0;
-
-	/* TONE */
-	if (tr == 1)		/* this sample has been treated as data */
-		state_ptr->td = 0;	/* next one will be treated as voice */
-	else if (a2p < -11776)	/* small sample-to-sample correlation */
-		state_ptr->td = 1;	/* signal may be data */
-	else				/* signal is voice */
-		state_ptr->td = 0;
-
-	/*
-	 * Adaptation speed control.
-	 */
-	state_ptr->dms += (fi - state_ptr->dms) >> 5;		/* FILTA */
-	state_ptr->dml += (((fi << 2) - state_ptr->dml) >> 7);	/* FILTB */
-
-	if (tr == 1)
-		state_ptr->ap = 256;
-	else if (y < 1536)					/* SUBTC */
-		state_ptr->ap += (0x200 - state_ptr->ap) >> 4;
-	else if (state_ptr->td == 1)
-		state_ptr->ap += (0x200 - state_ptr->ap) >> 4;
-	else if (abs((state_ptr->dms << 2) - state_ptr->dml) >=
-	    (state_ptr->dml >> 3))
-		state_ptr->ap += (0x200 - state_ptr->ap) >> 4;
-	else
-		state_ptr->ap += (-state_ptr->ap) >> 4;
-}
-
-/*
- * g726_decode()
- *
- * Description:
- *
- * Decodes a 4-bit code of G.726-32 encoded data of i and
- * returns the resulting linear PCM, A-law or u-law value.
- * return -1 for unknown out_coding value.
- */
-static int g726_decode(int	i, struct g726_state *state_ptr)
-{
-	int		sezi, sez, se;	/* ACCUM */
-	int		y;			/* MIX */
-	int		sr;			/* ADDB */
-	int		dq;
-	int		dqsez;
-
-	i &= 0x0f;			/* mask to get proper bits */
-#ifdef NOT_BLI
-	sezi = predictor_zero(state_ptr);
-	sez = sezi;
-	se = sezi + predictor_pole(state_ptr);	/* estimated signal */
-#else
-	sezi = predictor_zero(state_ptr);
-	sez = sezi >> 1;
-	se = (sezi + predictor_pole(state_ptr)) >> 1;	/* estimated signal */
-#endif
-
-	y = step_size(state_ptr);	/* dynamic quantizer step size */
-
-	dq = reconstruct(i & 8, _dqlntab[i], y); /* quantized diff. */
-
-#ifdef NOT_BLI
-	sr = se + dq;				/* reconst. signal */
-	dqsez = dq + sez;			/* pole prediction diff. */
-#else
-	sr = (dq < 0) ? se - (dq & 0x3FFF) : se + dq;	/* reconst. signal */
-	dqsez = sr - se + sez;		/* pole prediction diff. */
-#endif
-
-	update(4, y, _witab[i] << 5, _fitab[i], dq, sr, dqsez, state_ptr);
-
-#ifdef NOT_BLI
-	return (sr >> 10);	/* sr was 26-bit dynamic range */
-#else
-	return (sr << 2);	/* sr was 14-bit dynamic range */
-#endif
-}
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
+};
 
-/*
- * g726_encode()
- *
- * Encodes the input vale of linear PCM, A-law or u-law data sl and returns
- * the resulting code. -1 is returned for unknown input coding value.
- */
-static int g726_encode(int sl, struct g726_state *state_ptr)
+/* 20ms of G.726 at 32kbps */
+static uint8_t g726_slin_ex[] =
 {
-	int		sezi, se, sez;		/* ACCUM */
-	int		d;			/* SUBTA */
-	int		sr;			/* ADDB */
-	int		y;			/* MIX */
-	int		dqsez;			/* ADDC */
-	int		dq, i;
-
-#ifdef NOT_BLI
-	sl <<= 10;			/* 26-bit dynamic range */
-
-	sezi = predictor_zero(state_ptr);
-	sez = sezi;
-	se = sezi + predictor_pole(state_ptr);	/* estimated signal */
-#else
-	sl >>= 2;			/* 14-bit dynamic range */
-
-	sezi = predictor_zero(state_ptr);
-	sez = sezi >> 1;
-	se = (sezi + predictor_pole(state_ptr)) >> 1;	/* estimated signal */
-#endif
-
-	d = sl - se;				/* estimation difference */
-
-	/* quantize the prediction difference */
-	y = step_size(state_ptr);		/* quantizer step size */
-#ifdef NOT_BLI
-	d /= 0x1000;
-#endif
-	i = quantize(d, y, qtab_721, 7);	/* i = G726 code */
-
-	dq = reconstruct(i & 8, _dqlntab[i], y);	/* quantized est diff */
-
-#ifdef NOT_BLI
-	sr = se + dq;				/* reconst. signal */
-	dqsez = dq + sez;			/* pole prediction diff. */
-#else
-	sr = (dq < 0) ? se - (dq & 0x3FFF) : se + dq;	/* reconst. signal */
-	dqsez = sr - se + sez;			/* pole prediction diff. */
-#endif
-
-	update(4, y, _witab[i] << 5, _fitab[i], dq, sr, dqsez, state_ptr);
-
-	return (i);
-}
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
 
 /*
  * Private workspace for translating signed linear signals to G726.
@@ -698,12 +84,12 @@
 
 struct g726_encoder_pvt
 {
-  struct ast_frame f;
-  char offset[AST_FRIENDLY_OFFSET];   /* Space to build offset */
-  unsigned char outbuf[BUFFER_SIZE];  /* Encoded G726, two nibbles to a word */
-  unsigned char next_flag;
-  struct g726_state g726;
-  int tail;
+    struct ast_frame f;
+    uint8_t offset[AST_FRIENDLY_OFFSET];    /* Space to build offset */
+    uint8_t outbuf[BUFFER_SIZE];            /* Encoded G726, two nibbles to a word */
+    uint8_t next_flag;
+    g726_state_t g726_state;
+    int tail;
 };
 
 /*
@@ -712,12 +98,12 @@
 
 struct g726_decoder_pvt
 {
-  struct ast_frame f;
-  char offset[AST_FRIENDLY_OFFSET];	/* Space to build offset */
-  short outbuf[BUFFER_SIZE];	/* Decoded signed linear values */
-  struct g726_state g726;
-  int tail;
-  plc_state_t plc;
+    struct ast_frame f;
+    uint8_t offset[AST_FRIENDLY_OFFSET];	/* Space to build offset */
+    int16_t outbuf[BUFFER_SIZE];	        /* Decoded signed linear values */
+    g726_state_t g726_state;
+    int tail;
+    plc_state_t plc;
 };
 
 /*
@@ -731,21 +117,20 @@
  *  None.
  */
 
-static struct ast_translator_pvt *
-g726tolin_new (void)
+static struct ast_translator_pvt *g726tolin_new(void)
 {
-  struct g726_decoder_pvt *tmp;
-  tmp = malloc (sizeof (struct g726_decoder_pvt));
-  if (tmp)
+    struct g726_decoder_pvt *tmp;
+ 
+    if ((tmp = malloc(sizeof(struct g726_decoder_pvt))))
     {
-	  memset(tmp, 0, sizeof(*tmp));
-      tmp->tail = 0;
-      plc_init(&tmp->plc);
-      localusecnt++;
-	  g726_init_state(&tmp->g726);
-      ast_update_use_count ();
+	    memset(tmp, 0, sizeof(*tmp));
+        localusecnt++;
+        tmp->tail = 0;
+        plc_init(&tmp->plc);
+        g726_init(&(tmp->g726_state), 32000, G726_ENCODING_LINEAR, TRUE);
+        ast_update_use_count ();
     }
-  return (struct ast_translator_pvt *) tmp;
+    return (struct ast_translator_pvt *) tmp;
 }
 
 /*
@@ -759,20 +144,19 @@
  *  None.
  */
 
-static struct ast_translator_pvt *
-lintog726_new (void)
+static struct ast_translator_pvt *lintog726_new(void)
 {
-  struct g726_encoder_pvt *tmp;
-  tmp = malloc (sizeof (struct g726_encoder_pvt));
-  if (tmp)
+    struct g726_encoder_pvt *tmp;
+  
+    if ((tmp = malloc(sizeof(struct g726_encoder_pvt))))
     {
-	  memset(tmp, 0, sizeof(*tmp));
-      localusecnt++;
-      tmp->tail = 0;
-	  g726_init_state(&tmp->g726);
-      ast_update_use_count ();
+	    memset(tmp, 0, sizeof(*tmp));
+        localusecnt++;
+        tmp->tail = 0;
+        g726_init(&(tmp->g726_state), 32000, G726_ENCODING_LINEAR, TRUE);
+        ast_update_use_count ();
     }
-  return (struct ast_translator_pvt *) tmp;
+    return (struct ast_translator_pvt *) tmp;
 }
 
 /*
@@ -787,42 +171,41 @@
  *  tmp->tail is the number of packed values in the buffer.
  */
 
-static int
-g726tolin_framein (struct ast_translator_pvt *pvt, struct ast_frame *f)
+static int g726tolin_framein(struct ast_translator_pvt *pvt, struct ast_frame *f)
 {
-  struct g726_decoder_pvt *tmp = (struct g726_decoder_pvt *) pvt;
-  unsigned char *b;
-  int x;
-
-  if(f->datalen == 0) { /* perform PLC with nominal framesize of 20ms/160 samples */
-        if((tmp->tail + 160) > BUFFER_SIZE) {
+    struct g726_decoder_pvt *tmp = (struct g726_decoder_pvt *) pvt;
+    int new_samples;
+    
+    if (f->datalen == 0)
+    {
+        /* Perform PLC with nominal framesize of 20ms/160 samples */
+        if ((tmp->tail + 160) > BUFFER_SIZE)
+        {
             ast_log(LOG_WARNING, "Out of buffer space\n");
             return -1;
         }
-        if(useplc) {
-	    plc_fillin(&tmp->plc, tmp->outbuf+tmp->tail, 160);
-	    tmp->tail += 160;
-	}
-        return 0;
-  }
-
-  b = f->data;
-  for (x=0;x<f->datalen;x++) {
-  	if (tmp->tail >= BUFFER_SIZE) {
-		ast_log(LOG_WARNING, "Out of buffer space!\n");
-		return -1;
-	}
-	tmp->outbuf[tmp->tail++] = g726_decode((b[x] >> 4) & 0xf, &tmp->g726);
-  	if (tmp->tail >= BUFFER_SIZE) {
-		ast_log(LOG_WARNING, "Out of buffer space!\n");
-		return -1;
-	}
-	tmp->outbuf[tmp->tail++] = g726_decode(b[x] & 0x0f, &tmp->g726);
-  }
-
-  if(useplc) plc_rx(&tmp->plc, tmp->outbuf+tmp->tail-f->datalen*2, f->datalen*2);
-
-  return 0;
+        if (useplc)
+        {
+	        plc_fillin(&tmp->plc, tmp->outbuf + tmp->tail, 160);
+	        tmp->tail += 160;
+	    }
+    }
+    else
+    {
+        if ((tmp->tail + f->datalen*2) > BUFFER_SIZE)
+        {
+            ast_log(LOG_WARNING, "Out of buffer space\n");
+            return -1;
+        }
+        new_samples = g726_decode(&(tmp->g726_state),
+                                  tmp->outbuf + tmp->tail,
+                                  (const uint8_t *) f->data,
+                                  f->datalen);
+        if (useplc)
+            plc_rx(&tmp->plc, tmp->outbuf + tmp->tail, new_samples);
+        tmp->tail += new_samples;
+    }
+    return 0;
 }
 
 /*
@@ -837,24 +220,24 @@
  *  None.
  */
 
-static struct ast_frame *
-g726tolin_frameout (struct ast_translator_pvt *pvt)
+static struct ast_frame *g726tolin_frameout(struct ast_translator_pvt *pvt)
 {
-  struct g726_decoder_pvt *tmp = (struct g726_decoder_pvt *) pvt;
+    struct g726_decoder_pvt *tmp = (struct g726_decoder_pvt *) pvt;
+
+    if (tmp->tail == 0)
+        return NULL;
 
-  if (!tmp->tail)
-    return NULL;
+    tmp->f.frametype = AST_FRAME_VOICE;
+    tmp->f.subclass = AST_FORMAT_SLINEAR;
+    tmp->f.datalen = tmp->tail*sizeof(int16_t);
+    tmp->f.samples = tmp->tail;
+    tmp->f.mallocd = 0;
+    tmp->f.offset = AST_FRIENDLY_OFFSET;
+    tmp->f.src = __PRETTY_FUNCTION__;
+    tmp->f.data = tmp->outbuf;
 
-  tmp->f.frametype = AST_FRAME_VOICE;
-  tmp->f.subclass = AST_FORMAT_SLINEAR;
-  tmp->f.datalen = tmp->tail * 2;
-  tmp->f.samples = tmp->tail;
-  tmp->f.mallocd = 0;
-  tmp->f.offset = AST_FRIENDLY_OFFSET;
-  tmp->f.src = __PRETTY_FUNCTION__;
-  tmp->f.data = tmp->outbuf;
-  tmp->tail = 0;
-  return &tmp->f;
+    tmp->tail = 0;
+    return &tmp->f;
 }
 
 /*
@@ -868,26 +251,20 @@
  *  tmp->tail is number of signal values in the input buffer.
  */
 
-static int
-lintog726_framein (struct ast_translator_pvt *pvt, struct ast_frame *f)
+static int lintog726_framein(struct ast_translator_pvt *pvt, struct ast_frame *f)
 {
-  struct g726_encoder_pvt *tmp = (struct g726_encoder_pvt *) pvt;
-  short *s = f->data;
-  int samples = f->datalen / 2;
-  int x;
-  for (x=0;x<samples;x++) {
-  	if (tmp->next_flag & 0x80) {
-		if (tmp->tail >= BUFFER_SIZE) {
-			ast_log(LOG_WARNING, "Out of buffer space\n");
-			return -1;
-		}
-		tmp->outbuf[tmp->tail++] = ((tmp->next_flag & 0xf)<< 4) | g726_encode(s[x], &tmp->g726);
-		tmp->next_flag = 0;
-	} else {
-		tmp->next_flag = 0x80 | g726_encode(s[x], &tmp->g726);
-	}
-  }
-  return 0;
+    struct g726_encoder_pvt *tmp = (struct g726_encoder_pvt *) pvt;
+  
+    if ((tmp->tail + f->datalen/(2*sizeof(int16_t)) + 1) > BUFFER_SIZE)
+    {
+        ast_log(LOG_WARNING, "Out of buffer space\n");
+        return -1;
+    }
+    tmp->tail += g726_encode(&(tmp->g726_state),
+                             tmp->outbuf + tmp->tail,
+                             f->data,
+                             f->datalen/sizeof(int16_t));
+    return 0;
 }
 
 /*
@@ -902,64 +279,63 @@
  *  Leftover inbuf data gets packed, tail gets updated.
  */
 
-static struct ast_frame *
-lintog726_frameout (struct ast_translator_pvt *pvt)
+static struct ast_frame *lintog726_frameout(struct ast_translator_pvt *pvt)
 {
-  struct g726_encoder_pvt *tmp = (struct g726_encoder_pvt *) pvt;
+    struct g726_encoder_pvt *tmp = (struct g726_encoder_pvt *) pvt;
   
-  if (!tmp->tail)
-  	return NULL;
-  tmp->f.frametype = AST_FRAME_VOICE;
-  tmp->f.subclass = AST_FORMAT_G726;
-  tmp->f.samples = tmp->tail * 2;
-  tmp->f.mallocd = 0;
-  tmp->f.offset = AST_FRIENDLY_OFFSET;
-  tmp->f.src = __PRETTY_FUNCTION__;
-  tmp->f.data = tmp->outbuf;
-  tmp->f.datalen = tmp->tail;
+    if (tmp->tail == 0)
+  	    return NULL;
 
-  tmp->tail = 0;
-  return &tmp->f;
-}
+    tmp->f.frametype = AST_FRAME_VOICE;
+    tmp->f.subclass = AST_FORMAT_G726;
+    tmp->f.samples = tmp->tail*sizeof(int16_t);
+    tmp->f.mallocd = 0;
+    tmp->f.offset = AST_FRIENDLY_OFFSET;
+    tmp->f.src = __PRETTY_FUNCTION__;
+    tmp->f.data = tmp->outbuf;
+    tmp->f.datalen = tmp->tail;
 
+    tmp->tail = 0;
+    return &tmp->f;
+}
 
 /*
  * G726ToLin_Sample
  */
 
-static struct ast_frame *
-g726tolin_sample (void)
+static struct ast_frame *g726tolin_sample(void)
 {
-  static struct ast_frame f;
-  f.frametype = AST_FRAME_VOICE;
-  f.subclass = AST_FORMAT_G726;
-  f.datalen = sizeof (g726_slin_ex);
-  f.samples = sizeof(g726_slin_ex) * 2;
-  f.mallocd = 0;
-  f.offset = 0;
-  f.src = __PRETTY_FUNCTION__;
-  f.data = g726_slin_ex;
-  return &f;
+    static struct ast_frame f;
+ 
+    f.frametype = AST_FRAME_VOICE;
+    f.subclass = AST_FORMAT_G726;
+    f.datalen = sizeof(g726_slin_ex);
+    f.samples = sizeof(g726_slin_ex)*sizeof(int16_t);
+    f.mallocd = 0;
+    f.offset = 0;
+    f.src = __PRETTY_FUNCTION__;
+    f.data = g726_slin_ex;
+    return &f;
 }
 
 /*
  * LinToG726_Sample
  */
 
-static struct ast_frame *
-lintog726_sample (void)
+static struct ast_frame *lintog726_sample(void)
 {
-  static struct ast_frame f;
-  f.frametype = AST_FRAME_VOICE;
-  f.subclass = AST_FORMAT_SLINEAR;
-  f.datalen = sizeof (slin_g726_ex);
-  /* Assume 8000 Hz */
-  f.samples = sizeof (slin_g726_ex) / 2;
-  f.mallocd = 0;
-  f.offset = 0;
-  f.src = __PRETTY_FUNCTION__;
-  f.data = slin_g726_ex;
-  return &f;
+    static struct ast_frame f;
+
+    f.frametype = AST_FRAME_VOICE;
+    f.subclass = AST_FORMAT_SLINEAR;
+    f.datalen = sizeof(slin_g726_ex);
+    /* Assume 8000 samples/second */
+    f.samples = sizeof(slin_g726_ex)/2;
+    f.mallocd = 0;
+    f.offset = 0;
+    f.src = __PRETTY_FUNCTION__;
+    f.data = (int16_t *) slin_g726_ex;
+    return &f;
 }
 
 /*
@@ -973,120 +349,119 @@
  *  None.
  */
 
-static void
-g726_destroy (struct ast_translator_pvt *pvt)
+static void g726_destroy(struct ast_translator_pvt *pvt)
 {
-  free (pvt);
-  localusecnt--;
-  ast_update_use_count ();
+    free(pvt);
+    localusecnt--;
+    ast_update_use_count();
 }
 
 /*
  * The complete translator for G726ToLin.
  */
 
-static struct ast_translator g726tolin = {
-  "g726tolin",
-  AST_FORMAT_G726,
-  AST_FORMAT_SLINEAR,
-  g726tolin_new,
-  g726tolin_framein,
-  g726tolin_frameout,
-  g726_destroy,
-  /* NULL */
-  g726tolin_sample
+static struct ast_translator g726tolin =
+{
+    "g726tolin",
+    AST_FORMAT_G726,
+    AST_FORMAT_SLINEAR,
+    g726tolin_new,
+    g726tolin_framein,
+    g726tolin_frameout,
+    g726_destroy,
+    /* NULL */
+    g726tolin_sample
 };
 
 /*
  * The complete translator for LinToG726.
  */
 
-static struct ast_translator lintog726 = {
-  "lintog726",
-  AST_FORMAT_SLINEAR,
-  AST_FORMAT_G726,
-  lintog726_new,
-  lintog726_framein,
-  lintog726_frameout,
-  g726_destroy,
-  /* NULL */
-  lintog726_sample
+static struct ast_translator lintog726 =
+{
+    "lintog726",
+    AST_FORMAT_SLINEAR,
+    AST_FORMAT_G726,
+    lintog726_new,
+    lintog726_framein,
+    lintog726_frameout,
+    g726_destroy,
+    /* NULL */
+    lintog726_sample
 };
 
-static void 
-parse_config(void)
+static void parse_config(void)
 {
-  struct ast_config *cfg;
-  struct ast_variable *var;
-  if ((cfg = ast_config_load("codecs.conf"))) {
-    if ((var = ast_variable_browse(cfg, "plc"))) {
-      while (var) {
-       if (!strcasecmp(var->name, "genericplc")) {
-         useplc = ast_true(var->value) ? 1 : 0;
-         if (option_verbose > 2)
-           ast_verbose(VERBOSE_PREFIX_3 "codec_g726: %susing generic PLC\n", useplc ? "" : "not ");
-       }
-       var = var->next;
-      }
+    struct ast_config *cfg;
+    struct ast_variable *var;
+  
+    if ((cfg = ast_config_load("codecs.conf")))
+    {
+        if ((var = ast_variable_browse(cfg, "plc")))
+        {
+            while (var)
+            {
+                if (!strcasecmp(var->name, "genericplc"))
+                {
+                    useplc = ast_true(var->value)  ?  1  :  0;
+                    if (option_verbose > 2)
+                        ast_verbose(VERBOSE_PREFIX_3 "codec_g726: %susing generic PLC\n", useplc  ?  ""  :  "not ");
+                }
+                var = var->next;
+            }
+        }
+        ast_config_destroy(cfg);
     }
-    ast_config_destroy(cfg);
-  }
 }
 
-int
-reload(void)
+int reload(void)
 {
-  parse_config();
-  return 0;
+    parse_config();
+    return 0;
 }
 
-int
-unload_module (void)
+int unload_module(void)
 {
-  int res;
-  ast_mutex_lock (&localuser_lock);
-  res = ast_unregister_translator (&lintog726);
-  if (!res)
-    res = ast_unregister_translator (&g726tolin);
-  if (localusecnt)
-    res = -1;
-  ast_mutex_unlock (&localuser_lock);
-  return res;
+    int res;
+
+    ast_mutex_lock(&localuser_lock);
+    if ((res = ast_unregister_translator(&lintog726)) == 0)
+        res = ast_unregister_translator(&g726tolin);
+    if (localusecnt)
+        res = -1;
+    ast_mutex_unlock(&localuser_lock);
+    return res;
 }
 
-int
-load_module (void)
+int load_module(void)
 {
-  int res;
-  parse_config();
-  res = ast_register_translator (&g726tolin);
-  if (!res)
-    res = ast_register_translator (&lintog726);
-  else
-    ast_unregister_translator (&g726tolin);
-  return res;
+    int res;
+
+    parse_config();
+    if ((res = ast_register_translator(&g726tolin)) == 0)
+        res = ast_register_translator(&lintog726);
+    else
+        ast_unregister_translator(&g726tolin);
+    return res;
 }
 
 /*
  * Return a description of this module.
  */
-
-char *
-description (void)
+char *description(void)
 {
-  return tdesc;
+    return (char *) tdesc;
 }
 
-int
-usecount (void)
+int usecount(void)
 {
-  int res;
-  STANDARD_USECOUNT (res);
-  return res;
+    int res;
+
+    STANDARD_USECOUNT(res);
+    return res;
 }
 
-char *
-key ()
+char *key(void)
 {
-  return ASTERISK_GPL_KEY;
+    return ASTERISK_GPL_KEY;
 }
diff --exclude .svn -urN asterisk-1.2.9.1/configs/sip.conf.sample 1.2.9.1/configs/sip.conf.sample
--- asterisk-1.2.9.1/configs/sip.conf.sample	2006-06-01 14:41:47.000000000 +0200
+++ 1.2.9.1/configs/sip.conf.sample	2006-06-12 15:49:58.000000000 +0200
@@ -247,6 +247,32 @@
                           ; destinations which do not have a prior
                           ; account relationship with your server. 
 
+;------------------------------ JITTER BUFFER CONFIGURATION --------------------------
+; jb-enable = yes             ; Enables the use of a jitterbuffer on the receiving side of a
+                              ; SIP channel. Defaults to "no". An enabled jitterbuffer will
+                              ; be used only if the sending side can create and the receiving
+                              ; side can not accept jitter. The SIP channel can accept jitter,
+                              ; thus a jitterbuffer on the receive SIP side will be used only
+                              ; if it is forced and enabled.
+
+; jb-force = no               ; Forces the use of a jitterbuffer on the receive side of a SIP
+                              ; channel. Defaults to "no".
+
+; jb-max-size = 200           ; Max length of the jitterbuffer in milliseconds.
+
+; jb-resynch-threshold = 1000 ; Jump in the frame timestamps over which the jitterbuffer is
+                              ; resynchronized. Useful to improve the quality of the voice, with
+                              ; big jumps in/broken timestamps, usualy sent from exotic devices
+                              ; and programs. Defaults to 1000.
+
+; jb-impl = fixed             ; Jitterbuffer implementation, used on the receiving side of a SIP
+                              ; channel. Two implementation are currenlty available - "fixed"
+                              ; (with size always equals to jb-max-size) and "adaptive" (with
+                              ; variable size, actually the new jb of IAX2). Defaults to fixed.
+
+; jb-log = no                 ; Enables jitterbuffer frame logging. Defaults to "no".
+;-----------------------------------------------------------------------------------
+
 [authentication]
 ; Global credentials for outbound calls, i.e. when a proxy challenges your
 ; Asterisk server for authentication. These credentials override
diff --exclude .svn -urN asterisk-1.2.9.1/configs/zapata.conf.sample 1.2.9.1/configs/zapata.conf.sample
--- asterisk-1.2.9.1/configs/zapata.conf.sample	2006-04-28 18:40:32.000000000 +0200
+++ 1.2.9.1/configs/zapata.conf.sample	2006-06-12 15:49:58.000000000 +0200
@@ -472,6 +472,33 @@
 ;
 ;jitterbuffers=4
 ;
+;------------------------------ JITTER BUFFER CONFIGURATION --------------------------
+; jb-enable = yes             ; Enables the use of a jitterbuffer on the receiving side of a
+                              ; ZAP channel. Defaults to "no". An enabled jitterbuffer will
+                              ; be used only if the sending side can create and the receiving
+                              ; side can not accept jitter. The ZAP channel can't accept jitter,
+                              ; thus an enabled jitterbuffer on the receive ZAP side will always
+                              ; be used if the sending side can create jitter or if ZAP jb is
+                              ; forced.
+
+; jb-force = no               ; Forces the use of a jitterbuffer on the receive side of a ZAP
+                              ; channel. Defaults to "no".
+
+; jb-max-size = 200           ; Max length of the jitterbuffer in milliseconds.
+
+; jb-resynch-threshold = 1000 ; Jump in the frame timestamps over which the jitterbuffer is
+                              ; resynchronized. Useful to improve the quality of the voice, with
+                              ; big jumps in/broken timestamps, usualy sent from exotic devices
+                              ; and programs. Defaults to 1000.
+
+; jb-impl = fixed             ; Jitterbuffer implementation, used on the receiving side of a SIP
+                              ; channel. Two implementation are currenlty available - "fixed"
+                              ; (with size always equals to jb-max-size) and "adaptive" (with
+                              ; variable size, actually the new jb of IAX2). Defaults to fixed.
+
+; jb-log = no                 ; Enables jitterbuffer frame logging. Defaults to "no".
+;-----------------------------------------------------------------------------------
+;
 ; You can define your own custom ring cadences here.  You can define up to 8
 ; pairs.  If the silence is negative, it indicates where the callerid spill is
 ; to be placed.  Also, if you define any custom cadences, the default cadences
diff --exclude .svn -urN asterisk-1.2.9.1/frame.c 1.2.9.1/frame.c
--- asterisk-1.2.9.1/frame.c	2006-05-06 04:32:23.000000000 +0200
+++ 1.2.9.1/frame.c	2006-06-12 15:49:58.000000000 +0200
@@ -320,6 +320,13 @@
 		out->offset = fr->offset;
 		out->src = NULL;
 		out->data = fr->data;
+#ifdef AST_JB
+		/* Copy the timing data */
+		out->has_timing_info = fr->has_timing_info;
+		out->ts = fr->ts;
+		out->len = fr->len;
+		out->seqno = fr->seqno;
+#endif /* AST_JB */
 	} else
 		out = fr;
 	
@@ -387,6 +394,12 @@
 	out->prev = NULL;
 	out->next = NULL;
 	memcpy(out->data, f->data, out->datalen);	
+#ifdef AST_JB
+	out->has_timing_info = f->has_timing_info;
+	out->ts = f->ts;
+	out->len = f->len;
+	out->seqno = f->seqno;
+#endif /* AST_JB */
 	return out;
 }
 
diff --exclude .svn -urN asterisk-1.2.9.1/include/asterisk/abstract_jb.h 1.2.9.1/include/asterisk/abstract_jb.h
--- asterisk-1.2.9.1/include/asterisk/abstract_jb.h	1970-01-01 01:00:00.000000000 +0100
+++ 1.2.9.1/include/asterisk/abstract_jb.h	2006-06-12 15:49:55.000000000 +0200
@@ -0,0 +1,215 @@
+/*
+ * abstract_jb: common implementation-independent jitterbuffer stuff
+ *
+ * Copyright (C) 2005, Attractel OOD
+ *
+ * Contributors:
+ * Slav Klenov <slav@securax.org>
+ *
+ * Copyright on this file is disclaimed to Digium for inclusion in Asterisk
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Common implementation-independent jitterbuffer stuff.
+ * 
+ */
+
+#ifndef _ABSTRACT_JB_H_
+#define _ABSTRACT_JB_H_
+
+#include <stdio.h>
+#include <sys/time.h>
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+struct ast_channel;
+struct ast_frame;
+
+
+/* Configuration flags */
+#define AST_JB_ENABLED         (1 << 0)
+#define AST_JB_FORCED          (1 << 1)
+#define AST_JB_LOG             (1 << 2)
+
+#define AST_JB_IMPL_NAME_SIZE 12
+
+/*!
+ * \brief General jitterbuffer configuration.
+ */
+struct ast_jb_conf
+{
+	/*! \brief Combination of the AST_JB_ENABLED, AST_JB_FORCED and AST_JB_LOG flags. */
+	unsigned int flags;
+	/*! \brief Max size of the jitterbuffer implementation. */
+	long max_size;
+	/*! \brief Resynchronization threshold of the jitterbuffer implementation. */
+ 	long resync_threshold;
+	/*! \brief Name of the jitterbuffer implementation to be used. */
+ 	char impl[AST_JB_IMPL_NAME_SIZE];
+};
+
+
+/* Jitterbuffer configuration property names */
+#define AST_JB_CONF_PREFIX "jb-"
+#define AST_JB_CONF_ENABLE "enable"
+#define AST_JB_CONF_FORCE "force"
+#define AST_JB_CONF_MAX_SIZE "max-size"
+#define AST_JB_CONF_RESYNCH_THRESHOLD "resynch-threshold"
+#define AST_JB_CONF_IMPL "impl"
+#define AST_JB_CONF_LOG "log"
+
+
+struct ast_jb_impl;
+
+
+/*!
+ * \brief General jitterbuffer state.
+ */
+struct ast_jb
+{
+	/*! \brief Jitterbuffer configuration. */
+	struct ast_jb_conf conf;
+	/*! \brief Jitterbuffer implementation to be used. */
+	struct ast_jb_impl *impl;
+	/*! \brief Jitterbuffer object, passed to the implementation. */
+	void *jbobj;
+	/*! \brief The time the jitterbuffer was created. */
+	struct timeval timebase;
+	/*! \brief The time the next frame should be played. */
+	long next;
+	/*! \brief Voice format of the last frame in. */
+	int last_format;
+	/*! \brief File for frame timestamp tracing. */
+	FILE *logfile;
+	/*! \brief Jitterbuffer internal state flags. */
+	unsigned int flags;
+};
+
+
+/*!
+ * \brief Checks the need of a jb use in a generic bridge.
+ * \param c0 first bridged channel.
+ * \param c1 second bridged channel.
+ *
+ * Called from ast_generic_bridge() when two channels are entering in a bridge.
+ * The function checks the need of a jitterbuffer, depending on both channel's
+ * configuration and technology properties. As a result, this function sets
+ * appropriate internal jb flags to the channels, determining further behaviour
+ * of the bridged jitterbuffers.
+ */
+void ast_jb_do_usecheck(struct ast_channel *c0, struct ast_channel *c1);
+
+
+/*!
+ * \brief Calculates the time, left to the closest delivery moment in a bridge.
+ * \param c0 first bridged channel.
+ * \param c1 second bridged channel.
+ * \param time_left bridge time limit, or -1 if not set.
+ *
+ * Called from ast_generic_bridge() to determine the maximum time to wait for
+ * activity in ast_waitfor_n() call. If neihter of the channels is using jb,
+ * this function returns the time limit passed.
+ *
+ * \return maximum time to wait.
+ */
+int ast_jb_get_when_to_wakeup(struct ast_channel *c0, struct ast_channel *c1, int time_left);
+
+
+/*!
+ * \brief Puts a frame into a channel jitterbuffer.
+ * \param chan channel.
+ * \param frame frame.
+ *
+ * Called from ast_generic_bridge() to put a frame into a channel's jitterbuffer.
+ * The function will successfuly enqueue a frame if and only if:
+ * 1. the channel is using a jitterbuffer (as determined by ast_jb_do_usecheck()),
+ * 2. the frame's type is AST_FRAME_VOICE,
+ * 3. the frame has timing info set and has length >= 2 ms,
+ * 4. there is no some internal error happened (like failed memory allocation).
+ * Frames, successfuly queued, should be delivered by the channel's jitterbuffer,
+ * when their delivery time has came.
+ * Frames, not successfuly queued, should be delivered immediately.
+ * Dropped by the jb implementation frames are considered successfuly enqueued as
+ * far as they should not be delivered at all.
+ *
+ * \return zero if the frame was queued, -1 if not.
+ */
+int ast_jb_put(struct ast_channel *chan, struct ast_frame *f);
+
+
+/*!
+ * \brief Deliver the queued frames that should be delivered now for both channels.
+ * \param c0 first bridged channel.
+ * \param c1 second bridged channel.
+ *
+ * Called from ast_generic_bridge() to deliver any frames, that should be delivered
+ * for the moment of invocation. Does nothing if neihter of the channels is using jb
+ * or has any frames currently queued in. The function delivers frames usig ast_write()
+ * each of the channels.
+ */
+void ast_jb_get_and_deliver(struct ast_channel *c0, struct ast_channel *c1);
+
+
+/*!
+ * \brief Destroys jitterbuffer on a channel.
+ * \param chan channel.
+ *
+ * Called from ast_channel_free() when a channel is destroyed.
+ */
+void ast_jb_destroy(struct ast_channel *chan);
+
+
+/*!
+ * \brief Sets jitterbuffer configuration property.
+ * \param conf configuration to store the property in.
+ * \param varname property name.
+ * \param value property value.
+ *
+ * Called from a channel driver to build a jitterbuffer configuration tipically when
+ * reading a configuration file. It is not neccessary for a channel driver to know
+ * each of the jb configuration property names. The jitterbuffer itself knows them.
+ * The channel driver can pass each config var it reads through this function. It will
+ * return 0 if the variable was consumed from the jb conf.
+ *
+ * \return zero if the property was set to the configuration, -1 if not.
+ */
+int ast_jb_read_conf(struct ast_jb_conf *conf, char *varname, char *value);
+
+
+/*!
+ * \brief Configures a jitterbuffer on a channel.
+ * \param chan channel to configure.
+ * \param conf configuration to apply.
+ *
+ * Called from a channel driver when a channel is created and its jitterbuffer needs
+ * to be configured.
+ */
+void ast_jb_configure(struct ast_channel *chan, struct ast_jb_conf *conf);
+
+
+/*!
+ * \brief Copies a channel's jitterbuffer configuration.
+ * \param chan channel.
+ * \param conf destination.
+ */
+void ast_jb_get_config(struct ast_channel *chan, struct ast_jb_conf *conf);
+
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif /* _ABSTRACT_JB_H_ */
diff --exclude .svn -urN asterisk-1.2.9.1/include/asterisk/channel.h 1.2.9.1/include/asterisk/channel.h
--- asterisk-1.2.9.1/include/asterisk/channel.h	2006-06-01 22:27:50.000000000 +0200
+++ 1.2.9.1/include/asterisk/channel.h	2006-06-12 15:49:55.000000000 +0200
@@ -86,6 +86,10 @@
 #ifndef _ASTERISK_CHANNEL_H
 #define _ASTERISK_CHANNEL_H
 
+#ifdef AST_JB
+#include "asterisk/abstract_jb.h"
+#endif /* AST_JB */
+
 #include <unistd.h>
 #include <setjmp.h>
 #ifdef POLLCOMPAT 
@@ -414,6 +418,11 @@
 
 	/*! For easy linking */
 	struct ast_channel *next;
+
+#ifdef AST_JB
+	/*! The jitterbuffer state  */
+	struct ast_jb jb;
+#endif /* AST_JB */
 };
 
 /* \defgroup chanprop Channel tech properties:
@@ -421,6 +430,13 @@
 /* @{ */
 #define AST_CHAN_TP_WANTSJITTER	(1 << 0)	
 
+#ifdef AST_JB
+/* \defgroup chanprop Channel tech properties:
+	\brief Channels have this property if they can create jitter; i.e. most VoIP channels */
+/* @{ */
+#define AST_CHAN_TP_CREATESJITTER (1 << 1)
+#endif /* AST_JB */
+
 /* This flag has been deprecated by the transfercapbilty data member in struct ast_channel */
 /* #define AST_FLAG_DIGITAL	(1 << 0) */	/* if the call is a digital ISDN call */
 #define AST_FLAG_DEFER_DTMF	(1 << 1)	/*!< if dtmf should be deferred */
diff --exclude .svn -urN asterisk-1.2.9.1/include/asterisk/frame.h 1.2.9.1/include/asterisk/frame.h
--- asterisk-1.2.9.1/include/asterisk/frame.h	2005-11-29 19:24:39.000000000 +0100
+++ 1.2.9.1/include/asterisk/frame.h	2006-06-12 15:49:55.000000000 +0200
@@ -109,6 +109,16 @@
 	struct ast_frame *prev;			
 	/*! Next/Prev for linking stand alone frames */
 	struct ast_frame *next;			
+#ifdef AST_JB
+	/*! Timing data flag */
+	int has_timing_info;
+	/*! Timestamp in milliseconds */
+	long ts;
+	/*! Length in milliseconds */
+	long len;
+	/*! Sequence number */
+	int seqno;
+#endif /* AST_JB */
 };
 
 #define AST_FRIENDLY_OFFSET 	64	/*! It's polite for a a new frame to
diff --exclude .svn -urN asterisk-1.2.9.1/rtp.c 1.2.9.1/rtp.c
--- asterisk-1.2.9.1/rtp.c	2006-06-01 00:26:38.000000000 +0200
+++ 1.2.9.1/rtp.c	2006-06-12 15:49:58.000000000 +0200
@@ -628,6 +628,13 @@
 		if (rtp->f.subclass == AST_FORMAT_SLINEAR) 
 			ast_frame_byteswap_be(&rtp->f);
 		calc_rxstamp(&rtp->f.delivery, rtp, timestamp, mark);
+#ifdef AST_JB
+		/* Add timing data to let ast_generic_bridge() put the frame into a jitterbuf */
+		rtp->f.has_timing_info = 1;
+		rtp->f.ts = timestamp / 8;
+		rtp->f.len = rtp->f.samples / 8;
+		rtp->f.seqno = seqno;
+#endif /* AST_JB */
 	} else {
 		/* Video -- samples is # of samples vs. 90000 */
 		if (!rtp->lastividtimestamp)
@@ -1283,6 +1290,10 @@
 	*/
 	if (rtp->lastts > rtp->lastdigitts)
 		rtp->lastdigitts = rtp->lastts;
+#ifdef AST_JB
+	if (f->has_timing_info)
+		rtp->lastts = f->ts * 8;
+#endif /* AST_JB */
 
 	/* Get a pointer to the header */
 	rtpheader = (unsigned char *)(f->data - hdrlen);
diff --exclude .svn -urN asterisk-1.2.9.1/scx_jitterbuf.c 1.2.9.1/scx_jitterbuf.c
--- asterisk-1.2.9.1/scx_jitterbuf.c	1970-01-01 01:00:00.000000000 +0100
+++ 1.2.9.1/scx_jitterbuf.c	2006-06-12 15:49:58.000000000 +0200
@@ -0,0 +1,372 @@
+/*
+ * scx_jitterbuf: jitterbuffering algorithm
+ *
+ * Copyright (C) 2005, Attractel OOD
+ *
+ * Contributors:
+ * Slav Klenov <slav@securax.org>
+ *
+ * Copyright on this file is disclaimed to Digium for inclusion in Asterisk
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file 
+ * 
+ * \brief Jitterbuffering algorithm.
+ * 
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include "scx_jitterbuf.h"
+
+
+/* private scx_jb structure */
+struct scx_jb
+{
+	struct scx_jb_frame *frames;
+	struct scx_jb_frame *tail;
+	struct scx_jb_conf conf;
+	long rxcore;
+	long delay;
+	long next_delivery;
+	int force_resynch;
+};
+
+
+static struct scx_jb_frame * alloc_jb_frame(struct scx_jb *jb);
+static void release_jb_frame(struct scx_jb *jb, struct scx_jb_frame *frame);
+static void get_jb_head(struct scx_jb *jb, struct scx_jb_frame *frame);
+static int resynch_jb(struct scx_jb *jb, void *data, long ms, long ts, long now);
+
+
+static struct scx_jb_frame * alloc_jb_frame(struct scx_jb *jb)
+{
+	return (struct scx_jb_frame *) calloc(1, sizeof(struct scx_jb_frame));
+}
+
+
+static void release_jb_frame(struct scx_jb *jb, struct scx_jb_frame *frame)
+{
+	free(frame);
+}
+
+
+static void get_jb_head(struct scx_jb *jb, struct scx_jb_frame *frame)
+{
+	struct scx_jb_frame *fr;
+	
+	/* unlink the frame */
+	fr = jb->frames;
+	jb->frames = fr->next;
+	if(jb->frames != NULL)
+	{
+		jb->frames->prev = NULL;
+	}
+	else
+	{
+		/* the jb is empty - update tail */
+		jb->tail = NULL;
+	}
+	
+	/* update next */
+	jb->next_delivery = fr->delivery + fr->ms;
+	
+	/* copy the destination */
+	memcpy(frame, fr, sizeof(struct scx_jb_frame));
+	
+	/* and release the frame */
+	release_jb_frame(jb, fr);
+}
+
+
+struct scx_jb * scx_jb_new(struct scx_jb_conf *conf)
+{
+	struct scx_jb *jb;
+	
+	jb = calloc(1, sizeof(struct scx_jb));
+	if(jb == NULL)
+	{
+		return NULL;
+	}
+	
+	/* First copy our config */
+	memcpy(&jb->conf, conf, sizeof(struct scx_jb_conf));
+	/* we dont need the passed config anymore - continue working with the saved one */
+	conf = &jb->conf;
+	
+	/* validate the configuration */
+	if(conf->jbsize < 1)
+	{
+		conf->jbsize = SCX_JB_SIZE_DEFAULT;
+	}
+	if(conf->resync_threshold < 1)
+	{
+		conf->resync_threshold = SCX_JB_RESYNCH_THRESHOLD_DEFAULT;
+	}
+	
+	/* Set the constant delay to the jitterbuf */
+	jb->delay = conf->jbsize;
+	
+	return jb;
+}
+
+
+void scx_jb_destroy(struct scx_jb *jb)
+{
+	/* jitterbuf MUST be empty before it can be destroyed */
+	assert(jb->frames == NULL);
+	
+	free(jb);
+}
+
+
+static int resynch_jb(struct scx_jb *jb, void *data, long ms, long ts, long now)
+{
+	long diff, offset;
+	struct scx_jb_frame *frame;
+	
+	/* If jb is empty, just reinitialize the jb */
+	if(jb->frames == NULL)
+	{
+		/* debug check: tail should also be NULL */
+		assert(jb->tail == NULL);
+		
+		return scx_jb_put_first(jb, data, ms, ts, now);
+	}
+	
+	/* Adjust all jb state just as the new frame is with delivery = the delivery of the last
+	   frame (e.g. this one with max delivery) + the length of the last frame. */
+	
+	/* Get the diff in timestamps */
+	diff = ts - jb->tail->ts;
+	
+	/* Ideally this should be just the length of the last frame. The deviation is the desired
+	   offset */
+	offset = diff - jb->tail->ms;
+	
+	/* Do we really need to resynch, or this is just a frame for dropping? */
+	if(!jb->force_resynch && (offset < jb->conf.resync_threshold && offset > -jb->conf.resync_threshold))
+	{
+		return SCX_JB_DROP;
+	}
+	
+	/* Reset the force resynch flag */
+	jb->force_resynch = 0;
+	
+	/* apply the offset to the jb state */
+	jb->rxcore -= offset;
+	frame = jb->frames;
+	while(frame)
+	{
+		frame->ts += offset;
+		frame = frame->next;
+	}
+	
+	/* now jb_put() should add the frame at a last position */
+	return scx_jb_put(jb, data, ms, ts, now);
+}
+
+
+void scx_jb_set_force_resynch(struct scx_jb *jb)
+{
+	jb->force_resynch = 1;
+}
+
+
+int scx_jb_put_first(struct scx_jb *jb, void *data, long ms, long ts, long now)
+{
+	/* this is our first frame - set the base of the receivers time */
+	jb->rxcore = now - ts;
+	
+	/* init next for a first time - it should be the time the first frame should be played */
+	jb->next_delivery = now + jb->delay;
+	
+	/* put the frame */
+	return scx_jb_put(jb, data, ms, ts, now);
+}
+
+
+int scx_jb_put(struct scx_jb *jb, void *data, long ms, long ts, long now)
+{
+	struct scx_jb_frame *frame, *next, *newframe;
+	long delivery;
+	
+	/* debug check the validity of the input params */
+	assert(data != NULL);
+	/* do not allow frames shorter than 2 ms */
+	assert(ms >= 2);
+	assert(ts >= 0);
+	assert(now >= 0);
+	
+	delivery = jb->rxcore + jb->delay + ts;
+	
+	/* check if the new frame is not too late */
+	if(delivery < jb->next_delivery)
+	{
+		/* should drop the frame, but let first resynch_jb() check if this is not a jump in ts, or
+		   the force resynch flag was not set. */
+		return resynch_jb(jb, data, ms, ts, now);
+	}
+	
+	/* what if the delivery time is bigger than next + delay? Seems like a frame for the future.
+	   However, allow more resync_threshold ms in advance */
+	if(delivery > jb->next_delivery + jb->delay + jb->conf.resync_threshold)
+	{
+		/* should drop the frame, but let first resynch_jb() check if this is not a jump in ts, or
+		   the force resynch flag was not set. */
+		return resynch_jb(jb, data, ms, ts, now);
+	}
+
+	/* find the right place in the frames list, sorted by delivery time */
+	frame = jb->tail;
+	while(frame != NULL && frame->delivery > delivery)
+	{
+		frame = frame->prev;
+	}
+	
+	/* Check if the new delivery time is not covered already by the chosen frame */
+	if(frame && (frame->delivery == delivery ||
+		         delivery < frame->delivery + frame->ms ||
+		         (frame->next && delivery + ms > frame->next->delivery)))
+	{
+		/* TODO: Should we check for resynch here? Be careful to do not allow threshold smaller than
+		   the size of the jb */
+		
+		/* should drop the frame, but let first resynch_jb() check if this is not a jump in ts, or
+		   the force resynch flag was not set. */
+		return resynch_jb(jb, data, ms, ts, now);
+	}
+	
+	/* Reset the force resynch flag */
+	jb->force_resynch = 0;
+	
+	/* Get a new frame */
+	newframe = alloc_jb_frame(jb);
+	newframe->data = data;
+	newframe->ts = ts;
+	newframe->ms = ms;
+	newframe->delivery = delivery;
+	
+	/* and insert it right on place */
+	if(frame != NULL)
+	{
+		next = frame->next;
+		frame->next = newframe;
+		if(next != NULL)
+		{
+			newframe->next = next;
+			next->prev = newframe;
+		}
+		else
+		{
+			/* insert after the last frame - should update tail */
+			jb->tail = newframe;
+			newframe->next = NULL;
+		}
+		newframe->prev = frame;
+		
+		return SCX_JB_OK;
+	}
+	else if(jb->frames == NULL)
+	{
+		/* the frame list is empty or thats just the first frame ever */
+		/* tail should also be NULL is that case */
+		assert(jb->tail == NULL);
+		jb->frames = jb->tail = newframe;
+		newframe->next = NULL;
+		newframe->prev = NULL;
+		
+		return SCX_JB_OK;
+	}
+	else
+	{
+		/* insert on a first position - should update frames head */
+		newframe->next = jb->frames;
+		newframe->prev = NULL;
+		jb->frames->prev = newframe;
+		jb->frames = newframe;
+		
+		return SCX_JB_OK;
+	}
+}
+
+
+int scx_jb_get(struct scx_jb *jb, struct scx_jb_frame *frame, long now, long interpl)
+{
+	assert(now >= 0);
+	assert(interpl >= 2);
+	
+	if(now < jb->next_delivery)
+	{
+		/* too early for the next frame */
+		return SCX_JB_NOFRAME;
+	}
+	
+	/* Is the jb empty? */
+	if(jb->frames == NULL)
+	{
+		/* should interpolate a frame */
+		/* update next */
+		jb->next_delivery += interpl;
+		
+		return SCX_JB_INTERP;
+	}
+	
+	/* Isn't it too late for the first frame available in the jb? */
+	if(now > jb->frames->delivery + jb->frames->ms)
+	{
+		/* yes - should drop this frame and update next to point the next frame (get_jb_head() does it) */
+		get_jb_head(jb, frame);
+		
+		return SCX_JB_DROP;
+	}
+	
+	/* isn't it too early to play the first frame available? */
+	if(now < jb->frames->delivery)
+	{
+		/* yes - should interpolate one frame */
+		/* update next */
+		jb->next_delivery += interpl;
+		
+		return SCX_JB_INTERP;
+	}
+	
+	/* we have a frame for playing now (get_jb_head() updates next) */
+	get_jb_head(jb, frame);
+	
+	return SCX_JB_OK;
+}
+
+
+long scx_jb_next(struct scx_jb *jb)
+{
+	return jb->next_delivery;
+}
+
+
+int scx_jb_remove(struct scx_jb *jb, struct scx_jb_frame *frameout)
+{
+	if(jb->frames == NULL)
+	{
+		return SCX_JB_NOFRAME;
+	}
+	
+	get_jb_head(jb, frameout);
+	
+	return SCX_JB_OK;
+}
+
+
+
diff --exclude .svn -urN asterisk-1.2.9.1/scx_jitterbuf.h 1.2.9.1/scx_jitterbuf.h
--- asterisk-1.2.9.1/scx_jitterbuf.h	1970-01-01 01:00:00.000000000 +0100
+++ 1.2.9.1/scx_jitterbuf.h	2006-06-12 15:49:58.000000000 +0200
@@ -0,0 +1,93 @@
+/*
+ * scx_jitterbuf: jitterbuffering algorithm
+ *
+ * Copyright (C) 2005, Attractel OOD
+ *
+ * Contributors:
+ * Slav Klenov <slav@securax.org>
+ *
+ * Copyright on this file is disclaimed to Digium for inclusion in Asterisk
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file 
+ * 
+ * \brief Jitterbuffering algorithm.
+ * 
+ */
+
+#ifndef _SCX_JITTERBUF_H_
+#define _SCX_JITTERBUF_H_
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+
+/* return codes */
+#define SCX_JB_OK		0
+#define SCX_JB_DROP		1
+#define SCX_JB_INTERP	2
+#define SCX_JB_NOFRAME	3
+
+
+/* defaults */
+#define SCX_JB_SIZE_DEFAULT 200
+#define SCX_JB_RESYNCH_THRESHOLD_DEFAULT 1000
+
+
+/* jb configuration properties */
+struct scx_jb_conf
+{
+	long jbsize;
+ 	long resync_threshold;
+};
+
+
+struct scx_jb_frame
+{
+	void *data;
+	long ts;
+	long ms;
+	long delivery;
+	struct scx_jb_frame *next;
+	struct scx_jb_frame *prev;
+};
+
+
+struct scx_jb;
+
+
+/* jb interface */
+
+struct scx_jb * scx_jb_new(struct scx_jb_conf *conf);
+
+void scx_jb_destroy(struct scx_jb *jb);
+
+int scx_jb_put_first(struct scx_jb *jb, void *data, long ms, long ts, long now);
+
+int scx_jb_put(struct scx_jb *jb, void *data, long ms, long ts, long now);
+
+int scx_jb_get(struct scx_jb *jb, struct scx_jb_frame *frame, long now, long interpl);
+
+long scx_jb_next(struct scx_jb *jb);
+
+int scx_jb_remove(struct scx_jb *jb, struct scx_jb_frame *frameout);
+
+void scx_jb_set_force_resynch(struct scx_jb *jb);
+
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif /* _SCX_JITTERBUF_H_ */
diff --exclude .svn -urN asterisk-1.2.9.1/translate.c 1.2.9.1/translate.c
--- asterisk-1.2.9.1/translate.c	2006-02-25 20:54:40.000000000 +0100
+++ 1.2.9.1/translate.c	2006-06-12 15:49:58.000000000 +0200
@@ -157,6 +157,17 @@
 	struct ast_trans_pvt *p;
 	struct ast_frame *out;
 	struct timeval delivery;
+#ifdef AST_JB
+	int has_timing_info;
+	long ts;
+	long len;
+	int seqno;
+	
+	has_timing_info = f->has_timing_info;
+	ts = f->ts;
+	len = f->len;
+	seqno = f->seqno;
+#endif /* AST_JB */
 	p = path;
 	/* Feed the first frame into the first translator */
 	p->step->framein(p->state, f);
@@ -211,6 +222,15 @@
 			/* Invalidate prediction if we're entering a silence period */
 			if (out->frametype == AST_FRAME_CNG)
 				path->nextout = ast_tv(0, 0);
+#ifdef AST_JB
+			out->has_timing_info = has_timing_info;
+			if(has_timing_info)
+			{
+				out->ts = ts;
+				out->len = len;
+				out->seqno = seqno;
+			}
+#endif /* AST_JB */
 			return out;
 		}
 		p = p->next;
