Sophie

Sophie

distrib > Mandriva > 2007.1 > x86_64 > by-pkgid > 9ee9559fd1e45c46e051ec9d0928fc04 > files > 3

iax-0.2.3-10mdv2007.0.src.rpm

diff -Naur libiax2.old/src/frame.h libiax2/src/frame.h
--- libiax2.old/src/frame.h	2006-02-12 22:12:27.000000000 +0100
+++ libiax2/src/frame.h	2006-02-12 22:44:27.000000000 +0100
@@ -44,21 +44,40 @@
 #define AST_HTML_LINKREJECT	20		/* Reject LINKURL */
 
 /* Data formats for capabilities and frames alike */
-#define AST_FORMAT_G723_1	(1 << 0)	/* G.723.1 compression */
-#define AST_FORMAT_GSM		(1 << 1)	/* GSM compression */
-#define AST_FORMAT_ULAW		(1 << 2)	/* Raw mu-law data (G.711) */
-#define AST_FORMAT_ALAW		(1 << 3)	/* Raw A-law data (G.711) */
-#define AST_FORMAT_MP3		(1 << 4)	/* MPEG-2 layer 3 */
-#define AST_FORMAT_ADPCM	(1 << 5)	/* ADPCM (whose?) */
-#define AST_FORMAT_SLINEAR	(1 << 6)	/* Raw 16-bit Signed Linear (8000 Hz) PCM */
-#define AST_FORMAT_LPC10	(1 << 7)	/* LPC10, 180 samples/frame */
-#define AST_FORMAT_G729A	(1 << 8)	/* G.729a Audio */
-
-#define AST_FORMAT_MAX_AUDIO (1 << 15)	/* Maximum audio format */
-#define AST_FORMAT_JPEG		(1 << 16)	/* JPEG Images */
-#define AST_FORMAT_PNG		(1 << 17)	/* PNG Images */
-#define AST_FORMAT_H261		(1 << 18)	/* H.261 Video */
-#define AST_FORMAT_H263		(1 << 19)	/* H.263 Video */
+/*! G.723.1 compression */
+#define AST_FORMAT_G723_1       (1 << 0)
+	/*! GSM compression */
+#define AST_FORMAT_GSM          (1 << 1)
+	/*! Raw mu-law data (G.711) */
+#define AST_FORMAT_ULAW         (1 << 2)
+	/*! Raw A-law data (G.711) */
+#define AST_FORMAT_ALAW         (1 << 3)
+	/*! ADPCM (G.726, 32kbps) */
+#define AST_FORMAT_G726         (1 << 4)
+	/*! ADPCM (IMA) */
+#define AST_FORMAT_ADPCM        (1 << 5)
+	/*! Raw 16-bit Signed Linear (8000 Hz) PCM */
+#define AST_FORMAT_SLINEAR      (1 << 6)
+	/*! LPC10, 180 samples/frame */
+#define AST_FORMAT_LPC10        (1 << 7)
+	/*! G.729A audio */
+#define AST_FORMAT_G729A        (1 << 8)
+	/*! SpeeX Free Compression */
+#define AST_FORMAT_SPEEX        (1 << 9)
+	/*! iLBC Free Compression */
+#define AST_FORMAT_ILBC         (1 << 10)
+	/*! Maximum audio format */
+#define AST_FORMAT_MAX_AUDIO    (1 << 15)
+	/*! JPEG Images */
+#define AST_FORMAT_JPEG         (1 << 16)
+	/*! PNG Images */
+#define AST_FORMAT_PNG          (1 << 17)
+	/*! H.261 Video */
+#define AST_FORMAT_H261         (1 << 18)
+	/*! H.263 Video */
+#define AST_FORMAT_H263         (1 << 19)
+	/*! Max one */
+#define AST_FORMAT_MAX_VIDEO    (1 << 24)
 
 /* Control frame types */
 #define AST_CONTROL_HANGUP		1			/* Other end has hungup */
diff -Naur libiax2.old/src/iax2.h libiax2/src/iax2.h
--- libiax2.old/src/iax2.h	2006-02-12 22:12:27.000000000 +0100
+++ libiax2/src/iax2.h	2006-02-12 22:44:27.000000000 +0100
@@ -65,6 +65,8 @@
 #define IAX_COMMAND_UNSUPPORT	33	/* Unsupported message received */
 #define IAX_COMMAND_TRANSFER	34	/* Request remote transfer */
 #define IAX_COMMAND_PROVISION	35	/* Provision device */
+#define IAX_COMMAND_FWDOWNL    36      /* Download firmware */
+#define IAX_COMMAND_FWDATA     37      /* Firmware Data */
 
 #define IAX_DEFAULT_REG_EXPIRE  60	/* By default require re-registration once per minute */
 
@@ -104,6 +106,29 @@
 #define IAX_IE_PROVISIONING			29		/* Provisioning info */
 #define IAX_IE_AESPROVISIONING			30		/* AES Provisioning info */
 #define IAX_IE_DATETIME				31		/* Date/Time */
+#define IAX_IE_DEVICETYPE                       32              /* Device Type -- string */
+#define IAX_IE_SERVICEIDENT                     33              /* Service Identifier -- string */
+#define IAX_IE_FIRMWAREVER                      34              /* Firmware revision -- u16 */
+#define IAX_IE_FWBLOCKDESC                      35              /* Firmware block description -- u32 */
+#define IAX_IE_FWBLOCKDATA                      36              /* Firmware block of data -- raw */
+#define IAX_IE_PROVVER                          37              /* Provisioning Version (u32) */
+#define IAX_IE_CALLINGPRES                      38              /* Calling presentation (u8) */
+#define IAX_IE_CALLINGTON                       39              /* Calling type of number (u8) */
+#define IAX_IE_CALLINGTNS                       40              /* Calling transit network select (u16) */
+#define IAX_IE_SAMPLINGRATE                     41              /* Supported sampling rates (u16) */
+#define IAX_IE_CAUSECODE                        42              /* Hangup cause (u8) */
+#define IAX_IE_ENCRYPTION                       43              /* Encryption format (u16) */
+#define IAX_IE_ENCKEY                           44              /* Encryption key (raw) */
+#define IAX_IE_CODEC_PREFS          45      /* Codec Negotiation */
+
+#define IAX_IE_RR_JITTER                        46              /* Received jitter (as in RFC1889) u32 */
+#define IAX_IE_RR_LOSS                          47              /* Received loss (high byte loss pct, low 24 bits loss count, as in rfc1889 */
+#define IAX_IE_RR_PKTS                          48              /* Received frames (total frames received) u32 */
+#define IAX_IE_RR_DELAY                         49              /* Max playout delay for received frames (in ms) u16 */
+#define IAX_IE_RR_DROPPED                       50              /* Dropped frames (presumably by jitterbuf) u32 */
+#define IAX_IE_RR_OOO                           51              /* Frames received Out of Order u32 */
+
+
 
 #define IAX_AUTH_PLAINTEXT			(1 << 0)
 #define IAX_AUTH_MD5				(1 << 1)
@@ -112,6 +137,13 @@
 #define IAX_META_TRUNK				1		/* Trunk meta-message */
 #define IAX_META_VIDEO				2		/* Video frame */
 
+#define IAX_RATE_8KHZ                          (1 << 0) /* 8khz sampling (default if absent) */
+#define IAX_RATE_11KHZ                         (1 << 1) /* 11.025khz sampling */
+#define IAX_RATE_16KHZ                         (1 << 2) /* 16khz sampling */
+#define IAX_RATE_22KHZ                         (1 << 3) /* 22.05khz sampling */
+#define IAX_RATE_44KHZ                         (1 << 4) /* 44.1khz sampling */
+#define IAX_RATE_48KHZ                         (1 << 5) /* 48khz sampling */
+
 #define IAX_DPSTATUS_EXISTS			(1 << 0)
 #define IAX_DPSTATUS_CANEXIST		(1 << 1)
 #define IAX_DPSTATUS_NONEXISTANT	(1 << 2)
@@ -170,6 +202,18 @@
 	unsigned short len;				/* Length of data for this callno */
 } __PACKED;
 
+#define IAX_FIRMWARE_MAGIC 0x69617879
+
+struct ast_iax2_firmware_header {
+       unsigned int magic;             /* Magic number */
+       unsigned short version;         /* Software version */
+       unsigned char devname[16];      /* Device */
+       unsigned int datalen;           /* Data length of file beyond header */
+       unsigned char chksum[16];       /* Checksum of all data */
+       unsigned char data[0];
+} __PACKED;
+
+
 #if defined(_MSC_VER)
 #pragma pack(pop)
 #endif
diff -Naur libiax2.old/src/iax2-parser.c libiax2/src/iax2-parser.c
--- libiax2.old/src/iax2-parser.c	2006-02-12 22:12:27.000000000 +0100
+++ libiax2/src/iax2-parser.c	2006-02-12 22:44:27.000000000 +0100
@@ -3,15 +3,15 @@
  *
  * Implementation of Inter-Asterisk eXchange
  * 
- * Copyright (C) 2003, Digium
+ * Copyright (C) 2003-2004, Digium
  *
- * Mark Spencer <markster@linux-support.net>
+ * Mark Spencer <markster@digium.com>
  *
  * This program is free software, distributed under the terms of
  * the GNU Lesser (Library) General Public License
  */
 
-#ifdef WIN32
+#if defined(WIN32)  ||  defined(_WIN32_WCE)
 #include <winsock.h>
 #define snprintf _snprintf
 #else
@@ -89,15 +89,15 @@
 
 static void dump_int(char *output, int maxlen, void *value, int len)
 {
-	if (len == sizeof(unsigned int))
-		snprintf(output, maxlen, "%ld", (unsigned long)ntohl(get_uint32(value)));
+	if (len == (int)sizeof(unsigned int))
+		snprintf(output, maxlen, "%lu", (unsigned long)ntohl(get_uint32(value)));
 	else
 		snprintf(output, maxlen, "Invalid INT");
 }
 
 static void dump_short(char *output, int maxlen, void *value, int len)
 {
-	if (len == sizeof(unsigned short))
+	if (len == (int)sizeof(unsigned short))
 		snprintf(output, maxlen, "%d", ntohs(get_uint16(value)));
 	else
 		snprintf(output, maxlen, "Invalid SHORT");
@@ -105,12 +105,65 @@
 
 static void dump_byte(char *output, int maxlen, void *value, int len)
 {
-	if (len == sizeof(unsigned char))
-		snprintf(output, maxlen, "%d", ntohs(*((unsigned char *)value)));
+	if (len == (int)sizeof(unsigned char))
+		snprintf(output, maxlen, "%d", *((unsigned char *)value));
 	else
 		snprintf(output, maxlen, "Invalid BYTE");
 }
 
+static void dump_ipaddr(char *output, int maxlen, void *value, int len)
+{
+	struct sockaddr_in sin;
+	if (len == (int)sizeof(unsigned int)) {
+		memcpy(&sin.sin_addr, value, len);
+		snprintf(output, maxlen, "%s", inet_ntoa(sin.sin_addr));
+	} else
+		snprintf(output, maxlen, "Invalid IPADDR");
+}
+
+
+static void dump_prov_flags(char *output, int maxlen, void *value, int len)
+{
+	if (len == (int)sizeof(unsigned int))
+		snprintf(output, maxlen, "%lu (%s)", (unsigned long)ntohl(get_uint32(value)),
+			"PROVISION_PARSING_NOT_IMPLEMENTED");
+	else
+		snprintf(output, maxlen, "Invalid INT");
+}
+
+static void dump_samprate(char *output, int maxlen, void *value, int len)
+{
+	char tmp[256]="";
+	int sr;
+	if (len == (int)sizeof(unsigned short)) {
+		sr = ntohs(*((unsigned short *)value));
+		if (sr & IAX_RATE_8KHZ)
+			strcat(tmp, ",8khz");
+		if (sr & IAX_RATE_11KHZ)
+			strcat(tmp, ",11.025khz");
+		if (sr & IAX_RATE_16KHZ)
+			strcat(tmp, ",16khz");
+		if (sr & IAX_RATE_22KHZ)
+			strcat(tmp, ",22.05khz");
+		if (sr & IAX_RATE_44KHZ)
+			strcat(tmp, ",44.1khz");
+		if (sr & IAX_RATE_48KHZ)
+			strcat(tmp, ",48khz");
+		if (strlen(tmp))
+			strncpy(output, &tmp[1], maxlen - 1);
+		else
+			strncpy(output, "None specified!\n", maxlen - 1);
+	} else
+		snprintf(output, maxlen, "Invalid SHORT");
+
+}
+
+static void dump_prov_ies(char *output, int maxlen, unsigned char *iedata, int len);
+static void dump_prov(char *output, int maxlen, void *value, int len)
+{
+	dump_prov_ies(output, maxlen, value, len);
+}
+
 static struct iax2_ie {
 	int ie;
 	char *name;
@@ -126,6 +179,7 @@
 	{ IAX_IE_CAPABILITY, "CAPABILITY", dump_int },
 	{ IAX_IE_FORMAT, "FORMAT", dump_int },
 	{ IAX_IE_LANGUAGE, "LANGUAGE", dump_string },
+	{ IAX_IE_CODEC_PREFS, "CODEC_PREFS", dump_string },
 	{ IAX_IE_VERSION, "VERSION", dump_short },
 	{ IAX_IE_ADSICPE, "ADSICPE", dump_short },
 	{ IAX_IE_DNID, "DNID", dump_string },
@@ -143,55 +197,107 @@
 	{ IAX_IE_AUTOANSWER, "AUTO ANSWER REQ" },
 	{ IAX_IE_TRANSFERID, "TRANSFER ID", dump_int },
 	{ IAX_IE_RDNIS, "REFERRING DNIS", dump_string },
-	{ IAX_IE_PROVISIONING, "PROVISIONING" },
-	{ IAX_IE_AESPROVISIONING, "AES PROVISIONING" },
+	{ IAX_IE_PROVISIONING, "PROVISIONING", dump_prov },
+	{ IAX_IE_AESPROVISIONING, "AES PROVISIONG" },
 	{ IAX_IE_DATETIME, "DATE TIME", dump_int },
+	{ IAX_IE_DEVICETYPE, "DEVICE TYPE", dump_string },
+	{ IAX_IE_SERVICEIDENT, "SERVICE IDENT", dump_string },
+	{ IAX_IE_FIRMWAREVER, "FIRMWARE VER", dump_short },
+	{ IAX_IE_FWBLOCKDESC, "FW BLOCK DESC", dump_int },
+	{ IAX_IE_FWBLOCKDATA, "FW BLOCK DATA" },
+	{ IAX_IE_PROVVER, "PROVISIONG VER", dump_int },
+	{ IAX_IE_CALLINGPRES, "CALLING PRESNTN", dump_byte },
+	{ IAX_IE_CALLINGTON, "CALLING TYPEOFNUM", dump_byte },
+	{ IAX_IE_CALLINGTNS, "CALLING TRANSITNET", dump_short },
+	{ IAX_IE_SAMPLINGRATE, "SAMPLINGRATE", dump_samprate },
+	{ IAX_IE_CODEC_PREFS, "CODEC_PREFS", dump_string },
+	{ IAX_IE_RR_JITTER, "RR_JITTER", dump_int },
+	{ IAX_IE_RR_LOSS, "RR_LOSS", dump_int },
+	{ IAX_IE_RR_PKTS, "RR_PKTS", dump_int },
+	{ IAX_IE_RR_DELAY, "RR_DELAY", dump_short },
+	{ IAX_IE_RR_DROPPED, "RR_DROPPED", dump_int },
+	{ IAX_IE_RR_OOO, "RR_OOO", dump_int },
 };
 
 const char *iax_ie2str(int ie)
 {
 	int x;
-	for (x=0;x<sizeof(ies) / sizeof(ies[0]); x++) {
+	for (x=0;x<(int)sizeof(ies) / (int)sizeof(ies[0]); x++) {
 		if (ies[x].ie == ie)
 			return ies[x].name;
 	}
 	return "Unknown IE";
 }
 
+
+static void dump_prov_ies(char *output, int maxlen, unsigned char *iedata, int len)
+{
+	int ielen;
+	int ie;
+	int found;
+	char tmp[256];
+	if (len < 2)
+		return;
+	strcpy(output, "\n"); 
+	maxlen -= strlen(output); output += strlen(output);
+	while(len > 2) {
+		ie = iedata[0];
+		ielen = iedata[1];
+		if (ielen + 2> len) {
+			snprintf(tmp, (int)sizeof(tmp), "Total Prov IE length of %d bytes exceeds remaining prov frame length of %d bytes\n", ielen + 2, len);
+			strncpy(output, tmp, maxlen - 1);
+			maxlen -= strlen(output); output += strlen(output);
+			return;
+		}
+		found = 0;
+		if (!found) {
+			snprintf(tmp, (int)sizeof(tmp), "       Unknown Prov IE %03d  : Present\n", ie);
+			strncpy(output, tmp, maxlen - 1);
+			maxlen -= strlen(output); output += strlen(output);
+		}
+		iedata += (2 + ielen);
+		len -= (2 + ielen);
+	}
+}
+
 static void dump_ies(unsigned char *iedata, int len)
 {
 	int ielen;
 	int ie;
 	int x;
 	int found;
-	char interp[80];
-	char tmp[256];
+	char interp[1024];
+	char tmp[1024];
 	if (len < 2)
 		return;
 	while(len > 2) {
 		ie = iedata[0];
 		ielen = iedata[1];
 		if (ielen + 2> len) {
-			snprintf(tmp, sizeof(tmp), "Total IE length of %d bytes exceeds remaining frame length of %d bytes\n", ielen + 2, len);
+			snprintf(tmp, (int)sizeof(tmp), "Total IE length of %d bytes exceeds remaining frame length of %d bytes\n", ielen + 2, len);
 			outputf(tmp);
 			return;
 		}
 		found = 0;
-		for (x=0;x<sizeof(ies) / sizeof(ies[0]); x++) {
+		for (x=0;x<(int)sizeof(ies) / (int)sizeof(ies[0]); x++) {
 			if (ies[x].ie == ie) {
 				if (ies[x].dump) {
-					ies[x].dump(interp, sizeof(interp), iedata + 2, ielen);
-					snprintf(tmp, sizeof(tmp), "   %-15.15s : %s\n", ies[x].name, interp);
+					ies[x].dump(interp, (int)sizeof(interp), iedata + 2, ielen);
+					snprintf(tmp, (int)sizeof(tmp), "   %-15.15s : %s\n", ies[x].name, interp);
 					outputf(tmp);
 				} else {
-					snprintf(tmp, sizeof(tmp), "   %-15.15s : Present\n", ies[x].name);
+					if (ielen)
+						snprintf(interp, (int)sizeof(interp), "%d bytes", ielen);
+					else
+						strcpy(interp, "Present");
+					snprintf(tmp, (int)sizeof(tmp), "   %-15.15s : %s\n", ies[x].name, interp);
 					outputf(tmp);
 				}
 				found++;
 			}
 		}
 		if (!found) {
-			snprintf(tmp, sizeof(tmp), "   Unknown IE %03d  : Present\n", ie);
+			snprintf(tmp, (int)sizeof(tmp), "   Unknown IE %03d  : Present\n", ie);
 			outputf(tmp);
 		}
 		iedata += (2 + ielen);
@@ -202,7 +308,7 @@
 
 void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
 {
-	char *frames[] = {
+	const char *frames[] = {
 		"(0?)",
 		"DTMF   ",
 		"VOICE  ",
@@ -212,7 +318,7 @@
 		"IAX    ",
 		"TEXT   ",
 		"IMAGE  " };
-	char *iaxs[] = {
+	const char *iaxs[] = {
 		"(0?)",
 		"NEW    ",
 		"PING   ",
@@ -249,8 +355,10 @@
 		"UNSUPPORTED",
 		"TRANSFER",
 		"PROVISION",
+		"FWDOWNLD",
+		"FWDATA"
 	};
-	char *cmds[] = {
+	const char *cmds[] = {
 		"(0?)",
 		"HANGUP ",
 		"RING   ",
@@ -263,25 +371,26 @@
 	char retries[20];
 	char class2[20];
 	char subclass2[20];
-	char *class;
-	char *subclass;
+	const char *class;
+	const char *subclass;
 	char tmp[256];
+
 	if (f) {
 		fh = f->data;
-		snprintf(retries, sizeof(retries), "%03d", f->retries);
+		snprintf(retries, (int)sizeof(retries), "%03d", f->retries);
 	} else {
 		fh = fhi;
 		if (ntohs(fh->dcallno) & IAX_FLAG_RETRANS)
 			strcpy(retries, "Yes");
 		else
-			strcpy(retries, "No");
+			strcpy(retries, " No");
 	}
 	if (!(ntohs(fh->scallno) & IAX_FLAG_FULL)) {
 		/* Don't mess with mini-frames */
 		return;
 	}
-	if (fh->type > sizeof(frames)/sizeof(char *)) {
-		snprintf(class2, sizeof(class2), "(%d?)", fh->type);
+	if (fh->type > (int)sizeof(frames)/(int)sizeof(char *)) {
+		snprintf(class2, (int)sizeof(class2), "(%d?)", fh->type);
 		class = class2;
 	} else {
 		class = frames[(int)fh->type];
@@ -290,31 +399,31 @@
 		sprintf(subclass2, "%c", fh->csub);
 		subclass = subclass2;
 	} else if (fh->type == AST_FRAME_IAX) {
-		if (fh->csub >= sizeof(iaxs)/sizeof(iaxs[0])) {
-			snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);
+		if (fh->csub >= (int)sizeof(iaxs)/(int)sizeof(iaxs[0])) {
+			snprintf(subclass2, (int)sizeof(subclass2), "(%d?)", fh->csub);
 			subclass = subclass2;
 		} else {
 			subclass = iaxs[(int)fh->csub];
 		}
 	} else if (fh->type == AST_FRAME_CONTROL) {
-		if (fh->csub > sizeof(cmds)/sizeof(char *)) {
-			snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);
+		if (fh->csub > (int)sizeof(cmds)/(int)sizeof(char *)) {
+			snprintf(subclass2, (int)sizeof(subclass2), "(%d?)", fh->csub);
 			subclass = subclass2;
 		} else {
 			subclass = cmds[(int)fh->csub];
 		}
 	} else {
-		snprintf(subclass2, sizeof(subclass2), "%d", fh->csub);
+		snprintf(subclass2, (int)sizeof(subclass2), "%d", fh->csub);
 		subclass = subclass2;
 	}
-snprintf(tmp, sizeof(tmp), 
+snprintf(tmp, (int)sizeof(tmp), 
 "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s Subclass: %s\n",
 	(rx ? "Rx" : "Tx"),
 	retries, fh->oseqno, fh->iseqno, class, subclass);
 	outputf(tmp);
-snprintf(tmp, sizeof(tmp), 
-"   Timestamp: %05ldms  SCall: %5.5d  DCall: %5.5d [%s:%d]\n",
-	(long)ntohl(fh->ts),
+snprintf(tmp, (int)sizeof(tmp), 
+"   Timestamp: %05lums  SCall: %5.5d  DCall: %5.5d [%s:%d]\n",
+	(unsigned long)ntohl(fh->ts),
 	ntohs(fh->scallno) & ~IAX_FLAG_FULL, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS,
 		inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
 	outputf(tmp);
@@ -325,8 +434,8 @@
 int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, void *data, int datalen)
 {
 	char tmp[256];
-	if (datalen > (sizeof(ied->buf) - ied->pos)) {
-		snprintf(tmp, sizeof(tmp), "Out of space for ie '%s' (%d), need %d have %d\n", iax_ie2str(ie), ie, datalen, sizeof(ied->buf) - ied->pos);
+	if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
+		snprintf(tmp, (int)sizeof(tmp), "Out of space for ie '%s' (%d), need %d have %d\n", iax_ie2str(ie), ie, datalen, (int)sizeof(ied->buf) - ied->pos);
 		errorf(tmp);
 		return -1;
 	}
@@ -339,26 +448,26 @@
 
 int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, struct sockaddr_in *sin)
 {
-	return iax_ie_append_raw(ied, ie, sin, sizeof(struct sockaddr_in));
+	return iax_ie_append_raw(ied, ie, sin, (int)sizeof(struct sockaddr_in));
 }
 
 int iax_ie_append_int(struct iax_ie_data *ied, unsigned char ie, unsigned int value) 
 {
 	unsigned int newval;
 	newval = htonl(value);
-	return iax_ie_append_raw(ied, ie, &newval, sizeof(newval));
+	return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
 }
 
 int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsigned short value) 
 {
 	unsigned short newval;
 	newval = htons(value);
-	return iax_ie_append_raw(ied, ie, &newval, sizeof(newval));
+	return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
 }
 
 int iax_ie_append_str(struct iax_ie_data *ied, unsigned char ie, unsigned char *str)
 {
-	return iax_ie_append_raw(ied, ie, str, strlen(str));
+	return iax_ie_append_raw(ied, ie, str, strlen((char *) str));
 }
 
 int iax_ie_append_byte(struct iax_ie_data *ied, unsigned char ie, unsigned char dat)
@@ -387,8 +496,13 @@
 	int len;
 	int ie;
 	char tmp[256];
-	memset(ies, 0, sizeof(struct iax_ies));
+	memset(ies, 0, (int)sizeof(struct iax_ies));
 	ies->msgcount = -1;
+	ies->firmwarever = -1;
+	ies->calling_ton = -1;
+	ies->calling_tns = -1;
+	ies->calling_pres = -1;
+	ies->samprate = IAX_RATE_8KHZ;
 	while(datalen >= 2) {
 		ie = data[0];
 		len = data[1];
@@ -398,121 +512,138 @@
 		}
 		switch(ie) {
 		case IAX_IE_CALLED_NUMBER:
-			ies->called_number = data + 2;
+			ies->called_number = (char *) data + 2;
 			break;
 		case IAX_IE_CALLING_NUMBER:
-			ies->calling_number = data + 2;
+			ies->calling_number = (char *) data + 2;
 			break;
 		case IAX_IE_CALLING_ANI:
-			ies->calling_ani = data + 2;
+			ies->calling_ani = (char *) data + 2;
 			break;
 		case IAX_IE_CALLING_NAME:
-			ies->calling_name = data + 2;
+			ies->calling_name = (char *) data + 2;
 			break;
 		case IAX_IE_CALLED_CONTEXT:
-			ies->called_context = data + 2;
+			ies->called_context = (char *) data + 2;
 			break;
 		case IAX_IE_USERNAME:
-			ies->username = data + 2;
+			ies->username = (char *) data + 2;
 			break;
 		case IAX_IE_PASSWORD:
-			ies->password = data + 2;
+			ies->password = (char *) data + 2;
 			break;
 		case IAX_IE_CAPABILITY:
-			if (len != sizeof(unsigned int)) {
-				snprintf(tmp, sizeof(tmp), "Expecting capability to be %d bytes long but was %d\n", sizeof(unsigned int), len);
+			if (len != (int)sizeof(unsigned int)) {
+				snprintf(tmp, (int)sizeof(tmp), "Expecting capability to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
 				errorf(tmp);
 			} else
-				ies->capability = ntohl(get_uint32(data+2));
+				ies->capability = ntohl(get_uint32(data + 2));
 			break;
 		case IAX_IE_FORMAT:
-			if (len != sizeof(unsigned int)) {
-				snprintf(tmp, sizeof(tmp), "Expecting format to be %d bytes long but was %d\n", sizeof(unsigned int), len);
+			if (len != (int)sizeof(unsigned int)) {
+				snprintf(tmp, (int)sizeof(tmp), "Expecting format to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
 				errorf(tmp);
 			} else
-				ies->format = ntohl(get_uint32(data+2));
+				ies->format = ntohl(get_uint32(data + 2));
 			break;
 		case IAX_IE_LANGUAGE:
-			ies->language = data + 2;
+			ies->language = (char *) data + 2;
+			break;
+		case IAX_IE_CODEC_PREFS:
+			ies->codec_prefs = (char *) data + 2;
 			break;
 		case IAX_IE_VERSION:
-			if (len != sizeof(unsigned short)) {
-				snprintf(tmp, sizeof(tmp),  "Expecting version to be %d bytes long but was %d\n", sizeof(unsigned short), len);
+			if (len != (int)sizeof(unsigned short)) {
+				snprintf(tmp, (int)sizeof(tmp),  "Expecting version to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
 				errorf(tmp);
 			} else
-				ies->version = ntohs(get_uint16(data+2));
+				ies->version = ntohs(get_uint16(data + 2));
 			break;
 		case IAX_IE_ADSICPE:
-			if (len != sizeof(unsigned short)) {
-				snprintf(tmp, sizeof(tmp), "Expecting adsicpe to be %d bytes long but was %d\n", sizeof(unsigned short), len);
+			if (len != (int)sizeof(unsigned short)) {
+				snprintf(tmp, (int)sizeof(tmp), "Expecting adsicpe to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
+				errorf(tmp);
+			} else
+				ies->adsicpe = ntohs(get_uint16(data + 2));
+			break;
+		case IAX_IE_SAMPLINGRATE:
+			if (len != (int)sizeof(unsigned short)) {
+				snprintf(tmp, (int)sizeof(tmp), "Expecting samplingrate to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
 				errorf(tmp);
 			} else
-				ies->adsicpe = ntohs(get_uint16(data+2));
+				ies->samprate = ntohs(get_uint16(data + 2));
 			break;
 		case IAX_IE_DNID:
-			ies->dnid = data + 2;
+			ies->dnid = (char *) data + 2;
 			break;
 		case IAX_IE_RDNIS:
-			ies->rdnis = data + 2;
+			ies->rdnis = (char *) data + 2;
 			break;
 		case IAX_IE_AUTHMETHODS:
-			if (len != sizeof(unsigned short))  {
-				snprintf(tmp, sizeof(tmp), "Expecting authmethods to be %d bytes long but was %d\n", sizeof(unsigned short), len);
+			if (len != (int)sizeof(unsigned short))  {
+				snprintf(tmp, (int)sizeof(tmp), "Expecting authmethods to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
 				errorf(tmp);
 			} else
-				ies->authmethods = ntohs(get_uint16(data+2));
+				ies->authmethods = ntohs(get_uint16(data + 2));
 			break;
 		case IAX_IE_CHALLENGE:
-			ies->challenge = data + 2;
+			ies->challenge = (char *) data + 2;
 			break;
 		case IAX_IE_MD5_RESULT:
-			ies->md5_result = data + 2;
+			ies->md5_result = (char *) data + 2;
 			break;
 		case IAX_IE_RSA_RESULT:
-			ies->rsa_result = data + 2;
+			ies->rsa_result = (char *) data + 2;
 			break;
 		case IAX_IE_APPARENT_ADDR:
-			/* XXX need to check alignment? */
-			ies->apparent_addr = ((struct sockaddr_in *)(data+2));
+			ies->apparent_addr = ((struct sockaddr_in *)(data + 2));
 			break;
 		case IAX_IE_REFRESH:
-			if (len != sizeof(unsigned short)) {
-				snprintf(tmp, sizeof(tmp),  "Expecting refresh to be %d bytes long but was %d\n", sizeof(unsigned short), len);
+			if (len != (int)sizeof(unsigned short)) {
+				snprintf(tmp, (int)sizeof(tmp),  "Expecting refresh to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
 				errorf(tmp);
 			} else
-				ies->refresh = ntohs(get_uint16(data+2));
+				ies->refresh = ntohs(get_uint16(data + 2));
 			break;
 		case IAX_IE_DPSTATUS:
-			if (len != sizeof(unsigned short)) {
-				snprintf(tmp, sizeof(tmp),  "Expecting dpstatus to be %d bytes long but was %d\n", sizeof(unsigned short), len);
+			if (len != (int)sizeof(unsigned short)) {
+				snprintf(tmp, (int)sizeof(tmp),  "Expecting dpstatus to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
 				errorf(tmp);
 			} else
-				ies->dpstatus = ntohs(*((unsigned short *)(data + 2)));
+				ies->dpstatus = ntohs(get_uint16(data + 2));
 			break;
 		case IAX_IE_CALLNO:
-			if (len != sizeof(unsigned short)) {
-				snprintf(tmp, sizeof(tmp),  "Expecting callno to be %d bytes long but was %d\n", sizeof(unsigned short), len);
+			if (len != (int)sizeof(unsigned short)) {
+				snprintf(tmp, (int)sizeof(tmp),  "Expecting callno to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
 				errorf(tmp);
 			} else
-				ies->callno = ntohs(get_uint16(data+2));
+				ies->callno = ntohs(get_uint16(data + 2));
 			break;
 		case IAX_IE_CAUSE:
-			ies->cause = data + 2;
+			ies->cause = (char *) data + 2;
+			break;
+		case IAX_IE_CAUSECODE:
+			if (len != 1) {
+				snprintf(tmp, (int)sizeof(tmp), "Expecting causecode to be single byte but was %d\n", len);
+				errorf(tmp);
+			} else {
+				ies->causecode = data[2];
+			}
 			break;
 		case IAX_IE_IAX_UNKNOWN:
 			if (len == 1)
 				ies->iax_unknown = data[2];
 			else {
-				snprintf(tmp, sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len);
+				snprintf(tmp, (int)sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len);
 				errorf(tmp);
 			}
 			break;
 		case IAX_IE_MSGCOUNT:
-			if (len != sizeof(unsigned short)) {
-				snprintf(tmp, sizeof(tmp), "Expecting msgcount to be %d bytes long but was %d\n", sizeof(unsigned short), len);
+			if (len != (int)sizeof(unsigned short)) {
+				snprintf(tmp, (int)sizeof(tmp), "Expecting msgcount to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
 				errorf(tmp);
 			} else
-				ies->msgcount = ntohs(get_uint16(data+2));
+				ies->msgcount = ntohs(get_uint16(data + 2));	
 			break;
 		case IAX_IE_AUTOANSWER:
 			ies->autoanswer = 1;
@@ -521,22 +652,126 @@
 			ies->musiconhold = 1;
 			break;
 		case IAX_IE_TRANSFERID:
-			if (len != sizeof(unsigned int)) {
-				snprintf(tmp, sizeof(tmp), "Expecting transferid to be %d bytes long but was %d\n", sizeof(unsigned int), len);
+			if (len != (int)sizeof(unsigned int)) {
+				snprintf(tmp, (int)sizeof(tmp), "Expecting transferid to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
 				errorf(tmp);
 			} else
-				ies->transferid = ntohl(get_uint32(data+2));
+				ies->transferid = ntohl(get_uint32(data + 2));
 			break;
 		case IAX_IE_DATETIME:
-			if (len != sizeof(unsigned int)) {
-				snprintf(tmp, sizeof(tmp), "Expecting date/time to be %d bytes long but was %d\n", sizeof(unsigned int), len);
+			if (len != (int)sizeof(unsigned int)) {
+				snprintf(tmp, (int)sizeof(tmp), "Expecting date/time to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
+				errorf(tmp);
+			} else
+				ies->datetime = ntohl(get_uint32(data + 2));
+			break;
+		case IAX_IE_FIRMWAREVER:
+			if (len != (int)sizeof(unsigned short)) {
+				snprintf(tmp, (int)sizeof(tmp), "Expecting firmwarever to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
 				errorf(tmp);
 			} else
-				ies->datetime = ntohl(get_uint32(data+2));
+				ies->firmwarever = ntohs(get_uint16(data + 2));	
+			break;
+		case IAX_IE_DEVICETYPE:
+			ies->devicetype = (char *) data + 2;
+			break;
+		case IAX_IE_SERVICEIDENT:
+			ies->serviceident = (char *) data + 2;
+			break;
+		case IAX_IE_FWBLOCKDESC:
+			if (len != (int)sizeof(unsigned int)) {
+				snprintf(tmp, (int)sizeof(tmp), "Expected block desc to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
+				errorf(tmp);
+			} else
+				ies->fwdesc = ntohl(get_uint32(data + 2));
+			break;
+		case IAX_IE_FWBLOCKDATA:
+			ies->fwdata = data + 2;
+			ies->fwdatalen = len;
+			break;
+		case IAX_IE_PROVVER:
+			if (len != (int)sizeof(unsigned int)) {
+				snprintf(tmp, (int)sizeof(tmp), "Expected provisioning version to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
+				errorf(tmp);
+			} else {
+				ies->provverpres = 1;
+				ies->provver = ntohl(get_uint32(data + 2));
+			}
+			break;
+		case IAX_IE_CALLINGPRES:
+			if (len == 1)
+				ies->calling_pres = data[2];
+			else {
+				snprintf(tmp, (int)sizeof(tmp), "Expected single byte callingpres, but was %d long\n", len);
+				errorf(tmp);
+			}
+			break;
+		case IAX_IE_CALLINGTON:
+			if (len == 1)
+				ies->calling_ton = data[2];
+			else {
+				snprintf(tmp, (int)sizeof(tmp), "Expected single byte callington, but was %d long\n", len);
+				errorf(tmp);
+			}
+			break;
+		case IAX_IE_CALLINGTNS:
+			if (len != (int)sizeof(unsigned short)) {
+				snprintf(tmp, (int)sizeof(tmp), "Expecting callingtns to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
+				errorf(tmp);
+			} else
+				ies->calling_tns = ntohs(get_uint16(data + 2));	
+			break;
+		case IAX_IE_RR_JITTER:
+			if (len != (int)sizeof(unsigned int)) {
+				snprintf(tmp, (int)sizeof(tmp), "Expected jitter rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
+				errorf(tmp);
+			} else {
+				ies->rr_jitter = ntohl(get_uint32(data + 2));
+			}
+			break;
+		case IAX_IE_RR_LOSS:
+			if (len != (int)sizeof(unsigned int)) {
+				snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
+				errorf(tmp);
+			} else {
+				ies->rr_loss = ntohl(get_uint32(data + 2));
+			}
+			break;
+		case IAX_IE_RR_PKTS:
+			if (len != (int)sizeof(unsigned int)) {
+				snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
+				errorf(tmp);
+			} else {
+				ies->rr_pkts = ntohl(get_uint32(data + 2));
+			}
+			break;
+		case IAX_IE_RR_DELAY:
+			if (len != (int)sizeof(unsigned short)) {
+				snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
+				errorf(tmp);
+			} else {
+				ies->rr_delay = ntohs(get_uint16(data + 2));
+			}
+			break;
+		case IAX_IE_RR_DROPPED:
+			if (len != (int)sizeof(unsigned int)) {
+				snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
+				errorf(tmp);
+			} else {
+				ies->rr_dropped = ntohl(get_uint32(data + 2));
+			}
+			break;
+		case IAX_IE_RR_OOO:
+			if (len != (int)sizeof(unsigned int)) {
+				snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
+				errorf(tmp);
+			} else {
+				ies->rr_ooo = ntohl(get_uint32(data + 2));
+			}
 			break;
 		default:
-			snprintf(tmp, sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len);
-			errorf(tmp);
+			snprintf(tmp, (int)sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len);
+			outputf(tmp);
 		}
 		/* Overwrite information element with 0, to null terminate previous portion */
 		data[0] = 0;
@@ -569,7 +804,7 @@
 struct iax_frame *iax_frame_new(int direction, int datalen)
 {
 	struct iax_frame *fr;
-	fr = malloc(sizeof(struct iax_frame) + datalen);
+	fr = malloc((int)sizeof(struct iax_frame) + datalen);
 	if (fr) {
 		fr->direction = direction;
 		fr->retrans = -1;
diff -Naur libiax2.old/src/iax2-parser.h libiax2/src/iax2-parser.h
--- libiax2.old/src/iax2-parser.h	2006-02-12 22:12:27.000000000 +0100
+++ libiax2/src/iax2-parser.h	2006-02-12 22:44:27.000000000 +0100
@@ -5,7 +5,7 @@
  * 
  * Copyright (C) 2003, Digium
  *
- * Mark Spencer <markster@linux-support.net>
+ * Mark Spencer <markster@digium.com>
  *
  * This program is free software, distributed under the terms of
  * the GNU General Public License
@@ -19,11 +19,15 @@
 	char *calling_number;
 	char *calling_ani;
 	char *calling_name;
+	int calling_ton;
+	int calling_tns;
+	int calling_pres;
 	char *called_context;
 	char *username;
 	char *password;
 	unsigned int capability;
 	unsigned int format;
+	char *codec_prefs;
 	char *language;
 	int version;
 	unsigned short adsicpe;
@@ -38,20 +42,39 @@
 	unsigned short dpstatus;
 	unsigned short callno;
 	char *cause;
+	unsigned char causecode;
 	unsigned char iax_unknown;
 	int msgcount;
 	int autoanswer;
 	int musiconhold;
 	unsigned int transferid;
 	unsigned int datetime;
+	char *devicetype;
+	char *serviceident;
+	int firmwarever;
+	unsigned int fwdesc;
+	unsigned char *fwdata;
+	unsigned char fwdatalen;
+	unsigned int provver;
+	unsigned short samprate;
+	unsigned int provverpres;
+	unsigned int rr_jitter;
+	unsigned int rr_loss;
+	unsigned int rr_pkts;
+	unsigned short rr_delay;
+	unsigned int rr_dropped;
+	unsigned int rr_ooo;
 };
 
 #define DIRECTION_INGRESS 1
 #define DIRECTION_OUTGRESS 2
 
 struct iax_frame {
+#ifdef LIBIAX
 	struct iax_session *session;
 	struct iax_event *event;
+#endif
+
 	/* /Our/ call number */
 	unsigned short callno;
 	/* /Their/ call number */
diff -Naur libiax2.old/src/iax.c libiax2/src/iax.c
--- libiax2.old/src/iax.c	2006-02-12 22:12:27.000000000 +0100
+++ libiax2/src/iax.c	2006-02-12 22:44:27.000000000 +0100
@@ -1,4 +1,4 @@
-/*
+ /*
  * libiax: An implementation of Inter-Asterisk eXchange
  *
  * Copyright (C) 2001, Linux Support Services, Inc.
@@ -8,11 +8,19 @@
  * This program is free software, distributed under the terms of
  * the GNU Lesser (Library) General Public License
  */
- 
-#ifdef	WIN32
 
-#include <string.h>
+#if defined(WIN32)  ||  defined(_WIN32_WCE)
+#undef __STRICT_ANSI__ //for strdup with ms
+
+#if defined(_WIN32_WCE)
+#define strdup _strdup
+#else
 #include <process.h>
+#include <fcntl.h>
+#include <io.h>
+#include <errno.h>
+#endif
+#include <string.h>
 #include <windows.h>
 #include <winsock.h>
 #include <time.h>
@@ -20,17 +28,19 @@
 #include <malloc.h>
 #include <stdarg.h>
 #include <stdio.h>
-#include <fcntl.h>
-#include <io.h>
-#include <errno.h>
+#include <limits.h>
+
 
 #define	snprintf _snprintf
 
 #if defined(_MSC_VER)
-#define	close		_close
+#define	close		closesocket
+#if !defined(_WIN32_WCE)
+#define inline      __inline
+#endif
 #endif
 
-void gettimeofday(struct timeval *tv, struct timezone *tz);
+void gettimeofday(struct timeval *tv, void /*struct timezone*/ *tz);
 
 #else
 
@@ -39,6 +49,11 @@
 #include <netinet/in.h>
 #include <sys/time.h>
 #include <stdlib.h>
+#ifdef __GNUC__
+#ifndef __USE_SVID
+#define __USE_SVID
+#endif
+#endif
 #include <string.h>
 #include <stdarg.h>
 #include <stdio.h>
@@ -59,6 +74,10 @@
 
 #endif
 
+#ifdef NEWJB
+#include "jitterbuf.h"
+#endif
+
 #include "iax-client.h"
 #include "md5.h"
 
@@ -73,7 +92,7 @@
 
 /* Define socket options for IAX2 sockets, based on platform
  * availability of flags */
-#ifdef WIN32
+#if defined(WIN32)  ||  defined(_WIN32_WCE)
 #define IAX_SOCKOPTS 0
 #else
 #ifdef MACOSX
@@ -112,7 +131,7 @@
 #define DROP_WHOLE_FRAMES
 
 #define MIN_RETRY_TIME 10
-#define MAX_RETRY_TIME 10000
+#define MAX_RETRY_TIME 4000
 #define MEMORY_SIZE 1000
 
 #define TRANSFER_NONE  0
@@ -120,6 +139,7 @@
 #define TRANSFER_READY 2
 #define TRANSFER_REL   3
 
+#ifndef NEWJB
 /* No more than 4 seconds of jitter buffer */
 static int max_jitterbuffer = 4000;
 /* No more than 50 extra milliseconds of jitterbuffer than needed */
@@ -127,22 +147,37 @@
 /* To use or not to use the jitterbuffer */
 static int iax_use_jitterbuffer = 1;
 
+/* Dropcount (in per-MEMORY_SIZE) usually percent */
+static int iax_dropcount = 3;
+#endif
+
 /* UDP Socket (file descriptor) */
 static int netfd = -1;
 
 /* Max timeouts */
 static int maxretries = 10;
 
-/* Dropcount (in per-MEMORY_SIZE) usually percent */
-static int iax_dropcount = 3;
+
+
+/* external global networking replacements */
+static sendto_t	  iax_sendto = (sendto_t) sendto;
+static recvfrom_t iax_recvfrom = (recvfrom_t) recvfrom;
+
+/* ping interval (seconds) */
+static int ping_time = 10;
+static void send_ping(void *session);
 
 struct iax_session {
 	/* Private data */
 	void *pvt;
-	/* Sendto function */
+	/* session-local Sendto function */
 	sendto_t sendto;
 	/* Is voice quelched (e.g. hold) */
 	int quelch;
+	/* Codec Pref Order */
+	char codec_order[32];
+	/* Codec Pref Order Index*/
+	int codec_order_len;
 	/* Last received voice format */
 	int voiceformat;
 	/* Last transmitted voice format */
@@ -214,6 +249,9 @@
 #endif
 	/* Refresh if applicable */
 	int refresh;
+
+	/* ping scheduler id */
+	int pingid;
 	
 	/* Transfer stuff */
 	struct sockaddr_in transfer;
@@ -223,12 +261,18 @@
 	int transferpeer;	/* for attended transfer */
 	int transfer_moh;	/* for music on hold while performing attended transfer */
 
+#ifdef NEWJB
+	jitterbuf *jb;
+#endif
+	struct iax_netstat remote_netstats;
+
 	/* For linking if there are multiple connections */
 	struct iax_session *next;
 };
 
 char iax_errstr[256];
 
+
 #define IAXERROR snprintf(iax_errstr, sizeof(iax_errstr), 
 
 #ifdef DEBUG_SUPPORT
@@ -249,30 +293,15 @@
 	debug = 0;
 }
 
-void iax_set_private(struct iax_session *s, void *ptr)
-{
-	s->pvt = ptr;
-}
-
-void *iax_get_private(struct iax_session *s)
-{
-	return s->pvt;
-}
-
-void iax_set_sendto(struct iax_session *s, sendto_t ptr)
-{
-	s->sendto = ptr;
-}
-
 /* This is a little strange, but to debug you call DEBU(G "Hello World!\n"); */ 
-#ifdef	WIN32
+#if defined(WIN32)  ||  defined(_WIN32_WCE)
 #define G __FILE__, __LINE__,
 #else
 #define G __FILE__, __LINE__, __PRETTY_FUNCTION__, 
 #endif
 
 #define DEBU __debug 
-#ifdef	WIN32
+#if defined(WIN32)  ||  defined(_WIN32_WCE)
 static int __debug(char *file, int lineno, char *fmt, ...) 
 {
 	va_list args;
@@ -299,14 +328,17 @@
 #endif
 #else /* No debug support */
 
-#ifdef	WIN32
+#if defined(WIN32)  ||  defined(_WIN32_WCE)
 #define	DEBU
 #else
-#define DEBU
+#define DEBU(fmt...) \
+    do {} while(0)
 #endif
 #define G
 #endif
 
+typedef void (*sched_func)(void *);
+
 struct iax_sched {
 	/* These are scheduled things to be delivered */
 	struct timeval when;
@@ -314,45 +346,63 @@
 	struct iax_event *event;
 	/* If frame is non-NULL then we're transmitting a frame */
 	struct iax_frame *frame;
+	/* If func is non-NULL then we should call it */
+	sched_func func;
+	/* and pass it this argument */
+	void *arg;
 	/* Easy linking */
 	struct iax_sched *next;
 };
 
-#ifdef	WIN32
+static struct iax_sched *schedq = NULL;
+static struct iax_session *sessions = NULL;
+static int callnums = 1;
+static int transfer_id = 1;		/* for attended transfer */
+
 
-void bzero(void *b, size_t len)
+void iax_set_private(struct iax_session *s, void *ptr)
 {
-	memset(b,0,len);
+	s->pvt = ptr;
 }
 
-#endif
+void *iax_get_private(struct iax_session *s)
+{
+	return s->pvt;
+}
+
+void iax_set_sendto(struct iax_session *s, sendto_t ptr)
+{
+	s->sendto = ptr;
+}
+
+
+unsigned int iax_session_get_capability(struct iax_session *s)
+{
+	return s->capability;
+}
 
-static struct iax_sched *schedq = NULL;
-static struct iax_session *sessions = NULL;
-static int callnums = 1;
-static int transfer_id = 1;		/* for attended transfer */
 
 static int inaddrcmp(struct sockaddr_in *sin1, struct sockaddr_in *sin2)
 {
 	return (sin1->sin_addr.s_addr != sin2->sin_addr.s_addr) || (sin1->sin_port != sin2->sin_port);
 }
 
-static int iax_sched_event(struct iax_event *event, struct iax_frame *frame, int ms)
+static int iax_sched_add(struct iax_event *event, struct iax_frame *frame, sched_func func, void *arg, int ms)
 {
 
 	/* Schedule event to be delivered to the client
 	   in ms milliseconds from now, or a reliable frame to be retransmitted */
 	struct iax_sched *sched, *cur, *prev = NULL;
 	
-	if (!event && !frame) {
-		DEBU(G "No event, no frame?  what are we scheduling?\n");
+	if (!event && !frame && !func) {
+		DEBU(G "No event, no frame, no func?  what are we scheduling?\n");
 		return -1;
 	}
 	
 
 	sched = (struct iax_sched*)malloc(sizeof(struct iax_sched));
 	if (sched) {
-		bzero(sched, sizeof(struct iax_sched));
+        memset(sched, 0, sizeof(struct iax_sched));
 		gettimeofday(&sched->when, NULL);
 		sched->when.tv_sec += (ms / 1000);
 		ms = ms % 1000;
@@ -363,6 +413,8 @@
 		}
 		sched->event = event;
 		sched->frame = frame;
+		sched->func = func;
+		sched->arg = arg;
 		/* Put it in the list, in order */
 		cur = schedq;
 		while(cur && ((cur->when.tv_sec < sched->when.tv_sec) || 
@@ -384,6 +436,32 @@
 	}
 }
 
+static int iax_sched_del(struct iax_event *event, struct iax_frame *frame, sched_func func, void *arg, int all)
+{
+	struct iax_sched *cur, *tmp, *prev = NULL;
+
+	cur = schedq;
+	while (cur) {
+		if (cur->event == event && cur->frame == frame && cur->func == func && cur->arg == arg) {
+			if (prev)
+				prev->next = cur->next;
+			else
+				schedq = cur->next;
+			tmp = cur;
+			cur = cur->next;	
+			free(tmp);
+			if (!all)
+				return -1;
+		} else {
+			prev = cur;
+			cur = cur->next;
+		}
+	}
+	return 0;
+
+}
+
+
 int iax_time_to_next_event(void)
 {
 	struct timeval tv;
@@ -425,7 +503,18 @@
 		s->peercallno = 0;
 		s->transferpeer = 0;		/* for attended transfer */
 		s->next = sessions;
-		s->sendto = sendto;
+		s->sendto = iax_sendto;
+		s->pingid = -1;
+#ifdef NEWJB
+		s->jb = jb_new();
+		{
+			jb_conf jbconf;
+			jbconf.max_jitterbuf = 0;
+			jbconf.resync_threshold = 1000;
+			jbconf.max_contig_interp = 0;
+			jb_setconf(s->jb, &jbconf);
+		}
+#endif
 		sessions = s;
 	}
 	return s;
@@ -443,6 +532,33 @@
 	return 0;
 }
 
+int iax_get_netstats(struct iax_session *session, int *rtt, struct iax_netstat *local, struct iax_netstat *remote) {
+
+  if(!iax_session_valid(session)) return -1;
+
+  *rtt = session->pingtime;
+
+  *remote = session->remote_netstats;
+
+#ifdef NEWJB
+  {
+      jb_info stats;
+      jb_getinfo(session->jb, &stats);
+
+      local->jitter = stats.jitter;
+      /* XXX: should be short-term loss pct.. */
+      if(stats.frames_in == 0) stats.frames_in = 1;
+      local->losspct = stats.losspct/1000;
+      local->losscnt = stats.frames_lost;
+      local->packets = stats.frames_in;
+      local->delay = stats.current - stats.min;
+      local->dropped = stats.frames_dropped;
+      local->ooo = stats.frames_ooo;
+  }
+#endif
+  return 0;
+}
+
 static void add_ms(struct timeval *tv, int ms) {
   tv->tv_usec += ms * 1000;
   if(tv->tv_usec > 1000000) {
@@ -462,12 +578,10 @@
 	int voice = 0;
 	int genuine = 0;
 
-	if (f) {
-                if (f->frametype == AST_FRAME_VOICE) {
-                        voice = 1;
-                } else if (f->frametype == AST_FRAME_IAX) {
-                        genuine = 1;
-                }
+	if (f && f->frametype == AST_FRAME_VOICE) {
+		voice = 1;
+	} else if (!f || f->frametype == AST_FRAME_IAX) {
+		genuine = 1;
 	}
 	
 	
@@ -502,7 +616,7 @@
 		    add_ms(&session->offset, (int)(ms - session->nextpred)/10);
 		    
 		    if(!session->nextpred)		
-			session->nextpred = f->samples; 
+			session->nextpred = ms; 
 		    ms = session->nextpred; 
 		} else {
 		    /* in this case, just use the actual time, since
@@ -525,7 +639,7 @@
 		/* On a dataframe, use last value + 3 (to accomodate jitter buffer shrinking) 
 		   if appropriate unless it's a genuine frame */
 		if (genuine) {
-			if (ms <= session->lastsent)
+			if (ms <= (int) session->lastsent)
 				ms = session->lastsent + 3;
 		} else if (abs(ms - session->lastsent) <= 240) {
 			ms = session->lastsent + 3;
@@ -547,9 +661,179 @@
 	return ms;
 }
 
+#ifdef NEWJB
+static unsigned char get_n_bits_at(unsigned char *data, int n, int bit)
+{
+	int byte = bit / 8;       /* byte containing first bit */
+	int rem = 8 - (bit % 8);  /* remaining bits in first byte */
+	unsigned char ret = 0;
+	
+	if (n <= 0 || n > 8)
+		return 0;
+
+	if (rem < n) {
+		ret = (data[byte] << (n - rem));
+		ret |= (data[byte + 1] >> (8 - n + rem));
+	} else {
+		ret = (data[byte] >> (rem - n));
+	}
+
+	return (ret & (0xff >> (8 - n)));
+}
+
+static int speex_get_wb_sz_at(unsigned char *data, int len, int bit)
+{
+	static int SpeexWBSubModeSz[] = {
+		0, 36, 112, 192,
+		352, 0, 0, 0 };
+	int off = bit;
+	unsigned char c;
+
+	/* skip up to two wideband frames */
+	if (((len * 8 - off) >= 5) && 
+		get_n_bits_at(data, 1, off)) {
+		c = get_n_bits_at(data, 3, off + 1);
+		off += SpeexWBSubModeSz[c];
+
+		if (((len * 8 - off) >= 5) && 
+			get_n_bits_at(data, 1, off)) {
+			c = get_n_bits_at(data, 3, off + 1);
+			off += SpeexWBSubModeSz[c];
+
+			if (((len * 8 - off) >= 5) && 
+				get_n_bits_at(data, 1, off)) {
+				/* too many in a row */
+				DEBU(G "\tCORRUPT too many wideband streams in a row\n");
+				return -1;
+			}
+		}
+
+	}
+	return off - bit;
+}
+
+static int speex_get_samples(unsigned char *data, int len)
+{
+	static int SpeexSubModeSz[] = {
+		0, 43, 119, 160, 
+		220, 300, 364, 492, 
+		79, 0, 0, 0,
+		0, 0, 0, 0 };
+	static int SpeexInBandSz[] = { 
+		1, 1, 4, 4,
+		4, 4, 4, 4,
+		8, 8, 16, 16,
+		32, 32, 64, 64 };
+	int bit = 0;
+	int cnt = 0;
+	int off = 0;
+	unsigned char c;
+
+	DEBU(G "speex_get_samples(%d)\n", len);
+	while ((len * 8 - bit) >= 5) {
+		/* skip wideband frames */
+		off = speex_get_wb_sz_at(data, len, bit);
+		if (off < 0)  {
+			DEBU(G "\tERROR reading wideband frames\n");
+			break;
+		}
+		bit += off;
+
+		if ((len * 8 - bit) < 5) {
+			DEBU(G "\tERROR not enough bits left after wb\n");
+			break;
+		}
+
+		/* get control bits */
+		c = get_n_bits_at(data, 5, bit);
+		DEBU(G "\tCONTROL: %d at %d\n", c, bit);
+		bit += 5;
+
+		if (c == 15) { 
+			DEBU(G "\tTERMINATOR\n");
+			break;
+		} else if (c == 14) {
+			/* in-band signal; next 4 bits contain signal id */
+			c = get_n_bits_at(data, 4, bit);
+			bit += 4;
+			DEBU(G "\tIN-BAND %d bits\n", SpeexInBandSz[c]);
+			bit += SpeexInBandSz[c];
+		} else if (c == 13) {
+			/* user in-band; next 5 bits contain msg len */
+			c = get_n_bits_at(data, 5, bit);
+			bit += 5;
+			DEBU(G "\tUSER-BAND %d bytes\n", c);
+			bit += c * 8;
+		} else if (c > 8) {
+			DEBU(G "\tUNKNOWN sub-mode %d\n", c);
+			break;
+		} else {
+			/* skip number bits for submode (less the 5 control bits) */
+			DEBU(G "\tSUBMODE %d %d bits\n", c, SpeexSubModeSz[c]);
+			bit += SpeexSubModeSz[c] - 5;
+
+			cnt += 160; /* new frame */
+		}
+	}
+	DEBU(G "\tSAMPLES: %d\n", cnt);
+	return cnt;
+}
+
+static inline int get_interp_len(int format)
+{
+	return (format == AST_FORMAT_ILBC) ? 30 : 20;
+}
+
+static int get_sample_cnt(struct iax_event *e)
+{
+	int cnt = 0;
+
+	/*
+	 * In the case of zero length frames, do not return a cnt of 0
+	 */
+	if ( e->datalen == 0 ) {
+		return get_interp_len( e->subclass ) * 8;
+	}
+
+	switch (e->subclass) {
+	  case AST_FORMAT_SPEEX:
+	    cnt = speex_get_samples(e->data, e->datalen);
+	    break;
+	  case AST_FORMAT_G723_1:
+	    cnt = 240;		/* FIXME Not always the case */
+	    break;
+	  case AST_FORMAT_ILBC:
+	    cnt = 240 * (e->datalen / 50);
+	    break;
+	  case AST_FORMAT_GSM:
+	    cnt = 160 * (e->datalen / 33);
+	    break;
+	  case AST_FORMAT_G729A:
+	    cnt = 160 * (e->datalen / 20);
+	    break;
+	  case AST_FORMAT_SLINEAR:
+	    cnt = e->datalen / 2;
+	    break;
+	  case AST_FORMAT_LPC10:
+	    cnt = 22 * 8 + (((char *)(e->data))[7] & 0x1) * 8;
+	    break;
+	  case AST_FORMAT_ULAW:
+	  case AST_FORMAT_ALAW:
+	    cnt = e->datalen;
+	    break;
+	  case AST_FORMAT_ADPCM:
+	  case AST_FORMAT_G726:
+	    cnt = e->datalen * 2;
+	    break;
+	  default:
+	    return 0;
+	}
+	return cnt;
+}
+#endif
+
 static int iax_xmit_frame(struct iax_frame *f)
 {
-	struct ast_iax2_full_hdr *h = (f->data);
 	/* Send the frame raw */
 #ifdef DEBUG_SUPPORT
 	if (ntohs(h->scallno) & IAX_FLAG_FULL)
@@ -591,74 +875,82 @@
 				return -1;
 			}
 			memcpy(fc->data, f->data, f->datalen);
-			iax_sched_event(NULL, fc, fc->retrytime);
+			iax_sched_add(NULL, fc, NULL, NULL, fc->retrytime);
 			return iax_xmit_frame(fc);
 		}
 	} else
 		return -1;
 }
 
+void iax_set_networking(sendto_t st, recvfrom_t rf)
+{
+	iax_sendto = st;
+	iax_recvfrom = rf;
+}
+
 int iax_init(int preferredportno)
 {
 	int portno = preferredportno;
 	struct sockaddr_in sin;
-	int sinlen;
+	unsigned int sinlen;
 	int flags;
-	
-	if (netfd > -1) {
-		/* Sokay, just don't do anything */
-		DEBU(G "Already initialized.");
-		return 0;
-	}
-	netfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
-	if (netfd < 0) {
-		DEBU(G "Unable to allocate UDP socket\n");
-		IAXERROR "Unable to allocate UDP socket\n");
-		return -1;
-	}
-	
-	if (preferredportno == 0) 
-		preferredportno = IAX_DEFAULT_PORTNO;
-		
-	if (preferredportno > 0) {
-		sin.sin_family = AF_INET;
-		sin.sin_addr.s_addr = 0;
-		sin.sin_port = htons((short)preferredportno);
-		if (bind(netfd, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
-			DEBU(G "Unable to bind to preferred port.  Using random one instead.");
-		}
-	}
-	sinlen = sizeof(sin);
-	if (getsockname(netfd, (struct sockaddr *) &sin, &sinlen) < 0) {
-		close(netfd);
-		netfd = -1;
-		DEBU(G "Unable to figure out what I'm bound to.");
-		IAXERROR "Unable to determine bound port number.");
-	}
-#ifdef	WIN32
-	flags = 1;
-	if (ioctlsocket(netfd,FIONBIO,(unsigned long *) &flags)) {
-		_close(netfd);
-		netfd = -1;
-		DEBU(G "Unable to set non-blocking mode.");
-		IAXERROR "Unable to set non-blocking mode.");
-	}
-	
+
+	if(iax_recvfrom == (recvfrom_t) recvfrom) {
+	    if (netfd > -1) {
+		    /* Sokay, just don't do anything */
+		    DEBU(G "Already initialized.");
+		    return 0;
+	    }
+	    netfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+	    if (netfd < 0) {
+		    DEBU(G "Unable to allocate UDP socket\n");
+		    IAXERROR "Unable to allocate UDP socket\n");
+		    return -1;
+	    }
+	    
+	    if (preferredportno == 0) 
+		    preferredportno = IAX_DEFAULT_PORTNO;
+		    
+	    if (preferredportno > 0) {
+		    sin.sin_family = AF_INET;
+		    sin.sin_addr.s_addr = 0;
+		    sin.sin_port = htons((short)preferredportno);
+		    if (bind(netfd, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
+			    DEBU(G "Unable to bind to preferred port.  Using random one instead.");
+		    }
+	    }
+	    sinlen = sizeof(sin);
+	    if (getsockname(netfd, (struct sockaddr *) &sin, &sinlen) < 0) {
+		    close(netfd);
+		    netfd = -1;
+		    DEBU(G "Unable to figure out what I'm bound to.");
+		    IAXERROR "Unable to determine bound port number.");
+	    }
+#if defined(WIN32)  ||  defined(_WIN32_WCE)
+	    flags = 1;
+	    if (ioctlsocket(netfd,FIONBIO,(unsigned long *) &flags)) {
+		    closesocket(netfd);
+		    netfd = -1;
+		    DEBU(G "Unable to set non-blocking mode.");
+		    IAXERROR "Unable to set non-blocking mode.");
+	    }
+	    
 #else
-	if ((flags = fcntl(netfd, F_GETFL)) < 0) {
-		close(netfd);
-		netfd = -1;
-		DEBU(G "Unable to retrieve socket flags.");
-		IAXERROR "Unable to retrieve socket flags.");
-	}
-	if (fcntl(netfd, F_SETFL, flags | O_NONBLOCK) < 0) {
-		close(netfd);
-		netfd = -1;
-		DEBU(G "Unable to set non-blocking mode.");
-		IAXERROR "Unable to set non-blocking mode.");
-	}
+	    if ((flags = fcntl(netfd, F_GETFL)) < 0) {
+		    close(netfd);
+		    netfd = -1;
+		    DEBU(G "Unable to retrieve socket flags.");
+		    IAXERROR "Unable to retrieve socket flags.");
+	    }
+	    if (fcntl(netfd, F_SETFL, flags | O_NONBLOCK) < 0) {
+		    close(netfd);
+		    netfd = -1;
+		    DEBU(G "Unable to set non-blocking mode.");
+		    IAXERROR "Unable to set non-blocking mode.");
+	    }
 #endif
-	portno = ntohs(sin.sin_port);
+	    portno = ntohs(sin.sin_port);
+	}
 	srand(time(NULL));
 	callnums = rand() % 32767 + 1;
 	transfer_id = rand() % 32767 + 1;
@@ -812,6 +1104,8 @@
 		fr->retries = -1;
 		res = iax_xmit_frame(fr);
 	}
+	if( !now && fr!=NULL )
+	        iax_frame_free( fr ); 
 	return res;
 }
 
@@ -841,7 +1135,7 @@
 }
 #endif
 
-static int __send_command(struct iax_session *i, char type, int command, unsigned int ts, char *data, int datalen, int seqno, 
+static int __send_command(struct iax_session *i, char type, int command, unsigned int ts, unsigned char *data, int datalen, int seqno, 
 		int now, int transfer, int final, int samples)
 {
 	struct ast_frame f;
@@ -852,20 +1146,20 @@
 	f.mallocd = 0;
 	f.offset = 0;
 #ifdef __GNUC__
-	f.src = __FUNCTION__;
+	f.src = (char *) __FUNCTION__;
 #else
-	f.src = __FILE__;
+	f.src = (char *) __FILE__;
 #endif
 	f.data = data;
 	return iax_send(i, &f, ts, seqno, now, transfer, final);
 }
 
-static int send_command(struct iax_session *i, char type, int command, unsigned int ts, char *data, int datalen, int seqno)
+static int send_command(struct iax_session *i, char type, int command, unsigned int ts, unsigned char *data, int datalen, int seqno)
 {
 	return __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 0, 0);
 }
 
-static int send_command_final(struct iax_session *i, char type, int command, unsigned int ts, char *data, int datalen, int seqno)
+static int send_command_final(struct iax_session *i, char type, int command, unsigned int ts, unsigned char *data, int datalen, int seqno)
 {
 #if 0
 	/* It is assumed that the callno has already been locked */
@@ -877,17 +1171,17 @@
 	return r;
 }
 
-static int send_command_immediate(struct iax_session *i, char type, int command, unsigned int ts, char *data, int datalen, int seqno)
+static int send_command_immediate(struct iax_session *i, char type, int command, unsigned int ts, unsigned char *data, int datalen, int seqno)
 {
 	return __send_command(i, type, command, ts, data, datalen, seqno, 1, 0, 0, 0);
 }
 
-static int send_command_transfer(struct iax_session *i, char type, int command, unsigned int ts, char *data, int datalen)
+static int send_command_transfer(struct iax_session *i, char type, int command, unsigned int ts, unsigned char *data, int datalen)
 {
 	return __send_command(i, type, command, ts, data, datalen, 0, 0, 1, 0, 0);
 }
 
-static int send_command_samples(struct iax_session *i, char type, int command, unsigned int ts, char *data, int datalen, int seqno, int samples)
+static int send_command_samples(struct iax_session *i, char type, int command, unsigned int ts, unsigned char *data, int datalen, int seqno, int samples)
 {
 	return __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 0, samples);
 }
@@ -902,7 +1196,7 @@
 	memset(&ied, 0, sizeof(ied));
 	
 	// Copy The Transfer Destination Into The IE Structure
-	iax_ie_append_str(&ied, IAX_IE_CALLED_NUMBER, number);
+	iax_ie_append_str(&ied, IAX_IE_CALLED_NUMBER, (unsigned char *) number);
 	
 	// Send The Transfer Command - Asterisk Will Handle The Rest!			
 	res = send_command(session, AST_FRAME_IAX, IAX_COMMAND_TRANSFER, 0, ied.buf, ied.pos, -1);
@@ -941,6 +1235,15 @@
 	memset(&session->rxcore, 0, sizeof(session->rxcore));
 	memset(&session->offset, 0, sizeof(session->offset));
 	memset(&session->history, 0, sizeof(session->history));
+#ifdef NEWJB
+	{ /* Reset jitterbuffer */
+	    jb_frame frame;
+	    while(jb_getall(session->jb,&frame) == JB_OK) 
+		iax_event_free(frame.data);
+	
+	    jb_reset(session->jb);
+	}
+#endif
 	session->jitterbuffer = 0;
 	session->jitter = 0;
 	session->lag = 0;
@@ -1084,9 +1387,6 @@
 {
 	struct iax_session *s0, *s1;
 
-	complete_transfer(s, s->peercallno, 0, 1);
-	s->svoiceformat = -1;
-
 	s0 = s;
 	s1 = iax_find_session2(s0->transferpeer);
 	if (s1 != NULL &&
@@ -1101,6 +1401,11 @@
 		s0->transfer_moh = 0;
 		send_command_immediate(s0, AST_FRAME_IAX, IAX_COMMAND_UNQUELCH, 0, NULL, 0, s0->iseqno);
 	}
+
+	memset(&s->transfer, 0, sizeof(s->transfer));
+	s->transferring = TRANSFER_NONE;
+	s->transferpeer = 0;
+	s->transfer_moh = 0;
 }
 
 static void destroy_session(struct iax_session *session)
@@ -1136,6 +1441,15 @@
 				prev->next = session->next;
 			else
 				sessions = session->next;
+#ifdef NEWJB
+			{
+			    jb_frame frame;
+			    while(jb_getall(session->jb,&frame) == JB_OK) 
+				iax_event_free(frame.data);
+		   	
+			    jb_destroy(session->jb);
+			}
+#endif
 			free(session);
 			return;
 		}
@@ -1156,10 +1470,12 @@
 			/* Lag requests are never actually sent to the client, but
 			   other than that are handled as normal packets */
 			switch(event->etype) {
+				/* the user on the outside may need to look at the session so we will not free 
+				   it here anymore we will test for hangup event in iax_event_free and do it
+				   there.
+				 */
 			case IAX_EVENT_REJECT:
 			case IAX_EVENT_HANGUP:
-				/* Destroy this session -- it's no longer valid */
-				destroy_session(event->session);
 				return event;
 			case IAX_EVENT_LAGRQ:
 				event->etype = IAX_EVENT_LAGRP;
@@ -1190,7 +1506,7 @@
 	return send_command(session, AST_FRAME_DTMF, digit, 0, NULL, 0, -1);
 }
 
-int iax_send_voice(struct iax_session *session, int format, char *data, int datalen, int samples)
+int iax_send_voice(struct iax_session *session, int format, unsigned char *data, int datalen, int samples)
 {
 	/* Send a (possibly compressed) voice frame */
 	if (!session->quelch)
@@ -1198,13 +1514,13 @@
 	return 0;
 }
 
-int iax_send_cng(struct iax_session *session, int level, char *data, int datalen)
+int iax_send_cng(struct iax_session *session, int level, unsigned char *data, int datalen)
 {    
 	session->notsilenttx = 0;
 	return send_command(session, AST_FRAME_CNG, level, 0, data, datalen, -1);
 }
 
-int iax_send_image(struct iax_session *session, int format, char *data, int datalen)
+int iax_send_image(struct iax_session *session, int format, unsigned char *data, int datalen)
 {
 	/* Send an image frame */
 	return send_command(session, AST_FRAME_IMAGE, format, 0, data, datalen, -1);
@@ -1223,8 +1539,10 @@
 	tmp[255] = '\0';
 	strncpy(tmp, server, sizeof(tmp) - 1);
 	p = strchr(tmp, ':');
-	if (p)
-		portno = atoi(p);
+	if (p) {
+		*p = '\0';
+		portno = atoi(p+1);
+	}
 	
 	memset(&ied, 0, sizeof(ied));
 	if (secret)
@@ -1243,7 +1561,7 @@
 	session->peeraddr.sin_family = AF_INET;
 	strncpy(session->username, peer, sizeof(session->username) - 1);
 	session->refresh = refresh;
-	iax_ie_append_str(&ied, IAX_IE_USERNAME, peer);
+	iax_ie_append_str(&ied, IAX_IE_USERNAME, (unsigned char *) peer);
 	iax_ie_append_short(&ied, IAX_IE_REFRESH, refresh);
 	res = send_command(session, AST_FRAME_IAX, IAX_COMMAND_REGREQ, 0, ied.buf, ied.pos, -1);
 	return res;
@@ -1253,21 +1571,22 @@
 {
 	struct iax_ie_data ied;
 	memset(&ied, 0, sizeof(ied));
-	iax_ie_append_str(&ied, IAX_IE_CAUSE, reason ? reason : "Unspecified");
+	iax_ie_append_str(&ied, IAX_IE_CAUSE, reason ? (unsigned char *) reason : (unsigned char *) "Unspecified");
 	return send_command_final(session, AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied.buf, ied.pos, -1);
 }
 
 int iax_hangup(struct iax_session *session, char *byemsg)
 {
 	struct iax_ie_data ied;
+	iax_sched_del(NULL, NULL, send_ping, (void *) session, 1);
 	memset(&ied, 0, sizeof(ied));
-	iax_ie_append_str(&ied, IAX_IE_CAUSE, byemsg ? byemsg : "Normal clearing");
+	iax_ie_append_str(&ied, IAX_IE_CAUSE, byemsg ? (unsigned char *) byemsg : (unsigned char *) "Normal clearing");
 	return send_command_final(session, AST_FRAME_IAX, IAX_COMMAND_HANGUP, 0, ied.buf, ied.pos, -1);
 }
 
 int iax_sendurl(struct iax_session *session, char *url)
 {
-	return send_command(session, AST_FRAME_HTML, AST_HTML_URL, 0, url, strlen(url), -1);
+	return send_command(session, AST_FRAME_HTML, AST_HTML_URL, 0, (unsigned char *) url, strlen(url), -1);
 }
 
 int iax_ring_announce(struct iax_session *session)
@@ -1285,6 +1604,12 @@
 	return send_command(session, AST_FRAME_CONTROL, AST_CONTROL_BUSY, 0, NULL, 0, -1);
 }
 
+int iax_congestion(struct iax_session *session)
+{
+	return send_command(session, AST_FRAME_CONTROL, AST_CONTROL_CONGESTION, 0, NULL, 0, -1);
+}
+
+
 int iax_accept(struct iax_session *session, int format)
 {
 	struct iax_ie_data ied;
@@ -1305,12 +1630,12 @@
 
 int iax_send_url(struct iax_session *session, char *url, int link)
 {
-	return send_command(session, AST_FRAME_HTML, link ? AST_HTML_LINKURL : AST_HTML_URL, 0, url, strlen(url), -1);
+	return send_command(session, AST_FRAME_HTML, link ? AST_HTML_LINKURL : AST_HTML_URL, 0, (unsigned char *) url, strlen(url), -1);
 }
 
 int iax_send_text(struct iax_session *session, char *text)
 {
-	return send_command(session, AST_FRAME_TEXT, 0, 0, text, strlen(text), -1);
+	return send_command(session, AST_FRAME_TEXT, 0, 0, (unsigned char *) text, strlen(text) + 1, -1);
 }
 
 int iax_send_unlink(struct iax_session *session)
@@ -1325,14 +1650,53 @@
 
 static int iax_send_pong(struct iax_session *session, unsigned int ts)
 {
-	return send_command(session, AST_FRAME_IAX, IAX_COMMAND_PONG, ts, NULL, 0, -1);
+        struct iax_ie_data ied;
+
+        memset(&ied, 0, sizeof(ied));
+#ifdef NEWJB
+	{
+	    jb_info stats;
+	    jb_getinfo(session->jb, &stats);
+
+	    iax_ie_append_int(&ied,IAX_IE_RR_JITTER, stats.jitter);
+	    /* XXX: should be short-term loss pct.. */
+	    if(stats.frames_in == 0) stats.frames_in = 1;
+	    iax_ie_append_int(&ied,IAX_IE_RR_LOSS, 
+		((0xff & (stats.losspct/1000)) << 24 | (stats.frames_lost & 0x00ffffff)));
+	    iax_ie_append_int(&ied,IAX_IE_RR_PKTS, stats.frames_in);
+	    iax_ie_append_short(&ied,IAX_IE_RR_DELAY, stats.current - stats.min);
+	    iax_ie_append_int(&ied,IAX_IE_RR_DROPPED, stats.frames_dropped);
+	    iax_ie_append_int(&ied,IAX_IE_RR_OOO, stats.frames_ooo);
+	}
+#else
+	    iax_ie_append_int(&ied,IAX_IE_RR_JITTER, session->jitter);
+	    /* don't know, don't send! iax_ie_append_int(&ied,IAX_IE_RR_LOSS, 0); */
+	    /* don't know, don't send! iax_ie_append_int(&ied,IAX_IE_RR_PKTS, stats.frames_in); */
+	    /* don't know, don't send! iax_ie_append_short(&ied,IAX_IE_RR_DELAY, stats.current - stats.min); */
+#endif
+
+	return send_command(session, AST_FRAME_IAX, IAX_COMMAND_PONG, ts, ied.buf, ied.pos, -1);
 }
 
+/* external API; deprecated since we send pings ourselves now (finally) */
 int iax_send_ping(struct iax_session *session)
 {
 	return send_command(session, AST_FRAME_IAX, IAX_COMMAND_PING, 0, NULL, 0, -1);
 }
 
+/* scheduled ping sender; sends ping, then reschedules */
+static void send_ping(void *s)
+{
+	struct iax_session *session = (struct iax_session *)s;
+
+	/* important, eh? */
+	if(!iax_session_valid(session)) return;
+
+	send_command(session, AST_FRAME_IAX, IAX_COMMAND_PING, 0, NULL, 0, -1);
+	session->pingid = iax_sched_add(NULL,NULL, send_ping, (void *)session, ping_time * 1000);
+	return;
+}
+
 static int iax_send_lagrp(struct iax_session *session, unsigned int ts)
 {
 	return send_command(session, AST_FRAME_IAX, IAX_COMMAND_LAGRP, ts, NULL, 0, -1);
@@ -1383,11 +1747,11 @@
 		MD5Update(&md5, (const unsigned char *) challenge, strlen(challenge));
 		MD5Update(&md5, (const unsigned char *) password, strlen(password));
 		MD5Final((unsigned char *) reply, &md5);
-		bzero(realreply, sizeof(realreply));
+		memset(realreply, 0, sizeof(realreply));
 		convert_reply(realreply, (unsigned char *) reply);
-		iax_ie_append_str(&ied, IAX_IE_MD5_RESULT, realreply);
+		iax_ie_append_str(&ied, IAX_IE_MD5_RESULT, (unsigned char *) realreply);
 	} else {
-		iax_ie_append_str(&ied, IAX_IE_MD5_RESULT, password);
+		iax_ie_append_str(&ied, IAX_IE_MD5_RESULT, (unsigned char *) password);
 	}
 	return send_command(session, AST_FRAME_IAX, IAX_COMMAND_AUTHREP, 0, ied.buf, ied.pos, -1);
 }
@@ -1399,18 +1763,18 @@
 	char realreply[256];
 	struct iax_ie_data ied;
 	memset(&ied, 0, sizeof(ied));
-	iax_ie_append_str(&ied, IAX_IE_USERNAME, session->username);
+	iax_ie_append_str(&ied, IAX_IE_USERNAME, (unsigned char *) session->username);
 	iax_ie_append_short(&ied, IAX_IE_REFRESH, session->refresh);
 	if ((methods & IAX_AUTHMETHOD_MD5) && challenge) {
 		MD5Init(&md5);
 		MD5Update(&md5, (const unsigned char *) challenge, strlen(challenge));
 		MD5Update(&md5, (const unsigned char *) password, strlen(password));
 		MD5Final((unsigned char *) reply, &md5);
-		bzero(realreply, sizeof(realreply));
+		memset(realreply, 0, sizeof(realreply));
 		convert_reply(realreply, (unsigned char *) reply);
-		iax_ie_append_str(&ied, IAX_IE_MD5_RESULT, realreply);
+		iax_ie_append_str(&ied, IAX_IE_MD5_RESULT, (unsigned char *) realreply);
 	} else {
-		iax_ie_append_str(&ied, IAX_IE_MD5_RESULT, password);
+		iax_ie_append_str(&ied, IAX_IE_MD5_RESULT, (unsigned char *) password);
 	}
 	return send_command(session, AST_FRAME_IAX, IAX_COMMAND_REGREQ, 0, ied.buf, ied.pos, -1);
 }
@@ -1420,7 +1784,7 @@
 {
 	struct iax_ie_data ied;
 	memset(&ied, 0, sizeof(ied));
-	iax_ie_append_str(&ied, IAX_IE_CALLED_NUMBER, number);
+	iax_ie_append_str(&ied, IAX_IE_CALLED_NUMBER, (unsigned char *) number);
 	return send_command(session, AST_FRAME_IAX, IAX_COMMAND_DIAL, 0, ied.buf, ied.pos, -1);
 }
 
@@ -1438,10 +1802,60 @@
 {
 	struct iax_ie_data ied;
 	memset(&ied, 0, sizeof(ied));
-	iax_ie_append_str(&ied, IAX_IE_CALLED_NUMBER, number);
+	iax_ie_append_str(&ied, IAX_IE_CALLED_NUMBER, (unsigned char *) number);
 	return send_command(session, AST_FRAME_IAX, IAX_COMMAND_DPREQ, 0, ied.buf, ied.pos, -1);
 }
 
+static inline int which_bit(unsigned int i)
+{
+    char x;
+    for(x = 0; x < 32; x++) {
+        if ((1U << x) == i) {
+            return x + 1;
+        }
+    }
+    return 0;
+}
+
+char iax_pref_codec_add(struct iax_session *session, unsigned int format)
+{
+	int diff = (int) 'A';
+	session->codec_order[session->codec_order_len++] = (which_bit(format)) + diff;
+	session->codec_order[session->codec_order_len] = '\0';
+	return session->codec_order[session->codec_order_len-1];
+}
+
+
+void iax_pref_codec_del(struct iax_session *session, unsigned int format)
+{
+	int diff = (int) 'A';
+	int x;
+	char old[32];
+	char remove = which_bit(format) + diff;
+
+	strncpy(old, session->codec_order, sizeof(old));
+	session->codec_order_len = 0;
+
+	for (x = 0;  x < (int) strlen(old);  x++) {
+		if (old[x] != remove) {
+			session->codec_order[session->codec_order_len++] = old[x];
+		}
+	}
+	session->codec_order[session->codec_order_len] = '\0';
+}
+
+int iax_pref_codec_get(struct iax_session *session, unsigned int *array, int len)
+{
+	int diff = (int) 'A';
+	int x;
+	
+	for (x = 0; x < session->codec_order_len && x < len; x++) {
+		array[x] = (1 << (session->codec_order[x] - diff - 1));
+	}
+
+	return x;
+}
+
 int iax_call(struct iax_session *session, char *cidnum, char *cidname, char *ich, char *lang, int wait, int formats, int capabilities)
 {
 	char tmp[256]="";
@@ -1462,17 +1876,22 @@
 	strncpy(tmp, ich, sizeof(tmp) - 1);	
 	iax_ie_append_short(&ied, IAX_IE_VERSION, IAX_PROTO_VERSION);
 	if (cidnum)
-		iax_ie_append_str(&ied, IAX_IE_CALLING_NUMBER, cidnum);
+		iax_ie_append_str(&ied, IAX_IE_CALLING_NUMBER, (unsigned char *) cidnum);
 	if (cidname)
-		iax_ie_append_str(&ied, IAX_IE_CALLING_NAME, cidname);
-	
+		iax_ie_append_str(&ied, IAX_IE_CALLING_NAME, (unsigned char *) cidname);
+
+	if (session->codec_order_len) {
+		iax_ie_append_str(&ied, IAX_IE_CODEC_PREFS, (unsigned char *) session->codec_order);
+	}
+
 	session->capability = capabilities;
+	session->pingid = iax_sched_add(NULL,NULL, send_ping, (void *)session, 2 * 1000);
 
 	/* XXX We should have a preferred format XXX */
 	iax_ie_append_int(&ied, IAX_IE_FORMAT, formats);
 	iax_ie_append_int(&ied, IAX_IE_CAPABILITY, capabilities);
 	if (lang)
-		iax_ie_append_str(&ied, IAX_IE_LANGUAGE, lang);
+		iax_ie_append_str(&ied, IAX_IE_LANGUAGE, (unsigned char *) lang);
 	
 	/* Part 1 is [user[:password]@]peer[:port] */
 	part1 = strtok(tmp, "/");
@@ -1516,13 +1935,13 @@
 		context = NULL;
 	}
 	if (username)
-		iax_ie_append_str(&ied, IAX_IE_USERNAME, username);
+		iax_ie_append_str(&ied, IAX_IE_USERNAME, (unsigned char *) username);
 	if (exten && strlen(exten))
-		iax_ie_append_str(&ied, IAX_IE_CALLED_NUMBER, exten);
+		iax_ie_append_str(&ied, IAX_IE_CALLED_NUMBER, (unsigned char *) exten);
 	if (dnid && strlen(dnid))
-		iax_ie_append_str(&ied, IAX_IE_DNID, dnid);
+		iax_ie_append_str(&ied, IAX_IE_DNID, (unsigned char *) dnid);
 	if (context && strlen(context))
-		iax_ie_append_str(&ied, IAX_IE_CALLED_CONTEXT, context);
+		iax_ie_append_str(&ied, IAX_IE_CALLED_CONTEXT, (unsigned char *) context);
 
 	/* Setup host connection */
 	hp = gethostbyname(hostname);
@@ -1558,6 +1977,7 @@
 		return ms;
 }
 
+#ifdef notdef_cruft
 static int match(struct sockaddr_in *sin, short callno, short dcallno, struct iax_session *cur)
 {
 	if ((cur->peeraddr.sin_addr.s_addr == sin->sin_addr.s_addr) &&
@@ -1578,6 +1998,7 @@
 	}
 	return 0;
 }
+#endif
 
 /* splitted match into 2 passes otherwise causing problem of matching
    up the wrong session using the dcallno and the peercallno because
@@ -1656,6 +2077,7 @@
 		cur->peeraddr.sin_addr.s_addr = sin->sin_addr.s_addr;
 		cur->peeraddr.sin_port = sin->sin_port;
 		cur->peeraddr.sin_family = AF_INET;
+		cur->pingid = iax_sched_add(NULL,NULL, send_ping, (void *)cur, 2 * 1000);
 		DEBU(G "Making new session, peer callno %d, our callno %d\n", callno, cur->callno);
 	} else {
 		DEBU(G "No session, peer = %d, us = %d\n", callno, dcallno);
@@ -1680,6 +2102,36 @@
 
 #define FUDGE 1
 
+#ifdef NEWJB
+/* From chan_iax2/steve davies:  need to get permission from steve or digium, I guess */
+static long unwrap_timestamp(long ts, long last)
+{
+        int x;
+
+        if ( (ts & 0xFFFF0000) == (last & 0xFFFF0000) ) {
+                x = ts - last;
+                if (x < -50000) {
+                        /* Sudden big jump backwards in timestamp:
+                           What likely happened here is that miniframe timestamp has circled but we haven't
+                           gotten the update from the main packet.  We'll just pretend that we did, and
+                           update the timestamp appropriately. */
+                        ts = ( (last & 0xFFFF0000) + 0x10000) | (ts & 0xFFFF);
+                                DEBU(G "schedule_delivery: pushed forward timestamp\n");
+                }
+                if (x > 50000) {
+                        /* Sudden apparent big jump forwards in timestamp:
+                           What's likely happened is this is an old miniframe belonging to the previous
+                           top-16-bit timestamp that has turned up out of order.
+                           Adjust the timestamp appropriately. */
+                        ts = ( (last & 0xFFFF0000) - 0x10000) | (ts & 0xFFFF);
+                                DEBU(G "schedule_delivery: pushed back timestamp\n");
+                }
+        }
+	return ts;
+}
+#endif
+
+
 static struct iax_event *schedule_delivery(struct iax_event *e, unsigned int ts, int updatehistory)
 {
 	/* 
@@ -1687,10 +2139,11 @@
 	 * Dynamically adjust the jitterbuffer and decide how long to wait
 	 * before delivering the packet.
 	 */
+#ifndef NEWJB
 	int ms, x;
 	int drops[MEMORY_SIZE];
 	int min, max=0, maxone=0, y, z, match;
-
+#endif
 
 #ifdef EXTREME_DEBUG	
 	DEBU(G "[%p] We are at %d, packet is for %d\n", e->session, calc_rxstamp(e->session), ts);
@@ -1715,6 +2168,37 @@
 		e->session->lastts = ts;
 	}
 #endif
+
+#ifdef NEWJB
+	{
+	    int type = JB_TYPE_CONTROL;
+	    int len = 0;
+
+	    if(e->etype == IAX_EVENT_VOICE) {
+	      type = JB_TYPE_VOICE;
+	      len = get_sample_cnt(e) / 8;
+	    } else if(e->etype == IAX_EVENT_CNG) {
+	      type = JB_TYPE_SILENCE;	
+	    }
+
+	    /* unwrap timestamp */
+	    ts = unwrap_timestamp(ts,e->session->last_ts);
+
+	    /* move forward last_ts if it's greater.  We do this _after_ unwrapping, because
+	     * asterisk _still_ has cases where it doesn't send full frames when it ought to */
+	    if(ts > e->session->last_ts) {
+		e->session->last_ts = ts;		
+	    }
+
+
+	    /* insert into jitterbuffer */
+	    /* TODO: Perhaps we could act immediately if it's not droppable and late */
+	    if(jb_put(e->session->jb, e, type, len, ts, calc_rxstamp(e->session)) == JB_DROP) {
+		  iax_event_free(e);
+	    }
+
+	}
+#else
 	
 	/* How many ms from now should this packet be delivered? (remember
 	   this can be a negative number, too */
@@ -1824,7 +2308,7 @@
 			   just drop a hangup frame because it's late, or a ping, or some such.
 			   That kinda ruins retransmissions too ;-) */
 			/* Queue for immediate delivery */
-			iax_sched_event(e, NULL, 0);
+			iax_sched_add(e, NULL, NULL, NULL, 0);
 			return NULL;
 			//return e;
 		}
@@ -1834,10 +2318,11 @@
 		return NULL;
 	}
 	/* We need this to be delivered in the future, so we use our scheduler */
-	iax_sched_event(e, NULL, ms);
+	iax_sched_add(e, NULL, NULL, NULL, ms);
 #ifdef EXTREME_DEBUG
 	DEBU(G "Delivering packet in %d ms\n", ms);
 #endif
+#endif /* NEWJB */
 	return NULL;
 	
 }
@@ -1851,11 +2336,7 @@
 		return csub;
 }
 
-static
-#ifndef	WIN32
-inline
-#endif
-char *extract(char *src, char *string)
+static inline char *extract(char *src, char *string)
 {
 	/* Extract and duplicate what we need from a string */
 	char *s, *t;
@@ -1885,8 +2366,13 @@
 	int updatehistory = 1;
 	ts = ntohl(fh->ts);
 	/* don't run last_ts backwards; i.e. for retransmits and the like */
-	if (ts > session->last_ts) 
+	if (ts > session->last_ts &&
+	    (fh->type == AST_FRAME_IAX && 
+	     subclass != IAX_COMMAND_ACK &&
+	     subclass != IAX_COMMAND_PONG &&
+	     subclass != IAX_COMMAND_LAGRP)) {
 	    session->last_ts = ts;
+	}
 
 
 #ifdef DEBUG_SUPPORT
@@ -2004,6 +2490,15 @@
 			}
 			e = schedule_delivery(e, ts, updatehistory);
 			break;
+		case AST_FRAME_CNG:
+			e->etype = IAX_EVENT_CNG;
+			e->subclass = subclass;
+                        if (datalen) {
+                                memcpy(e->data, fh->iedata, datalen);
+                                e->datalen = datalen;
+                        }
+                        e = schedule_delivery(e, ts, updatehistory);
+                        break;
 		case AST_FRAME_IAX:
 			/* Parse IE's */
 			if (datalen) {
@@ -2021,6 +2516,10 @@
 				/* This is a new, incoming call */
 				/* save the capability for validation */
 				session->capability = e->ies.capability;
+				if (e->ies.codec_prefs) {
+					strncpy(session->codec_order, e->ies.codec_prefs, sizeof(session->codec_order));
+					session->codec_order_len = strlen(session->codec_order);
+				}
 				e->etype = IAX_EVENT_CONNECT;
 				e = schedule_delivery(e, ts, updatehistory);
 				break;
@@ -2060,12 +2559,22 @@
 				e = schedule_delivery(e, ts, updatehistory);
 				break;
 			case IAX_COMMAND_PING:
+			case IAX_COMMAND_POKE:
 				/* PINGS and PONGS don't get scheduled; */
 				e->etype = IAX_EVENT_PING;
 				e->ts = ts;
 				break;
 			case IAX_COMMAND_PONG:
 				e->etype = IAX_EVENT_PONG;
+				/* track weighted average of ping time */
+				session->pingtime = ((2 * session->pingtime) + (calc_timestamp(session,0,NULL) - ts)) / 3;
+				session->remote_netstats.jitter = e->ies.rr_jitter;
+				session->remote_netstats.losspct = e->ies.rr_loss >> 24;;
+				session->remote_netstats.losscnt = e->ies.rr_loss & 0xffffff;
+				session->remote_netstats.packets = e->ies.rr_pkts;
+				session->remote_netstats.delay = e->ies.rr_delay;
+				session->remote_netstats.dropped = e->ies.rr_dropped;
+				session->remote_netstats.ooo = e->ies.rr_ooo;
 				break;
 			case IAX_COMMAND_ACCEPT:
 				if (e->ies.format & session->capability) {
@@ -2079,7 +2588,7 @@
 						REJECT event.
 					 */
 					memset(&ied, 0, sizeof(ied));
-					iax_ie_append_str(&ied, IAX_IE_CAUSE, "Unable to negotiate codec");
+					iax_ie_append_str(&ied, IAX_IE_CAUSE, (unsigned char *) "Unable to negotiate codec");
 					send_command_final(session, AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied.buf, ied.pos, -1);
 					e->etype = IAX_EVENT_REJECT;
 				}
@@ -2157,6 +2666,8 @@
 					complete_transfer(session, session->peercallno, 0, 1);
 				}
 				e->etype = IAX_EVENT_TRANSFER;
+				/* notify that asterisk no longer sitting between peers */
+				e = schedule_delivery(e, ts, updatehistory);
 				break;
 			case IAX_COMMAND_QUELCH:
 				e->etype = IAX_EVENT_QUELCH;
@@ -2231,8 +2742,10 @@
 				e->etype = IAX_EVENT_LINKURL;
 				/* Fall through */
 			case AST_HTML_URL:
-				if (!e->etype)
+				if (e->etype == -1)
 					e->etype = IAX_EVENT_URL;
+				e->subclass = fh->csub;
+				e->datalen = datalen;
 				if (datalen) {
 					memcpy(e->data, fh->iedata, datalen);
 				}
@@ -2284,12 +2797,12 @@
 			e->etype = IAX_EVENT_VOICE;
 			e->session = session;
 			e->subclass = session->voiceformat;
+			e->datalen = datalen;
 			if (datalen) {
 #ifdef EXTREME_DEBUG
 				DEBU(G "%d bytes of voice\n", datalen);
 #endif
 				memcpy(e->data, mh->data, datalen);
-				e->datalen = datalen;
 			}
 			ts = (session->last_ts & 0xFFFF0000) | ntohs(mh->ts);
 			return schedule_delivery(e, ts, updatehistory);
@@ -2310,14 +2823,19 @@
 
 static struct iax_event *iax_net_read(void)
 {
-	char buf[65536];
+	unsigned char buf[65536];
 	int res;
 	struct sockaddr_in sin;
-	int sinlen;
+	unsigned int sinlen;
 	sinlen = sizeof(sin);
-	res = recvfrom(netfd, buf, sizeof(buf), 0, (struct sockaddr *) &sin, &sinlen);
+	res = iax_recvfrom(netfd, buf, sizeof(buf), 0, (struct sockaddr *) &sin, &sinlen);
 	if (res < 0) {
-#ifdef	WIN32
+#if defined(_WIN32_WCE)
+		if (WSAGetLastError() != WSAEWOULDBLOCK) {
+			DEBU(G "Error on read: %d\n", WSAGetLastError());
+			IAXERROR "Read error on network socket: ???");
+		}
+#elif defined(WIN32)  ||  defined(_WIN32_WCE)
 		if (WSAGetLastError() != WSAEWOULDBLOCK) {
 			DEBU(G "Error on read: %d\n", WSAGetLastError());
 			IAXERROR "Read error on network socket: %s", strerror(errno));
@@ -2333,6 +2851,40 @@
 	return iax_net_process(buf, res, &sin);
 }
 
+static struct iax_session *iax_txcnt_session(struct ast_iax2_full_hdr *fh, int datalen,
+				struct sockaddr_in *sin, short callno, short dcallno)
+{
+	int subclass = uncompress_subclass(fh->csub);
+	unsigned char buf[ 65536 ]; /* allocated on stack with same size as iax_net_read() */
+	struct iax_ies ies;
+	struct iax_session *cur;
+
+	if ((fh->type != AST_FRAME_IAX) || (subclass != IAX_COMMAND_TXCNT) || (!datalen)) {
+		return NULL; /* special handling for TXCNT only */
+	}
+	memcpy(buf, fh->iedata, datalen);	/* prepare local buf for iax_parse_ies() */
+
+	if (iax_parse_ies(&ies, buf, datalen)) {
+		return NULL;	/* Unable to parse IE's */
+	}
+	if (!ies.transferid) {
+		return NULL;	/* TXCNT without proper IAX_IE_TRANSFERID */
+	}
+	for( cur=sessions; cur; cur=cur->next ) {
+		if ((cur->transferring) && (cur->transferid == (int) ies.transferid) &&
+		   	(cur->callno == dcallno) && (cur->transfercallno == callno)) {
+			/* We're transferring ---
+			 * 	skip address/port checking which would fail while remote peer behind symmetric NAT
+			 * 	verify transferid instead
+			 */
+			cur->transfer.sin_addr.s_addr = sin->sin_addr.s_addr;	/* setup for further handling */
+			cur->transfer.sin_port = sin->sin_port;
+			break;		
+		}
+	}
+	return cur;
+}
+
 struct iax_event *iax_net_process(unsigned char *buf, int len, struct sockaddr_in *sin)
 {
 	struct ast_iax2_full_hdr *fh = (struct ast_iax2_full_hdr *)buf;
@@ -2347,6 +2899,8 @@
 		}
 		/* We have a full header, process appropriately */
 		session = iax_find_session(sin, ntohs(fh->scallno) & ~IAX_FLAG_FULL, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS, 1);
+		if (!session)
+			session = iax_txcnt_session(fh, len-sizeof(struct ast_iax2_full_hdr), sin, ntohs(fh->scallno) & ~IAX_FLAG_FULL, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS);
 		if (session) 
 			return iax_header_to_event(session, fh, len - sizeof(struct ast_iax2_full_hdr), sin);
 		DEBU(G "No session?\n");
@@ -2407,11 +2961,13 @@
 				free(cur);
 				return event;
 			}
-		} else {
+		} else if(frame) {
 			/* It's a frame, transmit it and schedule a retry */
 			if (frame->retries < 0) {
 				/* It's been acked.  No need to send it.   Destroy the old
-				   frame */
+				   frame. If final, destroy the session. */
+				if (frame->final)
+					destroy_session(frame->session);
 				if (frame->data)
 					free(frame->data);
 				free(frame);
@@ -2419,17 +2975,30 @@
 				if (frame->transfer) {
 					/* Send a transfer reject since we weren't able to connect */
 					iax_send_txrej(frame->session);
+					if (frame->data)
+						free(frame->data);
+					free(frame);
 					free(cur);
 					break;
 				} else {
-					/* We haven't been able to get an ACK on this packet.  We should
-					   destroy its session */
-					event = (struct iax_event *)malloc(sizeof(struct iax_event));
-					if (event) {
-						event->etype = IAX_EVENT_TIMEOUT;
-						event->session = frame->session;
-						free(cur);
-						return handle_event(event);
+					/* We haven't been able to get an ACK on this packet. If a 
+					   final frame, destroy the session, otherwise, pass up timeout */
+					if (frame->final) {
+						destroy_session(frame->session);
+						if (frame->data)
+							free(frame->data);
+						free(frame);
+					} else {
+						event = (struct iax_event *)malloc(sizeof(struct iax_event));
+						if (event) {
+							event->etype = IAX_EVENT_TIMEOUT;
+							event->session = frame->session;
+							if (frame->data)
+								free(frame->data);
+							free(frame);
+							free(cur);
+							return handle_event(event);
+						}
 					}
 				}
 			} else {
@@ -2448,13 +3017,74 @@
 				fh->dcallno = htons(IAX_FLAG_RETRANS | frame->dcallno);
 				iax_xmit_frame(frame);
 				/* Schedule another retransmission */
-				printf("Scheduling retransmission %d\n", frame->retries);
-				iax_sched_event(NULL, frame, frame->retrytime);
+				DEBU(G "Scheduling retransmission %d\n", frame->retries);
+				iax_sched_add(NULL, frame, NULL, NULL, frame->retrytime);
 			}
+		} else if (cur->func) {
+		    cur->func(cur->arg);
 		}
 		free(cur);
 	}
 
+#ifdef NEWJB
+	/* get jitterbuffer-scheduled events */
+	{
+	    struct iax_session *cur;
+	    jb_frame frame;
+	    for(cur=sessions; cur; cur=cur->next) {
+		int ret;
+		long now;
+		long next;
+
+		now = (tv.tv_sec - cur->rxcore.tv_sec) * 1000 +
+		      (tv.tv_usec - cur->rxcore.tv_usec) / 1000;
+
+		if(now > (next = jb_next(cur->jb))) {
+			/* interp len no longer hardcoded, now determined by get_interp_len */
+			ret = jb_get(cur->jb,&frame,now,get_interp_len(cur->voiceformat));
+
+		    switch(ret) {
+			case JB_OK:
+//			    if(frame.type == JB_TYPE_VOICE && next + 20 != jb_next(cur->jb)) fprintf(stderr, "NEXT %ld is not %ld+20!\n", jb_next(cur->jb), next);
+			    event = frame.data;
+			    event = handle_event(event);
+			    if (event) {
+				    return event;
+			    }
+			break;
+			case JB_INTERP:
+//			    if(next + 20 != jb_next(cur->jb)) fprintf(stderr, "NEXT %ld is not %ld+20!\n", jb_next(cur->jb), next);
+			    /* create an interpolation frame */
+			    //fprintf(stderr, "Making Interpolation frame\n");
+			    event = (struct iax_event *)malloc(sizeof(struct iax_event));
+			    if (event) {
+				    event->etype    = IAX_EVENT_VOICE;
+				    event->subclass = cur->voiceformat;
+				    event->ts	    = now; /* XXX: ??? applications probably ignore this anyway */
+				    event->session  = cur;
+				    event->datalen  = 0;
+				    event = handle_event(event);
+				    if(event)
+					return event;
+			    }
+			break;
+			case JB_DROP:
+//			    if(next != jb_next(cur->jb)) fprintf(stderr, "NEXT %ld is not next %ld!\n", jb_next(cur->jb), next);
+			    iax_event_free(frame.data);
+			break;
+			case JB_NOFRAME:
+			case JB_EMPTY:
+			    /* do nothing */
+			break;
+			default:
+			    /* shouldn't happen */
+			break;
+		    }
+		}
+	    }
+	}
+
+#endif
 	/* Now look for networking events */
 	if (blocking) {
 		/* Block until there is data if desired */
@@ -2463,7 +3093,7 @@
 
 		FD_ZERO(&fds);
 		FD_SET(netfd, &fds);
-	
+
 		nextEventTime = iax_time_to_next_event(); 
 
 		if(nextEventTime < 0) 
@@ -2489,8 +3119,28 @@
 	return session->peeraddr;
 }
 
+void iax_session_destroy(struct iax_session **session) 
+{
+	destroy_session(*session);
+	*session = NULL;
+}
+
 void iax_event_free(struct iax_event *event)
 {
+	/* 
+	   We gave the user a chance to play with the session now we need to destroy it 
+	   if you are not calling this function on every event you read you are now going
+	   to leak sessions as well as events!
+	*/
+	switch(event->etype) {
+	case IAX_EVENT_REJECT:
+	case IAX_EVENT_HANGUP:
+		/* Destroy this session -- it's no longer valid */
+		if (event->session) { /* maybe the user did it already */
+			destroy_session(event->session);
+		}
+		break;
+	}
 	free(event);
 }
 
@@ -2516,5 +3166,5 @@
 		session->transfer_moh = 1;
 	}
 		
-	return send_command(session, AST_FRAME_IAX, IAX_COMMAND_QUELCH, 0, ied.buf, ied.pos, -1);		
+	return send_command(session, AST_FRAME_IAX, IAX_COMMAND_QUELCH, 0, ied.buf, ied.pos, -1);
 }
diff -Naur libiax2.old/src/iax-client.h libiax2/src/iax-client.h
--- libiax2.old/src/iax-client.h	2006-02-12 22:12:27.000000000 +0100
+++ libiax2/src/iax-client.h	2006-02-12 22:44:27.000000000 +0100
@@ -76,6 +76,7 @@
 #define IAX_EVENT_TEXT		29		/* Text Frame :-) */
 #define IAX_EVENT_REGREJ  30		/* Registration reply */
 #define IAX_EVENT_LINKURL	31		/* Unlink */
+#define IAX_EVENT_CNG	32		/* Comfort-noise (almost silence) */
 
 /* moved from iax.c to support attended transfer */
 #define IAX_EVENT_REREQUEST	999
@@ -86,14 +87,17 @@
 
 #define IAX_SCHEDULE_FUZZ 0			/* ms of fuzz to drop */
 
-#ifdef WIN32
+#if defined(WIN32)  ||  defined(_WIN32_WCE)
 #if defined(_MSC_VER)
 typedef int (__stdcall *sendto_t)(SOCKET, const char *, int, int, const struct sockaddr *, int);
+typedef int (__stdcall *recvfrom_t)(SOCKET, char *, int, int, struct sockaddr *, int *);
 #else
 typedef int PASCAL (*sendto_t)(SOCKET, const char *, int, int, const struct sockaddr *, int);
+typedef int PASCAL (*recvfrom_t)(SOCKET, char *buf, int len, int flags, struct sockaddr *from, int *fromlen);
 #endif
 #else
 typedef int (*sendto_t)(int, const void *, size_t, int, const struct sockaddr *, socklen_t);
+typedef int (*recvfrom_t)(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen);
 #endif
 
 struct iax_event {
@@ -143,15 +147,16 @@
 
 /* Front ends for sending events */
 extern int iax_send_dtmf(struct iax_session *session, char digit);
-extern int iax_send_voice(struct iax_session *session, int format, char *data, int datalen, int samples);
-extern int iax_send_cng(struct iax_session *session, int level, char *data, int datalen);
-extern int iax_send_image(struct iax_session *session, int format, char *data, int datalen);
+extern int iax_send_voice(struct iax_session *session, int format, unsigned char *data, int datalen, int samples);
+extern int iax_send_cng(struct iax_session *session, int level, unsigned char *data, int datalen);
+extern int iax_send_image(struct iax_session *session, int format, unsigned char *data, int datalen);
 extern int iax_send_url(struct iax_session *session, char *url, int link);
 extern int iax_send_text(struct iax_session *session, char *text);
 extern int iax_send_ping(struct iax_session *session);
 extern int iax_load_complete(struct iax_session *session);
 extern int iax_reject(struct iax_session *session, char *reason);
 extern int iax_busy(struct iax_session *session);
+extern int iax_congestion(struct iax_session *session);
 extern int iax_hangup(struct iax_session *session, char *byemsg);
 extern int iax_call(struct iax_session *session, char *cidnum, char *cidname, char *ich, char *lang, int wait, int format, int capability);
 extern int iax_accept(struct iax_session *session, int format);
@@ -175,7 +180,7 @@
 extern void iax_enable_debug(void);
 extern void iax_disable_debug(void);
 
-/* For attended trnasfer, application create a new session,
+/* For attended transfer, application create a new session,
  * make a call on the new session.
  * On answer of the new session, call iax_setup_transfer and wait for
  * IAX_EVENT_TXREADY when both sides are completed succefully or
@@ -184,15 +189,39 @@
  */
 extern int iax_setup_transfer(struct iax_session *s0, struct iax_session *s1);
 
-#if defined(__cplusplus)
-}
-#endif
+struct iax_netstat {
+	int jitter;
+	int losspct;
+	int losscnt;
+	int packets;
+	int delay;
+	int dropped;
+	int ooo;
+};
+/* fills in rtt, and an iax_netstat structure for each of local/remote directions of call */
+extern int iax_get_netstats(struct iax_session *s, int *rtt, struct iax_netstat *local, struct iax_netstat *remote);
+
+
+extern void iax_set_private(struct iax_session *s, void *pvt);
+extern void *iax_get_private(struct iax_session *s);
+extern void iax_set_sendto(struct iax_session *s, sendto_t sendto);
 
-void iax_set_private(struct iax_session *s, void *pvt);
-void *iax_get_private(struct iax_session *s);
-void iax_set_sendto(struct iax_session *s, sendto_t sendto);
+/* to use application networking instead of internal, set call this instead of iax_init,
+ * and pass in sendto and recvfrom replacements.  blocking reads may not be implemented */
+extern void iax_set_networking(sendto_t st, recvfrom_t rf);
+
+/* destroy an iax session */
+extern void iax_session_destroy(struct iax_session **session);
 
 /* Handle externally received frames */
 struct iax_event *iax_net_process(unsigned char *buf, int len, struct sockaddr_in *sin);
+extern unsigned int iax_session_get_capability(struct iax_session *s);
+extern char iax_pref_codec_add(struct iax_session *session, unsigned int format);
+extern void iax_pref_codec_del(struct iax_session *session, unsigned int format);
+extern int iax_pref_codec_get(struct iax_session *session, unsigned int *array, int len);
+
+#if defined(__cplusplus)
+}
+#endif
 
 #endif /* _ASTERISK_IAX_CLIENT_H */
diff -Naur libiax2.old/src/jitterbuf.c libiax2/src/jitterbuf.c
--- libiax2.old/src/jitterbuf.c	1970-01-01 01:00:00.000000000 +0100
+++ libiax2/src/jitterbuf.c	2006-02-12 22:44:27.000000000 +0100
@@ -0,0 +1,809 @@
+/*
+ * jitterbuf: an application-independent jitterbuffer
+ *
+ * Copyrights:
+ * Copyright (C) 2004-2005, Horizon Wimba, Inc.
+ *
+ * Contributors:
+ * Steve Kann <stevek@stevek.com>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU Lesser (Library) General Public License
+ *
+ * Copyright on this file is disclaimed to Digium for inclusion in Asterisk
+ */
+
+#include "jitterbuf.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* define these here, just for ancient compiler systems */
+#define JB_LONGMAX 2147483647L
+#define JB_LONGMIN (-JB_LONGMAX - 1L)
+
+/* MS VC can't do __VA_ARGS__ */
+#if (defined(WIN32)  ||  defined(_WIN32_WCE))  &&  defined(_MSC_VER)
+#define jb_warn if (warnf) warnf
+#define jb_err if (errf) errf
+#define jb_dbg if (dbgf) dbgf
+
+#ifdef DEEP_DEBUG
+  #define jb_dbg2 if (dbgf) dbgf
+#else
+  #define jb_dbg2 if (0) dbgf
+#endif
+
+#else
+
+#define jb_warn(...) (warnf ? warnf(__VA_ARGS__) : (void)0)
+#define jb_err(...) (errf ? errf(__VA_ARGS__) : (void)0)
+#define jb_dbg(...) (dbgf ? dbgf(__VA_ARGS__) : (void)0)
+
+#ifdef DEEP_DEBUG
+#define jb_dbg2(...) (dbgf ? dbgf(__VA_ARGS__) : (void)0)
+#else
+#define jb_dbg2(...) ((void)0)
+#endif
+
+#endif
+
+static jb_output_function_t warnf, errf, dbgf;
+
+void jb_setoutput(jb_output_function_t err, jb_output_function_t warn, jb_output_function_t dbg) 
+{
+	errf = err;
+	warnf = warn;
+	dbgf = dbg;
+}
+
+static void increment_losspct(jitterbuf *jb) 
+{
+    jb->info.losspct = (100000 + 499 * jb->info.losspct)/500;    
+}
+
+static void decrement_losspct(jitterbuf *jb) 
+{
+    jb->info.losspct = (499 * jb->info.losspct)/500;    
+}
+
+void jb_reset(jitterbuf *jb) 
+{
+	/* only save settings */
+	jb_conf s = jb->info.conf;
+	memset(jb,0,sizeof(jitterbuf));
+	jb->info.conf = s;
+
+	/* initialize length */
+	jb->info.current = jb->info.target = JB_TARGET_EXTRA; 
+	jb->info.silence_begin_ts = -1; 
+}
+
+jitterbuf * jb_new() 
+{
+    jitterbuf *jb;
+
+
+    jb = malloc(sizeof(jitterbuf));
+    if(!jb) return NULL;
+
+    jb_reset(jb);
+
+    jb_dbg2("jb_new() = %x\n", jb);
+    return jb;
+}
+
+void jb_destroy(jitterbuf *jb) 
+{
+    jb_frame *frame; 
+    jb_dbg2("jb_destroy(%x)\n", jb);
+
+    /* free all the frames on the "free list" */
+    frame = jb->free;
+    while(frame != NULL) {
+      jb_frame *next = frame->next;
+      free(frame);
+      frame = next;
+    }
+
+    /* free ourselves! */ 
+    free(jb);
+}
+
+
+
+/* simple history manipulation */
+/* maybe later we can make the history buckets variable size, or something? */
+/* drop parameter determines whether we will drop outliers to minimize
+ * delay */
+#if 0
+static int longcmp(const void *a, const void *b) 
+{
+    return *(long *)a - *(long *)b;
+}
+#endif
+
+static int history_put(jitterbuf *jb, long ts, long now, long ms) 
+{
+	long delay = now - (ts - jb->info.resync_offset);
+	long threshold = 2 * jb->info.jitter + jb->info.conf.resync_threshold;
+	long kicked;
+
+	/* don't add special/negative times to history */
+	if (ts <= 0) 
+		return 0;
+
+	/* check for drastic change in delay */
+	if (jb->info.conf.resync_threshold != -1) {
+		if (abs(delay - jb->info.last_delay) > threshold) {
+			jb->info.cnt_delay_discont++;
+			if (jb->info.cnt_delay_discont > 3) {
+				/* resync the jitterbuffer */
+				jb->info.cnt_delay_discont = 0;
+				jb->hist_ptr = 0;
+				jb->hist_maxbuf_valid = 0;
+
+				jb_warn("Resyncing the jb. last_delay %ld, this delay %ld, threshold %ld, new offset %ld\n", jb->info.last_delay, delay, threshold, ts - now);
+				jb->info.resync_offset = ts - now;
+				jb->info.last_delay = delay = 0; /* after resync, frame is right on time */
+			} else {
+				return -1;
+			}
+		} else {
+			jb->info.last_delay = delay;
+			jb->info.cnt_delay_discont = 0;
+		}
+	}
+
+    kicked = jb->history[jb->hist_ptr & JB_HISTORY_SZ];
+
+    jb->history[(jb->hist_ptr++) % JB_HISTORY_SZ] = delay;
+
+    /* optimization; the max/min buffers don't need to be recalculated, if this packet's
+     * entry doesn't change them.  This happens if this packet is not involved, _and_ any packet
+     * that got kicked out of the history is also not involved 
+     * We do a number of comparisons, but it's probably still worthwhile, because it will usually
+     * succeed, and should be a lot faster than going through all 500 packets in history */
+    if(!jb->hist_maxbuf_valid)
+      return 0;
+
+    /* don't do this until we've filled history 
+     * (reduces some edge cases below) */
+    if(jb->hist_ptr < JB_HISTORY_SZ)
+      goto invalidate;
+
+    /* if the new delay would go into min */
+    if(delay < jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1])
+      goto invalidate;
+    
+    /* or max.. */
+    if(delay > jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1])
+      goto invalidate;
+
+    /* or the kicked delay would be in min */
+    if(kicked <= jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1]) 
+      goto invalidate;
+
+    if(kicked >= jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1]) 
+      goto invalidate;
+
+    /* if we got here, we don't need to invalidate, 'cause this delay didn't 
+     * affect things */
+    return 0;
+    /* end optimization */
+
+
+invalidate:
+    jb->hist_maxbuf_valid = 0;
+    return 0;
+}
+
+static void history_calc_maxbuf(jitterbuf *jb) 
+{
+    int i,j;
+
+    if(jb->hist_ptr == 0) return;
+
+
+    /* initialize maxbuf/minbuf to the latest value */
+    for(i=0;i<JB_HISTORY_MAXBUF_SZ;i++) {
+/*
+ * jb->hist_maxbuf[i] = jb->history[(jb->hist_ptr-1) % JB_HISTORY_SZ];
+ * jb->hist_minbuf[i] = jb->history[(jb->hist_ptr-1) % JB_HISTORY_SZ];
+ */
+      jb->hist_maxbuf[i] = JB_LONGMIN;
+      jb->hist_minbuf[i] = JB_LONGMAX;
+    }
+
+    /* use insertion sort to populate maxbuf */
+    /* we want it to be the top "n" values, in order */
+
+    /* start at the beginning, or JB_HISTORY_SZ frames ago */
+    i = (jb->hist_ptr > JB_HISTORY_SZ) ? (jb->hist_ptr - JB_HISTORY_SZ) : 0; 
+
+    for(;i<jb->hist_ptr;i++) {
+	long toins = jb->history[i % JB_HISTORY_SZ];
+
+	/* if the maxbuf should get this */
+	if(toins > jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1])  {
+
+	    /* insertion-sort it into the maxbuf */
+	    for(j=0;j<JB_HISTORY_MAXBUF_SZ;j++) {
+		/* found where it fits */
+		if(toins > jb->hist_maxbuf[j]) {
+		    /* move over */
+		    memmove(jb->hist_maxbuf+j+1,jb->hist_maxbuf+j, (JB_HISTORY_MAXBUF_SZ-(j+1)) * sizeof(long));
+		    /* insert */
+		    jb->hist_maxbuf[j] = toins;
+
+		    break;
+		}
+	    }
+	}
+
+	/* if the minbuf should get this */
+	if(toins < jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1])  {
+
+	    /* insertion-sort it into the maxbuf */
+	    for(j=0;j<JB_HISTORY_MAXBUF_SZ;j++) {
+		/* found where it fits */
+		if(toins < jb->hist_minbuf[j]) {
+		    /* move over */
+		    memmove(jb->hist_minbuf+j+1,jb->hist_minbuf+j, (JB_HISTORY_MAXBUF_SZ-(j+1)) * sizeof(long));
+		    /* insert */
+		    jb->hist_minbuf[j] = toins;
+
+		    break;
+		}
+	    }
+	}
+
+	if(0) { 
+	  int k;
+	  fprintf(stderr, "toins = %ld\n", toins);
+	  fprintf(stderr, "maxbuf =");
+	  for(k=0;k<JB_HISTORY_MAXBUF_SZ;k++) 
+	      fprintf(stderr, "%ld ", jb->hist_maxbuf[k]);
+	  fprintf(stderr, "\nminbuf =");
+	  for(k=0;k<JB_HISTORY_MAXBUF_SZ;k++) 
+	      fprintf(stderr, "%ld ", jb->hist_minbuf[k]);
+	  fprintf(stderr, "\n");
+	}
+    }
+
+    jb->hist_maxbuf_valid = 1;
+}
+
+static void history_get(jitterbuf *jb) 
+{
+    long max, min, jitter;
+    int index;
+    int count;
+
+    if(!jb->hist_maxbuf_valid) 
+      history_calc_maxbuf(jb);
+
+    /* count is how many items in history we're examining */
+    count = (jb->hist_ptr < JB_HISTORY_SZ) ? jb->hist_ptr : JB_HISTORY_SZ;
+
+    /* index is the "n"ths highest/lowest that we'll look for */
+    index = count * JB_HISTORY_DROPPCT / 100;
+
+    /* sanity checks for index */
+    if(index > (JB_HISTORY_MAXBUF_SZ - 1)) index = JB_HISTORY_MAXBUF_SZ - 1;
+
+
+    if(index < 0) {
+      jb->info.min = 0;
+      jb->info.jitter = 0;
+      return;
+    }
+
+    max = jb->hist_maxbuf[index];
+    min = jb->hist_minbuf[index];
+
+    jitter = max - min;
+
+    /* these debug stmts compare the difference between looking at the absolute jitter, and the
+     * values we get by throwing away the outliers */
+    /*
+    fprintf(stderr, "[%d] min=%d, max=%d, jitter=%d\n", index, min, max, jitter);
+    fprintf(stderr, "[%d] min=%d, max=%d, jitter=%d\n", 0, jb->hist_minbuf[0], jb->hist_maxbuf[0], jb->hist_maxbuf[0]-jb->hist_minbuf[0]);
+    */
+
+    jb->info.min = min;
+    jb->info.jitter = jitter;
+}
+
+/* returns 1 if frame was inserted into head of queue, 0 otherwise */
+static int queue_put(jitterbuf *jb, void *data, int type, long ms, long ts) 
+{
+    jb_frame *frame;
+    jb_frame *p;
+	int head = 0;
+	long resync_ts = ts - jb->info.resync_offset;
+
+    frame = jb->free;
+    if(frame) {
+	jb->free = frame->next;
+    } else {
+	frame = malloc(sizeof(jb_frame));
+    }
+
+    if(!frame) {
+	jb_err("cannot allocate frame\n");
+	return 0;
+    }
+
+    jb->info.frames_cur++;
+
+    frame->data = data;
+	frame->ts = resync_ts;
+    frame->ms = ms;
+    frame->type = type;
+
+    /* 
+     * frames are a circular list, jb-frames points to to the lowest ts, 
+     * jb->frames->prev points to the highest ts
+     */
+
+    if(!jb->frames) {  /* queue is empty */
+	jb->frames = frame;
+	frame->next = frame;
+	frame->prev = frame;
+		head = 1;
+	} else if (resync_ts < jb->frames->ts) {
+	frame->next = jb->frames;
+	frame->prev = jb->frames->prev;
+
+	frame->next->prev = frame;
+	frame->prev->next = frame;
+
+	/* frame is out of order */
+	jb->info.frames_ooo++;
+
+	jb->frames = frame;
+		head = 1;
+    } else { 
+	p = jb->frames;
+
+	/* frame is out of order */
+	if(ts < p->prev->ts) jb->info.frames_ooo++;
+
+		while (resync_ts < p->prev->ts && p->prev != jb->frames) 
+	    p = p->prev;
+
+	frame->next = p;
+	frame->prev = p->prev;
+
+	frame->next->prev = frame;
+	frame->prev->next = frame;
+    }
+	return head;
+}
+
+static long queue_next(jitterbuf *jb) 
+{
+    if(jb->frames) return jb->frames->ts;
+    else return -1;
+}
+
+static long queue_last(jitterbuf *jb) 
+{
+    if(jb->frames) return jb->frames->prev->ts;
+    else return -1;
+}
+
+static jb_frame *_queue_get(jitterbuf *jb, long ts, int all) 
+{
+    jb_frame *frame;
+    frame = jb->frames;
+
+    if(!frame)
+	return NULL;
+
+    /*jb_warn("queue_get: ASK %ld FIRST %ld\n", ts, frame->ts); */
+
+    if(all || ts >= frame->ts) {
+	/* remove this frame */
+	frame->prev->next = frame->next;
+	frame->next->prev = frame->prev;
+
+	if(frame->next == frame)
+	  jb->frames = NULL;
+	else
+	  jb->frames = frame->next;
+
+
+	/* insert onto "free" single-linked list */
+	frame->next = jb->free;
+	jb->free = frame;
+
+	jb->info.frames_cur--;
+
+	/* we return the frame pointer, even though it's on free list, 
+	 * but caller must copy data */
+	return frame;
+    } 
+
+    return NULL;
+}
+
+static jb_frame *queue_get(jitterbuf *jb, long ts) 
+{
+    return _queue_get(jb,ts,0);
+}
+
+static jb_frame *queue_getall(jitterbuf *jb) 
+{
+    return _queue_get(jb,0,1);
+}
+
+#if 0
+/* some diagnostics */
+static void jb_dbginfo(jitterbuf *jb) 
+{
+    if(dbgf == NULL) return;
+
+    jb_dbg("\njb info: fin=%ld fout=%ld flate=%ld flost=%ld fdrop=%ld fcur=%ld\n",
+	    jb->info.frames_in, jb->info.frames_out, jb->info.frames_late, jb->info.frames_lost, jb->info.frames_dropped, jb->info.frames_cur);
+	
+    jb_dbg("	jitter=%ld current=%ld target=%ld min=%ld sil=%d len=%d len/fcur=%ld\n",
+	    jb->info.jitter, jb->info.current, jb->info.target, jb->info.min, jb->info.silence_begin_ts, jb->info.current - jb->info.min, 
+	    jb->info.frames_cur ? (jb->info.current - jb->info.min)/jb->info.frames_cur : -8);
+    if(jb->info.frames_in > 0) 
+	jb_dbg("jb info: Loss PCT = %ld%%, Late PCT = %ld%%\n",
+	    jb->info.frames_lost * 100/(jb->info.frames_in + jb->info.frames_lost), 
+	    jb->info.frames_late * 100/jb->info.frames_in);
+	jb_dbg("jb info: queue %d -> %d.  last_ts %d (queue len: %d) last_ms %d\n",
+	    queue_next(jb), 
+	    queue_last(jb),
+	    jb->info.next_voice_ts, 
+	    queue_last(jb) - queue_next(jb),
+	    jb->info.last_voice_ms);
+}
+#endif
+
+#ifdef DEEP_DEBUG
+static void jb_chkqueue(jitterbuf *jb) 
+{
+    int i=0;
+    jb_frame *p = jb->frames;
+
+    if(!p) {
+      return;
+    }
+
+    do {
+	if(p->next == NULL)  {
+	  jb_err("Queue is BROKEN at item [%d]", i);	
+	}
+	i++;
+	p=p->next;
+    } while (p->next != jb->frames);
+}
+
+static void jb_dbgqueue(jitterbuf *jb) 
+{
+    int i=0;
+    jb_frame *p = jb->frames;
+
+    jb_dbg("queue: ");
+
+    if(!p) {
+      jb_dbg("EMPTY\n");
+      return;
+    }
+
+    do {
+	jb_dbg("[%d]=%ld ", i++, p->ts);
+	p=p->next;
+    } while (p->next != jb->frames);
+
+    jb_dbg("\n");
+}
+#endif
+
+int jb_put(jitterbuf *jb, void *data, int type, long ms, long ts, long now) 
+{
+    jb_dbg2("jb_put(%x,%x,%ld,%ld,%ld)\n", jb, data, ms, ts, now);
+
+    jb->info.frames_in++;
+
+    if(type == JB_TYPE_VOICE) {
+      /* presently, I'm only adding VOICE frames to history and drift calculations; mostly because with the
+       * IAX integrations, I'm sending retransmitted control frames with their awkward timestamps through */
+		if (history_put(jb,ts,now,ms))
+			return JB_DROP;
+    }
+
+	/* if put into head of queue, caller needs to reschedule */
+	if (queue_put(jb,data,type,ms,ts)) {
+		return JB_SCHED;
+	}
+
+    return JB_OK;
+}
+
+
+static int _jb_get(jitterbuf *jb, jb_frame *frameout, long now, long interpl) 
+{
+    jb_frame *frame;
+    long diff;
+
+    /*if((now - jb_next(jb)) > 2 * jb->info.last_voice_ms) jb_warn("SCHED: %ld", (now - jb_next(jb))); */
+    /* get jitter info */
+    history_get(jb);
+
+
+    /* target */
+    jb->info.target = jb->info.jitter + jb->info.min + JB_TARGET_EXTRA; 
+
+    /* if a hard clamp was requested, use it */
+    if((jb->info.conf.max_jitterbuf) && ((jb->info.target - jb->info.min) > jb->info.conf.max_jitterbuf)) {
+	jb_dbg("clamping target from %d to %d\n", (jb->info.target - jb->info.min), jb->info.conf.max_jitterbuf);
+	jb->info.target = jb->info.min + jb->info.conf.max_jitterbuf;
+    }
+
+    diff = jb->info.target - jb->info.current;
+
+    /*    jb_warn("diff = %d lms=%d last = %d now = %d\n", diff,  */
+    /*	jb->info.last_voice_ms, jb->info.last_adjustment, now); */
+
+    /* let's work on non-silent case first */
+    if(!jb->info.silence_begin_ts) { 
+      /* we want to grow */
+      if( (diff > 0) && 
+	  /* we haven't grown in the delay length */
+	  (((jb->info.last_adjustment + JB_ADJUST_DELAY) < now) || 
+	   /* we need to grow more than the "length" we have left */
+	   (diff > queue_last(jb)  - queue_next(jb)) ) ) {
+              /* grow by interp frame len */
+	      jb->info.current += interpl;
+              jb->info.next_voice_ts += interpl;
+              jb->info.last_voice_ms = interpl;
+	      jb->info.last_adjustment = now;
+              jb->info.cnt_contig_interp++;
+	      jb_dbg("G");
+              /* assume silence instead of continuing to interpolate */
+              if (jb->info.conf.max_contig_interp && jb->info.cnt_contig_interp >= jb->info.conf.max_contig_interp)
+                  jb->info.silence_begin_ts = jb->info.next_voice_ts - jb->info.current;
+	      return JB_INTERP;
+      }
+
+      frame = queue_get(jb, jb->info.next_voice_ts - jb->info.current);
+
+      /* not a voice frame; just return it. */
+      if(frame && frame->type != JB_TYPE_VOICE) {
+        /* track start of silence */
+	if(frame->type == JB_TYPE_SILENCE) {
+	  jb->info.silence_begin_ts = frame->ts;
+          jb->info.cnt_contig_interp = 0;
+        }
+
+	*frameout = *frame;
+	jb->info.frames_out++;
+	jb_dbg("o");
+	return JB_OK;
+      }
+
+      /* voice frame is later than expected */
+      if(frame && frame->ts + jb->info.current < jb->info.next_voice_ts) {
+        if (frame->ts + jb->info.current > jb->info.next_voice_ts - jb->info.last_voice_ms) {
+            /* either we interpolated past this frame in the last jb_get */
+            /* or the frame is still in order, but came a little too quick */ 
+            *frameout = *frame;
+            /* reset expectation for next frame */
+            jb->info.next_voice_ts = frame->ts + jb->info.current + frame->ms;
+            jb->info.frames_out++;
+            decrement_losspct(jb);
+            jb->info.cnt_contig_interp = 0;
+            jb_dbg("v");
+            return JB_OK;
+        } else {
+      	    /* voice frame is late */
+            *frameout = *frame;
+            jb->info.frames_out++;
+            decrement_losspct(jb);
+            jb->info.frames_late++;
+            jb->info.frames_lost--;
+            jb_dbg("l");
+            /*jb_warn("\nlate: wanted=%ld, this=%ld, next=%ld\n", jb->info.next_voice_ts - jb->info.current, frame->ts, queue_next(jb));
+            jb_warninfo(jb); */
+            return JB_DROP;
+        }
+      }
+
+      /* keep track of frame sizes, to allow for variable sized-frames */
+      if(frame && frame->ms > 0) {
+	jb->info.last_voice_ms = frame->ms;
+      }
+
+      /* we want to shrink; shrink at 1 frame / 500ms */
+      /* unless we don't have a frame, then shrink 1 frame */
+      /* every 80ms (though perhaps we can shrink even faster */
+      /* in this case) */
+      if(diff < -JB_TARGET_EXTRA && 
+		((!frame && jb->info.last_adjustment + 80 < now) || 
+		 (jb->info.last_adjustment + 500 < now))) {
+	jb->info.last_adjustment = now;
+        jb->info.cnt_contig_interp = 0;
+
+	if(frame)  {
+	  *frameout = *frame;
+          /* shrink by frame size we're throwing out */
+          jb->info.current -= frame->ms;
+	  jb->info.frames_out++;
+	  decrement_losspct(jb);
+	  jb->info.frames_dropped++;
+	  jb_dbg("s");
+	  return JB_DROP;
+	} else {
+          /* shrink by last_voice_ms */
+          jb->info.current -= jb->info.last_voice_ms;
+	  jb->info.frames_lost++;
+	  increment_losspct(jb);
+	  jb_dbg("S");
+	  return JB_NOFRAME;
+	}
+      }
+
+      /* lost frame */
+      if(!frame) {
+	  /* this is a bit of a hack for now, but if we're close to
+	   * target, and we find a missing frame, it makes sense to
+	   * grow, because the frame might just be a bit late;
+	   * otherwise, we presently get into a pattern where we return
+	   * INTERP for the lost frame, then it shows up next, and we
+	   * throw it away because it's late */
+	  /* I've recently only been able to replicate this using
+	   * iaxclient talking to app_echo on asterisk.  In this case,
+	   * my outgoing packets go through asterisk's (old)
+	   * jitterbuffer, and then might get an unusual increasing delay 
+	   * there if it decides to grow?? */
+	  /* Update: that might have been a different bug, that has been fixed..
+	   * But, this still seemed like a good idea, except that it ended up making a single actual
+	   * lost frame get interpolated two or more times, when there was "room" to grow, so it might
+	   * be a bit of a bad idea overall */
+	  /*if(diff > -1 * jb->info.last_voice_ms) { 
+	      jb->info.current += jb->info.last_voice_ms;
+	      jb->info.last_adjustment = now;
+	      jb_warn("g");
+	      return JB_INTERP;
+	  } */
+	  jb->info.frames_lost++;
+	  increment_losspct(jb);
+          jb->info.next_voice_ts += interpl;
+          jb->info.last_voice_ms = interpl;
+          jb->info.cnt_contig_interp++;
+          /* assume silence instead of continuing to interpolate */
+          if (jb->info.conf.max_contig_interp && jb->info.cnt_contig_interp >= jb->info.conf.max_contig_interp)
+            jb->info.silence_begin_ts = jb->info.next_voice_ts - jb->info.current;
+	  jb_dbg("L");
+	  return JB_INTERP;
+      }
+
+      /* normal case; return the frame, increment stuff */
+      *frameout = *frame;
+      jb->info.next_voice_ts += frame->ms;
+      jb->info.frames_out++;
+      decrement_losspct(jb);
+      jb->info.cnt_contig_interp = 0;
+      jb_dbg("v");
+      return JB_OK;
+  } else {     
+      /* TODO: after we get the non-silent case down, we'll make the
+       * silent case -- basically, we'll just grow and shrink faster
+       * here, plus handle next_voice_ts a bit differently */
+      
+      /* to disable silent special case altogether, just uncomment this: */
+       /* jb->info.silence_begin_ts = 0; */
+
+       /* shrink interpl len every 10ms during silence */
+       if (diff < -JB_TARGET_EXTRA &&
+           jb->info.last_adjustment + 10 <= now) {
+         jb->info.current -= interpl;
+         jb->info.last_adjustment = now;
+       }
+
+       frame = queue_get(jb, now - jb->info.current);
+       if(!frame) {
+	  return JB_NOFRAME;
+       } else if (frame->type != JB_TYPE_VOICE) {
+          /* normal case; in silent mode, got a non-voice frame */
+          *frameout = *frame;
+	  jb->info.frames_out++;
+          return JB_OK;
+       }
+       if (frame->ts < jb->info.silence_begin_ts) {
+          /* voice frame is late */
+	  *frameout = *frame;
+	  jb->info.frames_out++;
+	  decrement_losspct(jb);
+	  jb->info.frames_late++;
+	  jb->info.frames_lost--;
+	  jb_dbg("l");
+	  /*jb_warn("\nlate: wanted=%ld, this=%ld, next=%ld\n", jb->info.next_voice_ts - jb->info.current, frame->ts, queue_next(jb));
+	jb_warninfo(jb); */
+	  return JB_DROP;
+       } else { 
+          /* voice frame */
+	  /* try setting current to target right away here */
+	  jb->info.current = jb->info.target;
+	  jb->info.silence_begin_ts = 0;
+	  jb->info.next_voice_ts = frame->ts + jb->info.current + frame->ms;
+	  jb->info.last_voice_ms = frame->ms;
+	  jb->info.frames_out++;
+	  decrement_losspct(jb);
+	  *frameout = *frame;
+	  jb_dbg("V");
+	  return JB_OK;
+       }
+  }
+}
+
+long jb_next(jitterbuf *jb) 
+{
+    if(jb->info.silence_begin_ts) {
+      long next = queue_next(jb);
+      if(next > 0) { 
+        /* shrink during silence */
+        if (jb->info.target - jb->info.current < -JB_TARGET_EXTRA)
+          return jb->info.last_adjustment + 10;
+        return next + jb->info.target;
+      }
+      else return JB_LONGMAX;
+    } else {
+      return jb->info.next_voice_ts;
+    }
+}
+
+int jb_get(jitterbuf *jb, jb_frame *frameout, long now, long interpl) 
+{
+    int ret = _jb_get(jb,frameout,now,interpl);
+#if 0
+    static int lastts=0;
+    int thists = ((ret == JB_OK) || (ret == JB_DROP)) ? frameout->ts : 0;
+    jb_warn("jb_get(%x,%x,%ld) = %d (%d)\n", jb, frameout, now, ret, thists);
+    if(thists && thists < lastts) jb_warn("XXXX timestamp roll-back!!!\n");
+    lastts = thists;
+#endif
+    return ret;
+}
+
+int jb_getall(jitterbuf *jb, jb_frame *frameout) 
+{
+    jb_frame *frame;
+    frame = queue_getall(jb);
+
+    if(!frame) {
+      return JB_NOFRAME;
+    }
+
+    *frameout = *frame;
+    return JB_OK;
+}
+
+
+int jb_getinfo(jitterbuf *jb, jb_info *stats) 
+{
+
+    history_get(jb);
+
+    *stats = jb->info;
+
+  return JB_OK;
+}
+
+int jb_setconf(jitterbuf *jb, jb_conf *conf) 
+{
+  /* take selected settings from the struct */
+
+	jb->info.conf.max_jitterbuf = conf->max_jitterbuf;
+ 	jb->info.conf.resync_threshold = conf->resync_threshold;
+	jb->info.conf.max_contig_interp = conf->max_contig_interp;
+
+  return JB_OK;
+}
+
+
diff -Naur libiax2.old/src/jitterbuf.h libiax2/src/jitterbuf.h
--- libiax2.old/src/jitterbuf.h	1970-01-01 01:00:00.000000000 +0100
+++ libiax2/src/jitterbuf.h	2006-02-12 22:44:27.000000000 +0100
@@ -0,0 +1,160 @@
+/*
+ * jitterbuf: an application-independent jitterbuffer
+ *
+ * Copyrights:
+ * Copyright (C) 2004-2005, Horizon Wimba, Inc.
+ *
+ * Contributors:
+ * Steve Kann <stevek@stevek.com>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU Lesser (Library) General Public License
+ *
+ * Copyright on this file is disclaimed to Digium for inclusion in Asterisk
+ */
+
+#ifndef _JITTERBUF_H_
+#define _JITTERBUF_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* configuration constants */
+	/* Number of historical timestamps to use in calculating jitter and drift */
+#define JB_HISTORY_SZ		500	
+	/* what percentage of timestamps should we drop from the history when we examine it;
+	 * this might eventually be something made configurable */
+#define JB_HISTORY_DROPPCT	3
+	/* the maximum droppct we can handle (say it was configurable). */
+#define JB_HISTORY_DROPPCT_MAX	4
+	/* the size of the buffer we use to keep the top and botton timestamps for dropping */
+#define JB_HISTORY_MAXBUF_SZ	JB_HISTORY_SZ * JB_HISTORY_DROPPCT_MAX / 100 
+	/* amount of additional jitterbuffer adjustment  */
+#define JB_TARGET_EXTRA 40
+	/* ms between growing and shrinking; may not be honored if jitterbuffer runs out of space */
+#define JB_ADJUST_DELAY 40
+
+
+/* return codes */
+#define JB_OK		0
+#define JB_EMPTY	1
+#define JB_NOFRAME	2
+#define JB_INTERP	3
+#define JB_DROP		4
+#define JB_SCHED	5
+
+/* frame types */
+#define JB_TYPE_CONTROL	0
+#define JB_TYPE_VOICE	1
+#define JB_TYPE_VIDEO	2  /* reserved */
+#define JB_TYPE_SILENCE	3
+
+
+typedef struct jb_conf {
+	/* settings */
+	long max_jitterbuf;	/* defines a hard clamp to use in setting the jitter buffer delay */
+ 	long resync_threshold;  /* the jb will resync when delay increases to (2 * jitter) + this param */
+	long max_contig_interp; /* the max interp frames to return in a row */
+} jb_conf;
+
+typedef struct jb_info {
+	jb_conf conf;
+
+	/* statistics */
+	long frames_in;  	/* number of frames input to the jitterbuffer.*/
+	long frames_out;  	/* number of frames output from the jitterbuffer.*/
+	long frames_late; 	/* number of frames which were too late, and dropped.*/
+	long frames_lost; 	/* number of missing frames.*/
+	long frames_dropped; 	/* number of frames dropped (shrinkage) */
+	long frames_ooo; 	/* number of frames received out-of-order */
+	long frames_cur; 	/* number of frames presently in jb, awaiting delivery.*/
+	long jitter; 		/* jitter measured within current history interval*/
+	long min;		/* minimum lateness within current history interval */
+	long current; 		/* the present jitterbuffer adjustment */
+	long target; 		/* the target jitterbuffer adjustment */
+	long losspct; 		/* recent lost frame percentage (* 1000) */
+	long next_voice_ts;	/* the ts of the next frame to be read from the jb - in receiver's time */
+	long last_voice_ms;	/* the duration of the last voice frame */
+	long silence_begin_ts;	/* the time of the last CNG frame, when in silence */
+	long last_adjustment;   /* the time of the last adjustment */
+	long last_delay;        /* the last now added to history */
+	long cnt_delay_discont;	/* the count of discontinuous delays */
+	long resync_offset;     /* the amount to offset ts to support resyncs */
+	long cnt_contig_interp; /* the number of contiguous interp frames returned */
+} jb_info;
+
+typedef struct jb_frame {
+	void *data;		/* the frame data */
+	long ts;	/* the relative delivery time expected */
+	long ms;	/* the time covered by this frame, in sec/8000 */
+	int  type;	/* the type of frame */
+	struct jb_frame *next, *prev;
+} jb_frame;
+
+typedef struct jitterbuf {
+	jb_info info;
+
+	/* history */
+	long history[JB_HISTORY_SZ];   		/* history */
+	int  hist_ptr;				/* points to index in history for next entry */
+	long hist_maxbuf[JB_HISTORY_MAXBUF_SZ];	/* a sorted buffer of the max delays (highest first) */
+	long hist_minbuf[JB_HISTORY_MAXBUF_SZ];	/* a sorted buffer of the min delays (lowest first) */
+	int  hist_maxbuf_valid;			/* are the "maxbuf"/minbuf valid? */
+
+
+	jb_frame *frames; 		/* queued frames */
+	jb_frame *free; 		/* free frames (avoid malloc?) */
+} jitterbuf;
+
+
+/* new jitterbuf */
+extern jitterbuf *		jb_new(void);
+
+/* destroy jitterbuf */
+extern void			jb_destroy(jitterbuf *jb);
+
+/* reset jitterbuf */
+/* NOTE:  The jitterbuffer should be empty before you call this, otherwise
+ * you will leak queued frames, and some internal structures */
+extern void			jb_reset(jitterbuf *jb);
+
+/* queue a frame data=frame data, timings (in ms): ms=length of frame (for voice), ts=ts (sender's time) 
+ * now=now (in receiver's time) return value is one of 
+ * JB_OK: Frame added. Last call to jb_next() still valid
+ * JB_DROP: Drop this frame immediately
+ * JB_SCHED: Frame added. Call jb_next() to get a new time for the next frame
+ */
+extern int 			jb_put(jitterbuf *jb, void *data, int type, long ms, long ts, long now);
+
+/* get a frame for time now (receiver's time)  return value is one of
+ * JB_OK:  You've got frame!
+ * JB_DROP: Here's an audio frame you should just drop.  Ask me again for this time..
+ * JB_NOFRAME: There's no frame scheduled for this time.
+ * JB_INTERP: Please interpolate an interpl-length frame for this time (either we need to grow, or there was a lost frame) 
+ * JB_EMPTY: The jb is empty.
+ */
+extern int			jb_get(jitterbuf *jb, jb_frame *frame, long now, long interpl);
+
+/* unconditionally get frames from jitterbuf until empty */
+extern int jb_getall(jitterbuf *jb, jb_frame *frameout);
+
+/* when is the next frame due out, in receiver's time (0=EMPTY) 
+ * This value may change as frames are added (esp non-audio frames) */
+extern long			jb_next(jitterbuf *jb);
+
+/* get jitterbuf info: only "statistics" may be valid */
+extern int			jb_getinfo(jitterbuf *jb, jb_info *stats);
+
+/* set jitterbuf conf */
+extern int			jb_setconf(jitterbuf *jb, jb_conf *conf);
+
+typedef 		void (*jb_output_function_t)(const char *fmt, ...);
+extern void 			jb_setoutput(jb_output_function_t err, jb_output_function_t warn, jb_output_function_t dbg);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
diff -Naur libiax2.old/src/Makefile.am libiax2/src/Makefile.am
--- libiax2.old/src/Makefile.am	2006-02-12 22:12:27.000000000 +0100
+++ libiax2/src/Makefile.am	2006-02-12 22:44:27.000000000 +0100
@@ -1,15 +1,15 @@
-CFLAGS_AM = -Wall -O2
-CFLAGS_AM += -g -Wall -Wstrict-prototypes -I .
-CFLAGS_AM += -DDEBUG_SUPPORT -DLIBIAX
-CFLAGS_AM += -fsigned-char
+AM_CFLAGS = -Wall -O2
+AM_CFLAGS += -g -Wall -Wstrict-prototypes -I .
+AM_CFLAGS += -DDEBUG_SUPPORT -DLIBIAX
+AM_CFLAGS += -fsigned-char
 # -DDEBUG_DEFAULT 
-CFLAGS_AM += $(UCFLAGS)
+AM_CFLAGS += $(UCFLAGS)
 
 
 pkgdir = $(libdir)
 pkg_LTLIBRARIES=libiax.la
-libiax_la_SOURCES = iax2-parser.c iax.c md5.c 
-EXTRA_DIST = md5.h frame.h iax-client.h iax2.h iax2-parser.h
+libiax_la_SOURCES = iax2-parser.c iax.c md5.c jitterbuf.c
+EXTRA_DIST = md5.h frame.h iax-client.h iax2.h iax2-parser.h jitterbuf.h
 
 install-data-local:
 	mkdir -p $(includedir)/iax
diff -Naur libiax2.old/src/md5.c libiax2/src/md5.c
--- libiax2.old/src/md5.c	2006-02-12 22:12:27.000000000 +0100
+++ libiax2/src/md5.c	2006-02-12 22:44:27.000000000 +0100
@@ -8,9 +8,21 @@
 # include <features.h>
 # include <sys/types.h>
 #elif defined(SOLARIS)
-/* each solaris is different -- this won't work on 2.6 or 2.7 */
-# include <sys/isa_defs.h>
+  /* each solaris is different -- this won't work on 2.6 or 2.7 */
+# include <sys/isa_defs.h> /* Defines either _LITTLE_ENDIAN or _BIG_ENDIAN */
+#  define __BIG_ENDIAN		4321
+#  define __LITTLE_ENDIAN	1234
+#  define BIG_ENDIAN		4321
+#  define LITTLE_ENDIAN		1234
+#  ifdef _LITTLE_ENDIAN
+#    define __BYTE_ORDER	__LITTLE_ENDIAN
+#    define BYTE_ORDER		LITTLE_ENDIAN
+#  else
+#    define __BYTE_ORDER	__BIG_ENDIAN
+#    define BYTE_ORDER		BIG_ENDIAN
+#  endif
 #endif
+
 #if __BYTE_ORDER == __BIG_ENDIAN || BYTE_ORDER == BIG_ENDIAN
 # define HIGHFIRST 1
 #elif __BYTE_ORDER == __LITTLE_ENDIAN || BYTE_ORDER == LITLE_ENDIAN
diff -Naur libiax2.old/src/winpoop.h libiax2/src/winpoop.h
--- libiax2.old/src/winpoop.h	2006-02-12 22:12:27.000000000 +0100
+++ libiax2/src/winpoop.h	2006-02-12 22:44:27.000000000 +0100
@@ -20,11 +20,13 @@
 
 #include <winsock.h>
 
-static inline int inet_aton(char *cp, struct in_addr *inp)
+void gettimeofday(struct timeval *tv, void /*struct timezone*/ *tz);
+
+static INLINE int inet_aton(char *cp, struct in_addr *inp)
 {
-	int res;
 	int a1, a2, a3, a4;
 	unsigned int saddr;
+
 	if (sscanf(cp, "%d.%d.%d.%d", &a1, &a2, &a3, &a4) != 4)
 		return 0;
 	a1 &= 0xff;