[Freeswitch-svn] [commit] r8321 - in freeswitch/trunk: . libs/iax src/mod/endpoints/mod_iax

Freeswitch SVN anthm at freeswitch.org
Thu May 8 19:25:36 EDT 2008


Author: anthm
Date: Thu May  8 19:25:36 2008
New Revision: 8321

Added:
   freeswitch/trunk/src/mod/endpoints/mod_iax/answer.h
   freeswitch/trunk/src/mod/endpoints/mod_iax/frame.h
   freeswitch/trunk/src/mod/endpoints/mod_iax/iax-client.h
   freeswitch/trunk/src/mod/endpoints/mod_iax/iax-mutex.c
   freeswitch/trunk/src/mod/endpoints/mod_iax/iax-mutex.h
   freeswitch/trunk/src/mod/endpoints/mod_iax/iax.c
   freeswitch/trunk/src/mod/endpoints/mod_iax/iax.h
   freeswitch/trunk/src/mod/endpoints/mod_iax/iax2-parser.c
   freeswitch/trunk/src/mod/endpoints/mod_iax/iax2-parser.h
   freeswitch/trunk/src/mod/endpoints/mod_iax/iax2.h
   freeswitch/trunk/src/mod/endpoints/mod_iax/jitterbuf.c
   freeswitch/trunk/src/mod/endpoints/mod_iax/jitterbuf.h
   freeswitch/trunk/src/mod/endpoints/mod_iax/md5.c
   freeswitch/trunk/src/mod/endpoints/mod_iax/md5.h
   freeswitch/trunk/src/mod/endpoints/mod_iax/winiphone.c
   freeswitch/trunk/src/mod/endpoints/mod_iax/winpoop.h
Removed:
   freeswitch/trunk/libs/iax/
Modified:
   freeswitch/trunk/configure.in
   freeswitch/trunk/src/mod/endpoints/mod_iax/Makefile

Log:
slim down iax build

Modified: freeswitch/trunk/configure.in
==============================================================================
--- freeswitch/trunk/configure.in	(original)
+++ freeswitch/trunk/configure.in	Thu May  8 19:25:36 2008
@@ -593,7 +593,6 @@
 AC_CONFIG_SUBDIRS(libs/voipcodecs)
 AC_CONFIG_SUBDIRS(libs/codec/ilbc)
 AC_CONFIG_SUBDIRS(libs/curl)
-AC_CONFIG_SUBDIRS(libs/iax)
 AC_CONFIG_SUBDIRS(libs/iksemel)
 AC_CONFIG_SUBDIRS(libs/js/nsprpub)
 AC_CONFIG_SUBDIRS(libs/js)

Modified: freeswitch/trunk/src/mod/endpoints/mod_iax/Makefile
==============================================================================
--- freeswitch/trunk/src/mod/endpoints/mod_iax/Makefile	(original)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/Makefile	Thu May  8 19:25:36 2008
@@ -1,11 +1,6 @@
 BASE=../../../..
+LOCAL_CFLAGS=-I. -DNEWJB -DLIBIAX
+LOCAL_OBJS=iax2-parser.o iax.o md5.o jitterbuf.o iax-mutex.o
 
-IAX_DIR=$(BASE)/libs/iax
-IAXLA=$(IAX_DIR)/src/libiax.la
-LOCAL_CFLAGS=-I$(IAX_DIR)/src
-LOCAL_LIBADD=$(IAXLA)
 include $(BASE)/build/modmake.rules
 
-$(IAXLA): $(IAX_DIR) $(IAX_DIR)/.update
-	cd $(IAX_DIR) && $(MAKE)
-

Added: freeswitch/trunk/src/mod/endpoints/mod_iax/answer.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/answer.h	Thu May  8 19:25:36 2008
@@ -0,0 +1,237 @@
+/*
+  * Signed 16-bit audio data
+  *
+  * Source: answer.raw
+  *
+  * Copyright (C) 1999, Mark Spencer and Linux Support Services
+  *
+  * Distributed under the terms of the GNU General Public License
+  *
+  */
+
+static signed short answer[] = {
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 0x19b7, 0x0245, 0xeee5, 0xb875, 0xd9a4, 0x6018, 0x660a, 0xc3c6, 
+0x8741, 0xff55, 0x4c2e, 0x2146, 0xfed2, 0xf079, 0xcbd4, 0xe561, 0x3c41, 0x3166, 
+0xd425, 0xdc59, 0x2748, 0x087d, 0xc72b, 0xfe3a, 0x4681, 0x14c6, 0xcf45, 0xdd38, 
+0xf8dd, 0x0a39, 0x3a5a, 0x32b9, 0xbfec, 0x957f, 0x15a3, 0x70f4, 0x1d95, 0xbfc4, 
+0xd367, 0xfda0, 0x0dc0, 0x29eb, 0x1fc2, 0xd684, 0xcab1, 0x19c7, 0x29ef, 0xe679, 
+0xe9d0, 0x2b82, 0x151a, 0xca9f, 0xdb68, 0x1f4a, 0x271c, 0x0e2a, 0xfb32, 0xd1b2, 
+0xc8ff, 0x2382, 0x6380, 0x0a52, 0xa118, 0xccbf, 0x2ddc, 0x33fd, 0x0964, 0xf2a4, 
+0xdd81, 0xe092, 0x1a00, 0x325c, 0xf5e3, 0xd6a1, 0x0b6c, 0x1c75, 0xe4f8, 0xe07c, 
+0x2082, 0x2b3e, 0xf445, 0xdaa9, 0xea13, 0xff3c, 0x245c, 0x35c1, 0xf308, 0xab53, 
+0xdf59, 0x4698, 0x3f3b, 0xe7f7, 0xca84, 0xed4d, 0x0c3f, 0x1e94, 0x1c2d, 0xf06f, 
+0xd4df, 0xff34, 0x23d8, 0x001e, 0xe3f1, 0x0b15, 0x2113, 0xf3fd, 0xd768, 0xf9a0, 
+0x1d31, 0x1c6e, 0x0797, 0xe3a0, 0xce6c, 0xfd7b, 0x422a, 0x2c4c, 0xd364, 0xbf42, 
+0x0278, 0x303e, 0x1c51, 0xf737, 0xe25a, 0xe75f, 0x0a8f, 0x22ab, 0x05f4, 0xe3f9, 
+0xf8c4, 0x1705, 0x0162, 0xe49f, 0xfb8b, 0x1e2b, 0x13ac, 0xf044, 0xe07b, 0xf01a, 
+0x1567, 0x2cbf, 0x0b75, 0xd01b, 0xd206, 0x1563, 0x38d7, 0x0f2e, 0xdb32, 0xdc30, 
+0x023b, 0x1e44, 0x16eb, 0xf5f7, 0xe425, 0xfa33, 0x14d5, 0x0968, 0xeff2, 0xf762, 
+0x1137, 0x0e59, 0xf13a, 0xe651, 0xff41, 0x1d60, 0x18fd, 0xf1e6, 0xd75f, 0xf097, 
+0x20ec, 0x27fa, 0xfba4, 0xd5b8, 0xe68e, 0x1657, 0x2518, 0x04f6, 0xe5a3, 0xe976, 
+0x0578, 0x18fa, 0x0a92, 0xec0a, 0xef2a, 0x111f, 0x12f4, 0xeec3, 0xe95e, 0x0d3a, 
+0x18fd, 0xff72, 0xeefc, 0xf114, 0xfaaa, 0x14ee, 0x21db, 0xf56e, 0xcb49, 0xf621, 
+0x3323, 0x1947, 0xe017, 0xe7e9, 0x0819, 0x0707, 0x084c, 0x0f57, 0xf152, 0xdf92, 
+0x104a, 0x28eb, 0xedcc, 0xd4ad, 0x1415, 0x296d, 0xed9a, 0xdf57, 0x0cc2, 0x0d95, 
+0xf7b5, 0x0deb, 0x0b34, 0xd713, 0xea08, 0x38d6, 0x216d, 0xc727, 0xdc32, 0x2cd2, 
+0x1822, 0xe2d5, 0xfeb3, 0x106c, 0xe6e5, 0xf81e, 0x2fe8, 0x01af, 0xc180, 0x037a, 
+0x42d8, 0xf88d, 0xc344, 0x0a4f, 0x2c4e, 0xf19d, 0xebeb, 0x162c, 0xf9e9, 0xde93, 
+0x1b56, 0x2c60, 0xd8aa, 0xce3e, 0x2a41, 0x2eeb, 0xdab1, 0xde32, 0x1c32, 0x0aba, 
+0xeabe, 0x1008, 0x136d, 0xda2f, 0xec3b, 0x31dd, 0x1130, 0xca79, 0xf5b8, 0x3423, 
+0x0274, 0xd27d, 0x035e, 0x1e68, 0xf641, 0xf904, 0x1691, 0xef7d, 0xd57a, 0x1c3b, 
+0x3c23, 0xe881, 0xc274, 0x0af5, 0x2962, 0xfa34, 0xf676, 0x0f71, 0xefcc, 0xe01f, 
+0x19e7, 0x276f, 0xe694, 0xe134, 0x1c3a, 0x0e8b, 0xd8e7, 0xfa81, 0x2f8b, 0x07c5, 
+0xd904, 0xf6fa, 0x0ca5, 0xf9a2, 0x0dc7, 0x2623, 0xec54, 0xbe23, 0x02b6, 0x4296, 
+0x10cd, 0xda61, 0xf11c, 0x0103, 0xf41c, 0x10b4, 0x2a03, 0xf63c, 0xce1a, 0xfdbd, 
+0x1fb4, 0xfc51, 0xf727, 0x1c8a, 0x04ff, 0xcf41, 0xec05, 0x2913, 0x1ce8, 0xf70c, 
+0xf744, 0xede8, 0xdd77, 0x0d99, 0x43f1, 0x119c, 0xc14f, 0xd60e, 0x17cb, 0x1e19, 
+0x0d4e, 0x0c95, 0xeed1, 0xcdf4, 0xf7a5, 0x331f, 0x1cd0, 0xeb17, 0xf082, 0xfb19, 
+0xe899, 0xfdeb, 0x323c, 0x2036, 0xdad3, 0xd134, 0xfd03, 0x1345, 0x1c10, 0x2239, 
+0xf656, 0xbc22, 0xdc3f, 0x3392, 0x3d59, 0xfd77, 0xdb4d, 0xe23f, 0xedbe, 0x0f7e, 
+0x35cc, 0x1947, 0xd5dc, 0xd1bf, 0x035d, 0x16fc, 0x1174, 0x1675, 0x0249, 0xd2d4, 
+0xd851, 0x184d, 0x32fe, 0x0f91, 0xee14, 0xe1e6, 0xdf9b, 0x016b, 0x3668, 0x2b2b, 
+0xe20c, 0xc554, 0xf257, 0x1c05, 0x1fc5, 0x14f0, 0xf891, 0xd41c, 0xdf83, 0x1865, 
+0x2de1, 0x0b16, 0xed58, 0xea0c, 0xea79, 0xfbd9, 0x22af, 0x2732, 0xf62f, 0xd389, 
+0xe7d9, 0x0b39, 0x1cdc, 0x1de3, 0x038a, 0xd809, 0xd5f7, 0x0b55, 0x305e, 0x1910, 
+0xf02e, 0xe089, 0xe7c7, 0x0195, 0x2265, 0x21da, 0xf743, 0xd8f2, 0xe978, 0x09a1, 
+0x190a, 0x17c5, 0x045a, 0xe46d, 0xdd06, 0xffb2, 0x2293, 0x1cfe, 0xfd4d, 0xe4f9, 
+0xe310, 0xfaf1, 0x1d22, 0x2376, 0x0113, 0xde3a, 0xe21b, 0x0204, 0x1ba1, 0x1bd6, 
+0x0333, 0xe563, 0xe104, 0xfd51, 0x1bc1, 0x1ccf, 0x0285, 0xe757, 0xe35e, 0xfaf2, 
+0x185d, 0x1d46, 0x06b7, 0xec13, 0xe108, 0xef6e, 0x121d, 0x2a17, 0x16a6, 0xe32c, 
+0xc9a9, 0xf070, 0x2f48, 0x3788, 0xfa4e, 0xc32a, 0xd9c2, 0x1fa1, 0x36fe, 0x07fa, 
+0xd9e4, 0xe577, 0x0e5e, 0x1755, 0xfb53, 0xed71, 0x0540, 0x19e0, 0x0301, 0xdc97, 
+0xe391, 0x1937, 0x367c, 0x0bc9, 0xca4c, 0xc96b, 0x105d, 0x461f, 0x2416, 0xd481, 
+0xbc97, 0xf8b7, 0x39af, 0x2ec9, 0xecc6, 0xcb50, 0xeee3, 0x1ffe, 0x1e8e, 0xf700, 
+0xe66a, 0xff58, 0x149f, 0x02e5, 0xe792, 0xf2d8, 0x1a4d, 0x225a, 0xf642, 0xce7f, 
+0xe6a6, 0x25e2, 0x38f5, 0x01d0, 0xc50f, 0xd243, 0x19bd, 0x3fc6, 0x14f0, 0xd2d7, 
+0xcdb6, 0x069a, 0x2ffe, 0x1847, 0xe6f8, 0xdf0a, 0x0337, 0x1a90, 0x067a, 0xeb5b, 
+0xf541, 0x143b, 0x14f2, 0xf092, 0xdc02, 0xfb91, 0x28a3, 0x2274, 0xeaa8, 0xc9e7, 
+0xef48, 0x2d01, 0x322e, 0xf6d2, 0xc7cb, 0xe13b, 0x1fda, 0x3217, 0x0458, 0xd690, 
+0xe2bf, 0x11c4, 0x21d5, 0x0291, 0xe5c8, 0xf3a9, 0x12ba, 0x11aa, 0xf22b, 0xe627, 
+0x03ec, 0x219a, 0x1036, 0xe2f2, 0xd93f, 0x059c, 0x2ed6, 0x1b75, 0xe227, 0xce55, 
+0xfb19, 0x2de0, 0x2477, 0xed08, 0xd148, 0xf307, 0x21d4, 0x2002, 0xf543, 0xdeac, 
+0xf7f9, 0x18a9, 0x11d6, 0xf0ef, 0xe8e4, 0x05ea, 0x1ba5, 0x0727, 0xe448, 0xe748, 
+0x100e, 0x265e, 0x07fc, 0xdbae, 0xde78, 0x0efa, 0x2ce0, 0x0f94, 0xddf1, 0xd9ea, 
+0x0797, 0x28f6, 0x12eb, 0xe60c, 0xdf46, 0x0469, 0x1fbb, 0x0ced, 0xe9f6, 0xe95f, 
+0x09fe, 0x1ab9, 0x02cb, 0xe5a4, 0xef2a, 0x1327, 0x1d7b, 0xfd07, 0xde3d, 0xed9c, 
+0x17e5, 0x22e7, 0xfe3a, 0xdb38, 0xe9b9, 0x161a, 0x2416, 0x0175, 0xde3d, 0xe9de, 
+0x1294, 0x1fc9, 0x00ea, 0xe2a7, 0xeee2, 0x1298, 0x1a7d, 0xfc1d, 0xe3bb, 0xf47a, 
+0x1642, 0x185e, 0xf727, 0xe1af, 0xf709, 0x19c3, 0x18e7, 0xf50d, 0xe010, 0xf75b, 
+0x1a9c, 0x18d8, 0xf4c5, 0xe0c9, 0xf865, 0x1a1c, 0x16d5, 0xf3a6, 0xe257, 0xfaf2, 
+0x1a44, 0x14d5, 0xf34f, 0xe4b6, 0xfc77, 0x17d5, 0x0ff8, 0xf133, 0xe8b7, 0x0344, 
+0x1a37, 0x0ad5, 0xe95e, 0xe61a, 0x08a5, 0x227e, 0x0e33, 0xe4a7, 0xdd70, 0x03b0, 
+0x25f4, 0x17b2, 0xec0a, 0xdb4e, 0xf898, 0x1ba3, 0x18f6, 0xf973, 0xe87f, 0xf77a, 
+0x0b93, 0x096c, 0xfb0e, 0xfb03, 0x0896, 0x0940, 0xf51d, 0xe904, 0xfdc7, 0x1dda, 
+0x1bf9, 0xf29b, 0xd37f, 0xea1b, 0x1f37, 0x3175, 0x07eb, 0xd3f7, 0xd46b, 0x077d, 
+0x2eeb, 0x1e67, 0xeeae, 0xd8c7, 0xef85, 0x1119, 0x18d3, 0x088e, 0xf953, 0xf5ad, 
+0xf556, 0xf63d, 0x0234, 0x167a, 0x19a1, 0xfbf9, 0xd873, 0xdd4b, 0x0f06, 0x3748, 
+0x21e6, 0xe181, 0xc032, 0xe79a, 0x2bec, 0x3e76, 0x0b1b, 0xce41, 0xcb23, 0xff96, 
+0x2d79, 0x26d1, 0xfcc7, 0xdf8a, 0xe525, 0xfd83, 0x10f1, 0x16d7, 0x0f50, 0xfaea, 
+0xe3f1, 0xe20f, 0x0158, 0x27d9, 0x2866, 0xf96f, 0xcb34, 0xd563, 0x11d6, 0x3d25, 
+0x2424, 0xe254, 0xc2c9, 0xe7cd, 0x248d, 0x34f5, 0x0c42, 0xdcd0, 0xd827, 0xfa65, 
+0x19eb, 0x1b50, 0x0721, 0xf396, 0xeb9c, 0xefde, 0x0016, 0x1594, 0x1cc1, 0x0658, 
+0xe22b, 0xd852, 0xfb3e, 0x2923, 0x2c78, 0xfc87, 0xcdb5, 0xd69c, 0x0e3c, 0x3527, 
+0x201f, 0xe993, 0xcf9e, 0xeb21, 0x183f, 0x25ea, 0x0c93, 0xed4d, 0xe5f9, 0xf548, 
+0x07fb, 0x117c, 0x0ff2, 0x0398, 0xf08c, 0xe628, 0xf489, 0x143b, 0x2419, 0x0ccf, 
+0xe2cc, 0xd5a6, 0xf861, 0x2615, 0x2a1b, 0xfeb4, 0xd543, 0xdc53, 0x09b4, 0x2901, 
+0x19ff, 0xf24a, 0xde86, 0xeec4, 0x0b7b, 0x1733, 0x0d0a, 0xfc24, 0xf1bb, 0xf110, 
+0xfa03, 0x0a0f, 0x15d4, 0x0e21, 0xf435, 0xe17e, 0xee90, 0x1225, 0x2527, 0x0efa, 
+0xe61f, 0xd916, 0xf7b8, 0x1f50, 0x2326, 0x0099, 0xe01e, 0xe473, 0x0491, 0x1b37, 
+0x1360, 0xfb17, 0xecd9, 0xf20d, 0x0051, 0x0aec, 0x0d4a, 0x073d, 0xfa5a, 0xeeb8, 
+0xf165, 0x0516, 0x17dc, 0x12da, 0xf71b, 0xe213, 0xed85, 0x0eef, 0x20c8, 0x0e09, 
+0xebcc, 0xe0d4, 0xf848, 0x1637, 0x19d6, 0x026b, 0xec09, 0xed00, 0xff9b, 0x0e5a, 
+0x0d6b, 0x026c, 0xf865, 0xf4da, 0xf888, 0x025a, 0x0cbb, 0x0d53, 0xff96, 0xeefa, 
+0xee80, 0x021c, 0x15d6, 0x126a, 0xf9c1, 0xe724, 0xf017, 0x0aa1, 0x18b6, 0x0b4e, 
+0xf2d7, 0xea91, 0xf957, 0x0cac, 0x1061, 0x03f4, 0xf6ad, 0xf476, 0xfbdf, 0x0489, 
+0x08b1, 0x06df, 0xffcf, 0xf766, 0xf537, 0xfddf, 0x0ad4, 0x0e15, 0x01da, 0xf205, 
+0xf0a0, 0x0082, 0x1066, 0x0e41, 0xfc71, 0xef1b, 0xf4ad, 0x05cd, 0x0f32, 0x07ed, 
+0xf9c8, 0xf401, 0xfa93, 0x04af, 0x088c, 0x04a7, 0xfe15, 0xf9f1, 0xfa64, 0xff1e, 
+0x0539, 0x078c, 0x02af, 0xfa1a, 0xf69d, 0xfd09, 0x075b, 0x0a3d, 0x01f2, 0xf761, 
+0xf642, 0xffa7, 0x08f3, 0x0830, 0xff05, 0xf7db, 0xf9bc, 0x0174, 0x068b, 0x04b2, 
+0xfeff, 0xfb39, 0xfc1a, 000000, 0x0371, 0x03d7, 0x00fe, 0xfd37, 0xfbe0, 0xfe78, 
+0x02af, 0x044a, 0x0180, 0xfd43, 0xfc00, 0xfed1, 0x02aa, 0x0346, 0x00dd, 0xfde0, 
+0xfbfe, 0x0114, 0x0987, 0x04bc, 0xf49d, 0xf23a, 0x06ab, 0x162e, 0x0544, 0xe76b, 
+0xea25, 0x1015, 0x2474, 0x0431, 0xd7d3, 0xe1ec, 0x1923, 0x2df5, 0x01cd, 0xd386, 
+0xe3d9, 0x1b9d, 0x2c62, 0xfeb8, 0xd31a, 0xe6ba, 0x1dbd, 0x2abb, 0xfbab, 0xd2ed, 
+0xe9ab, 0x1fa7, 0x28ef, 0xf8b3, 0xd2f5, 0xeca5, 0x2160, 0x26fd, 0xf5d7, 0xd334, 
+0xefa1, 0x22e5, 0x24ea, 0xf31b, 0xd3a9, 0xf29f, 0x2435, 0x22b6, 0xf07e, 0xd44e, 
+0xf59b, 0x2551, 0x2067, 0xee08, 0xd527, 0xf88e, 0x2639, 0x1e00, 0xebb6, 0xd62d, 
+0xfb77, 0x26eb, 0x1b85, 0xe98b, 0xd75f, 0xfe51, 0x276b, 0x18f9, 0xe78e, 0xd8b9, 
+0x011a, 0x27b6, 0x1660, 0xe5bb, 0xda3a, 0x03cc, 0x27cf, 0x13bd, 0xe415, 0xdbdf, 
+0x066a, 0x27b7, 0x1117, 0xe29e, 0xdda5, 0x08ec, 0x276e, 0x0e6d, 0xe154, 0xdf89, 
+0x0b52, 0x26f6, 0x0bc7, 0xe039, 0xe185, 0x0d96, 0x2653, 0x0924, 0xdf4e, 0xe399, 
+0x0fb9, 0x2584, 0x068b, 0xde93, 0xe5c0, 0x11b8, 0x248e, 0x03fd, 0xde08, 0xe7f8, 
+0x1390, 0x2372, 0x0180, 0xddaa, 0xea3c, 0x1544, 0x2231, 0xff12, 0xdd7a, 0xec89, 
+0x16cf, 0x20d0, 0xfcb9, 0xdd77, 0xeedb, 0x1831, 0x1f52, 0xfa77, 0xdd9f, 0xf132, 
+0x1969, 0x1db7, 0xf850, 0xddf1, 0xf385, 0x1a75, 0x1c06, 0xf645, 0xde6b, 0xf5d7, 
+0x1b5b, 0x1a3f, 0xf457, 0xdf0d, 0xf820, 0x1c13, 0x1867, 0xf288, 0xdfd2, 0xfa5f, 
+0x1ca1, 0x167f, 0xf0db, 0xe0ba, 0xfc92, 0x1d06, 0x148b, 0xef50, 0xe1c1, 0xfeb5, 
+0x1d43, 0x1290, 0xede9, 0xe2e6, 0x00c6, 0x1d58, 0x108e, 0xeca7, 0xe426, 0x02c4, 
+0x1d45, 0x0e8a, 0xeb8a, 0xe57f, 0x04a9, 0x1d0e, 0x0c87, 0xea92, 0xe6ec, 0x0677, 
+0x1cb2, 0x0a87, 0xe9be, 0xe86e, 0x082a, 0x1c34, 0x088b, 0xe912, 0xe9fe, 0x09c1, 
+0x1b95, 0x069c, 0xe88c, 0xeb9c, 0x0b3a, 0x1ad9, 0x04b6, 0xe82a, 0xed43, 0x0c96, 
+0x1a00, 0x02df, 0xe7eb, 0xeef3, 0x0dd0, 0x190d, 0x0116, 0xe7d0, 0xf0a8, 0x0eec, 
+0x1804, 0xff61, 0xe7d8, 0xf25d, 0x0fe6, 0x16e3, 0xfdc0, 0xe800, 0xf412, 0x10bf, 
+0x15b1, 0xfc36, 0xe848, 0xf5c5, 0x1176, 0x146e, 0xfac2, 0xe8ad, 0xf771, 0x120d, 
+0x1320, 0xf969, 0xe92e, 0xf913, 0x1282, 0x11c4, 0xf828, 0xe9cb, 0xfaac, 0x12d8, 
+0x1062, 0xf703, 0xea7e, 0xfc38, 0x130e, 0x0efa, 0xf5fb, 0xeb49, 0xfdb5, 0x1325, 
+0x0d8e, 0xf50e, 0xec26, 0xff20, 0x131e, 0x0c21, 0xf43f, 0xed15, 0x007a, 0x12fa, 
+0x0ab6, 0xf38d, 0xee15, 0x01be, 0x12bd, 0x094f, 0xf2f9, 0xef22, 0x02ef, 0x1265, 
+0x07f0, 0xf283, 0xf037, 0x0408, 0x11f6, 0x0699, 0xf226, 0xf156, 0x050a, 0x1170, 
+0x054b, 0xf1e8, 0xf27a, 0x05f4, 0x10d8, 0x040c, 0xf1c5, 0xf3a3, 0x06c2, 0x102c, 
+0x02da, 0xf1bc, 0xf4cc, 0x0779, 0x0f71, 0x01b7, 0xf1cc, 0xf5f5, 0x0815, 0x0ea7, 
+0x00a8, 0xf1f4, 0xf719, 0x0899, 0x0dd2, 0xffab, 0xf233, 0xf839, 0x0902, 0x0cf4, 
+0xfec0, 0xf288, 0xf950, 0x0952, 0x0c0e, 0xfdec, 0xf2ee, 0xfa5d, 0x0989, 0x0b23, 
+0xfd2d, 0xf368, 0xfb62, 0x09a7, 0x0a35, 0xfc85, 0xf3f1, 0xfc58, 0x09af, 0x0946, 
+0xfbf2, 0xf488, 0xfd3f, 0x09a1, 0x0859, 0xfb77, 0xf52c, 0xfe17, 0x097d, 0x076f, 
+0xfb14, 0xf5d8, 0xfede, 0x0945, 0x068a, 0xfac6, 0xf68d, 0xff93, 0x08fb, 0x05ad, 
+0xfa8e, 0xf747, 0x0034, 0x08a1, 0x04da, 0xfa6f, 0xf805, 0x00c2, 0x0836, 0x0410, 
+0xfa63, 0xf8c6, 0x013c, 0x07bf, 0x0354, 0xfa6c, 0xf985, 0x01a1, 0x073b, 0x02a4, 
+0xfa8a, 0xfa43, 0x01f1, 0x06af, 0x0204, 0xfab9, 0xfafc, 0x022c, 0x0619, 0x0175, 
+0xfafa, 0xfbae, 0x0252, 0x057f, 0x00f6, 0xfb4b, 0xfc5a, 0x0263, 0x04e0, 0x008b, 
+0xfbaa, 0xfcfa, 0x0262, 0x0440, 0x0032, 0xfc16, 0xfd90, 0x024b, 0x03a0, 0xffec, 
+0xfc8c, 0xfe19, 0x0225, 0x0301, 0xffb9, 0xfd0c, 0xfe93, 0x01ea, 0x0267, 0xff9c, 
+0xfd95, 0xfefe, 0x01a0, 0x01d3, 0xff90, 0xfe22, 0xff5a, 0x0147, 0x0145, 0xff99, 
+0xfeb3, 0xffa1, 0x00e0, 0x00c3, 0xffb6, 0xff46, 0xffd9, 0x006d, 0x004b, 0xffe5, 
+0xffda, 0xfffc, 000000, 0xfffe, 000000, 0xffff, 000000, 0xffff, 0xffff, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000 };

Added: freeswitch/trunk/src/mod/endpoints/mod_iax/frame.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/frame.h	Thu May  8 19:25:36 2008
@@ -0,0 +1,134 @@
+/*
+ * libiax: An implementation of the Inter-Asterisk eXchange protocol
+ *
+ * Asterisk internal frame definitions.
+ * 
+ * Copyright (C) 1999, Mark Spencer
+ *
+ * Mark Spencer <markster at linux-support.net>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU Lesser General Public License.  Other components of
+ * Asterisk are distributed under The GNU General Public License
+ * only.
+ */
+
+#ifndef _LIBIAX_FRAME_H
+#define _LIBIAX_FRAME_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+/* Frame types */
+#define AST_FRAME_DTMF		1		/* A DTMF digit, subclass is the digit */
+#define AST_FRAME_VOICE		2		/* Voice data, subclass is AST_FORMAT_* */
+#define AST_FRAME_VIDEO		3		/* Video frame, maybe?? :) */
+#define AST_FRAME_CONTROL	4		/* A control frame, subclass is AST_CONTROL_* */
+#define AST_FRAME_NULL		5		/* An empty, useless frame */
+#define AST_FRAME_IAX		6		/* Inter Aterisk Exchange private frame type */
+#define AST_FRAME_TEXT		7		/* Text messages */
+#define AST_FRAME_IMAGE		8		/* Image Frames */
+#define AST_FRAME_HTML		9		/* HTML Frames */
+#define AST_FRAME_CNG           10		/* Comfort Noise frame (subclass is level of CNG in -dBov) */
+
+/* HTML subclasses */
+#define AST_HTML_URL		1		/* Sending a URL */
+#define AST_HTML_DATA		2		/* Data frame */
+#define AST_HTML_BEGIN		4		/* Beginning frame */
+#define AST_HTML_END		8		/* End frame */
+#define AST_HTML_LDCOMPLETE	16		/* Load is complete */
+#define AST_HTML_NOSUPPORT	17		/* Peer is unable to support HTML */
+#define AST_HTML_LINKURL	18		/* Send URL and track */
+#define AST_HTML_UNLINK		19		/* Request no more linkage */
+#define AST_HTML_LINKREJECT	20		/* Reject LINKURL */
+
+/* Data formats for capabilities and frames alike */
+/*! 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 */
+#define AST_CONTROL_RING		2			/* Local ring */
+#define AST_CONTROL_RINGING 	3			/* Remote end is ringing */
+#define AST_CONTROL_ANSWER		4			/* Remote end has answered */
+#define AST_CONTROL_BUSY		5			/* Remote end is busy */
+#define AST_CONTROL_TAKEOFFHOOK 6			/* Make it go off hook */
+#define AST_CONTROL_OFFHOOK		7			/* Line is off hook */
+#define AST_CONTROL_CONGESTION	8			/* Congestion (circuits busy) */
+#define AST_CONTROL_FLASH		9			/* Flash hook */
+#define AST_CONTROL_WINK		10			/* Wink */
+#define AST_CONTROL_OPTION		11			/* Set an option */
+
+#define AST_FRIENDLY_OFFSET		64			/* Reserved header space */
+
+struct ast_frame {
+        /*! Kind of frame */
+        int frametype;
+        /*! Subclass, frame dependent */
+        int subclass;
+        /*! Length of data */
+        int datalen;
+        /*! Number of 8khz samples in this frame */
+        int samples;
+        /*! Was the data malloc'd?  i.e. should we free it when we discard the f
+rame? */
+        int mallocd;
+        /*! How far into "data" the data really starts */
+        int offset;
+        /*! Optional source of frame for debugging */
+        char *src;
+        /*! Pointer to actual data */
+        void *data;
+        /*! Next/Prev for linking stand alone frames */
+        struct ast_frame *prev;
+       /*! Next/Prev for linking stand alone frames */
+        struct ast_frame *next;
+                                                                /* Unused except
+ if debugging is turned on, but left
+                                                                   in the struct
+ so that it can be turned on without
+                                                                   requiring a r
+ecompile of the whole thing */
+};
+
+
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+
+#endif

Added: freeswitch/trunk/src/mod/endpoints/mod_iax/iax-client.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/iax-client.h	Thu May  8 19:25:36 2008
@@ -0,0 +1,244 @@
+/*
+ * Asterisk -- A telephony toolkit for Linux.
+ *
+ * Implementation of Inter-Asterisk eXchange
+ * 
+ * Copyright (C) 1999, Mark Spencer
+ *
+ * Mark Spencer <markster at linux-support.net>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU Lesser General Public License (LGPL)
+ */
+ 
+#ifndef _ASTERISK_IAX_CLIENT_H
+#define _ASTERISK_IAX_CLIENT_H
+
+#ifdef WIN32_TIME_GET_TIME
+#include <Mmsystem.h>
+#endif
+
+#if defined(_MSC_VER)
+/* disable zero-sized array in struct/union warning */
+#pragma warning(disable:4200)
+#endif
+
+#if !defined(LINUX) && !defined(NETBSD)
+#define socklen_t int
+#endif
+
+#include "frame.h"
+#include "iax2.h"
+#include "iax2-parser.h"
+
+#define MAXSTRLEN 80
+
+#define IAX_AUTHMETHOD_PLAINTEXT 	IAX_AUTH_PLAINTEXT
+#define IAX_AUTHMETHOD_MD5 			IAX_AUTH_MD5
+
+extern char iax_errstr[];
+
+struct iax_session;
+
+
+#define IAX_EVENT_CONNECT 0			/* Connect a new call */
+#define IAX_EVENT_ACCEPT  1			/* Accept a call */
+#define IAX_EVENT_HANGUP  2			/* Hang up a call */
+#define IAX_EVENT_REJECT  3			/* Rejected call */
+#define IAX_EVENT_VOICE   4			/* Voice Data */
+#define IAX_EVENT_DTMF    5			/* A DTMF Tone */
+#define IAX_EVENT_TIMEOUT 6			/* Connection timeout...  session will be
+									   a pointer to free()'d memory! */
+#define IAX_EVENT_LAGRQ   7			/* Lag request -- Internal use only */
+#define IAX_EVENT_LAGRP   8			/* Lag Measurement.  See event.lag */
+#define IAX_EVENT_RINGA	  9			/* Announce we/they are ringing */
+#define IAX_EVENT_PING	  10		/* Ping -- internal use only */
+#define IAX_EVENT_PONG	  11		/* Pong -- internal use only */
+#define IAX_EVENT_BUSY	  12		/* Report a line busy */
+#define IAX_EVENT_ANSWER  13		/* Answer the line */
+
+#define IAX_EVENT_IMAGE   14		/* Send/Receive an image */
+#define IAX_EVENT_AUTHRQ  15		/* Authentication request */
+#define IAX_EVENT_AUTHRP  16		/* Authentication reply */
+
+#define IAX_EVENT_REGREQ  17		/* Registration request */
+#define IAX_EVENT_REGACK  18		/* Registration reply */
+#define IAX_EVENT_URL	  19		/* URL received */
+#define IAX_EVENT_LDCOMPLETE 20		/* URL loading complete */
+
+#define IAX_EVENT_TRANSFER	21		/* Transfer has taken place */
+
+#define IAX_EVENT_DPREQ		22		/* Dialplan request */
+#define IAX_EVENT_DPREP		23		/* Dialplan reply */
+#define IAX_EVENT_DIAL		24		/* Dial on a TBD call */
+
+#define IAX_EVENT_QUELCH	25		/* Quelch Audio */
+#define IAX_EVENT_UNQUELCH	26		/* Unquelch Audio */
+
+#define IAX_EVENT_UNLINK	27		/* Unlink */
+#define IAX_EVENT_LINKREJECT	28		/* Link Rejection */
+#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) */
+#define IAX_EVENT_POKE   33
+
+/* moved from iax.c to support attended transfer */
+#define IAX_EVENT_REREQUEST	999
+#define IAX_EVENT_TXREPLY	1000
+#define IAX_EVENT_TXREJECT	1001
+#define IAX_EVENT_TXACCEPT  1002
+#define IAX_EVENT_TXREADY	1003
+
+#define IAX_SCHEDULE_FUZZ 0			/* ms of fuzz to drop */
+
+#ifdef WIN32
+#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 {
+	int etype;						/* Type of event */
+	int subclass;					/* Subclass data (event specific) */
+	time_in_ms_t ts;				/* Timestamp */
+	struct iax_session *session;	/* Applicable session */
+	int datalen;					/* Length of raw data */
+	struct iax_ies ies;				/* IE's for IAX2 frames */
+	unsigned char data[];			/* Raw data if applicable */
+};
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+/* All functions return 0 on success and -1 on failure unless otherwise
+   specified */
+
+/* Called to initialize IAX structures and sockets.  Returns actual
+   portnumber (which it will try preferred portno first, but if not
+   take what it can get */
+extern int iax_init(char *ip, int preferredportno);
+
+extern int iax_shutdown(void);
+
+/* Get filedescriptor for IAX to use with select or gtk_input_add */
+extern int iax_get_fd(void);
+
+/* Find out how many milliseconds until the next scheduled event */
+extern time_in_ms_t iax_time_to_next_event(void);
+
+/* Generate a new IAX session */
+extern struct iax_session *iax_session_new(void);
+
+/* Return exactly one iax event (if there is one pending).  If blocking is
+   non-zero, IAX will block until some event is received */
+extern struct iax_event *iax_get_event(int blocking);
+
+
+extern int iax_auth_reply(struct iax_session *session, char *password, 
+						char *challenge, int methods);
+
+/* Free an event */
+extern void iax_event_free(struct iax_event *event);
+
+struct sockaddr_in;
+
+/* 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, 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, const char *reason);
+int iax_reject_registration(struct iax_session *session, char *reason);
+int iax_ack_registration(struct iax_session *session);
+int iax_auth_registration(struct iax_session *session);
+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, const char *cidnum, const char *cidname, char *ich, char *lang, int wait, int format, int capability);
+extern int iax_accept(struct iax_session *session, int format);
+extern int iax_answer(struct iax_session *session);
+extern int iax_sendurl(struct iax_session *session, char *url);
+extern int iax_send_unlink(struct iax_session *session);
+extern int iax_send_link_reject(struct iax_session *session);
+extern int iax_ring_announce(struct iax_session *session);
+extern struct sockaddr_in iax_get_peer_addr(struct iax_session *session);
+extern int iax_register(struct iax_session *session, char *hostname, char *peer, char *secret, int refresh);
+extern int iax_lag_request(struct iax_session *session);
+extern int iax_dial(struct iax_session *session, char *number);	/* Dial on a TBD call */
+extern int iax_dialplan_request(struct iax_session *session, char *number);	/* Request dialplan status for number */
+extern int iax_quelch(struct iax_session *session);
+extern int iax_unquelch(struct iax_session * session);
+extern int iax_transfer(struct iax_session *session, char *number);  
+extern int iax_quelch_moh(struct iax_session *session, int MOH);
+
+extern void iax_destroy(struct iax_session  * session);
+
+extern void iax_enable_debug(void);
+extern void iax_disable_debug(void);
+
+/* 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
+ * IAX_EVENT_TXREJECT for either side.
+ * If there are music on hold the it will be stopped by this library.
+ */
+extern int iax_setup_transfer(struct iax_session *s0, struct iax_session *s1);
+
+struct iax_netstat {
+	time_in_ms_t jitter;
+	int losspct;
+	int losscnt;
+	int packets;
+	time_in_ms_t 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, time_in_ms_t *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);
+
+/* 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);
+
+/* Fine tune jitterbuffer */
+extern void iax_set_jb_target_extra( long value );
+
+extern char *iax_get_peer_ip(struct iax_session *session);
+extern char *iax_event_get_apparent_ip(struct iax_event *event);
+extern void iax_set_samplerate(struct iax_session *session, unsigned short samplemask);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* _ASTERISK_IAX_CLIENT_H */

Added: freeswitch/trunk/src/mod/endpoints/mod_iax/iax-mutex.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/iax-mutex.c	Thu May  8 19:25:36 2008
@@ -0,0 +1,124 @@
+/* 
+ * Simple Mutex abstraction
+ * Copyright(C) 2007 Michael Jerris
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so.
+ *
+ * This work is provided under this license on an "as is" basis, without warranty of any kind,
+ * either expressed or implied, including, without limitation, warranties that the covered code
+ * is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire
+ * risk as to the quality and performance of the covered code is with you. Should any covered
+ * code prove defective in any respect, you (not the initial developer or any other contributor)
+ * assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty
+ * constitutes an essential part of this license. No use of any covered code is authorized hereunder
+ * except under this disclaimer. 
+ *
+ */
+
+#define _XOPEN_SOURCE 600
+#include <stdlib.h>
+#include "iax-mutex.h"
+
+
+#ifdef WIN32
+#define _WIN32_WINNT 0x0400
+#include <windows.h>
+struct mutex {
+	CRITICAL_SECTION mutex;
+};
+
+#else
+
+#include <pthread.h>
+struct mutex {
+	pthread_mutex_t mutex;
+};
+
+#endif
+
+
+mutex_status_t iax_mutex_create(mutex_t **mutex)
+{
+	mutex_status_t status = MUTEX_FAILURE;
+#ifndef WIN32
+	pthread_mutexattr_t attr;
+#endif
+	mutex_t *check = NULL;
+
+	check = (mutex_t *)malloc(sizeof(**mutex));
+	if (!check)
+		goto done;
+#ifdef WIN32
+	InitializeCriticalSection(&check->mutex);
+#else
+	if (pthread_mutexattr_init(&attr))
+		goto done;
+
+	if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE))
+		goto fail;
+
+	if (pthread_mutex_init(&check->mutex, &attr))
+		goto fail;
+
+	goto success;
+
+fail:
+        pthread_mutexattr_destroy(&attr);
+		goto done;
+
+success:
+#endif
+	*mutex = check;
+	status = MUTEX_SUCCESS;
+
+done:
+	return status;
+}
+
+mutex_status_t iax_mutex_destroy(mutex_t *mutex)
+{
+#ifdef WIN32
+	DeleteCriticalSection(&mutex->mutex);
+#else
+	if (pthread_mutex_destroy(&mutex->mutex))
+		return MUTEX_FAILURE;
+#endif
+	free(mutex);
+	return MUTEX_SUCCESS;
+}
+
+mutex_status_t iax_mutex_lock(mutex_t *mutex)
+{
+#ifdef WIN32
+	EnterCriticalSection(&mutex->mutex);
+#else
+	if (pthread_mutex_lock(&mutex->mutex))
+		return MUTEX_FAILURE;
+#endif
+	return MUTEX_SUCCESS;
+}
+
+mutex_status_t iax_mutex_trylock(mutex_t *mutex)
+{
+#ifdef WIN32
+	if (!TryEnterCriticalSection(&mutex->mutex))
+		return MUTEX_FAILURE;
+#else
+	if (pthread_mutex_trylock(&mutex->mutex))
+		return MUTEX_FAILURE;
+#endif
+	return MUTEX_SUCCESS;
+}
+
+mutex_status_t iax_mutex_unlock(mutex_t *mutex)
+{
+#ifdef WIN32
+	LeaveCriticalSection(&mutex->mutex);
+#else
+	if (pthread_mutex_unlock(&mutex->mutex))
+		return MUTEX_FAILURE;
+#endif
+	return MUTEX_SUCCESS;
+}

Added: freeswitch/trunk/src/mod/endpoints/mod_iax/iax-mutex.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/iax-mutex.h	Thu May  8 19:25:36 2008
@@ -0,0 +1,37 @@
+/* 
+ * Simple Mutex abstraction
+ * Copyright(C) 2007 Michael Jerris
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so.
+ *
+ * This work is provided under this license on an "as is" basis, without warranty of any kind,
+ * either expressed or implied, including, without limitation, warranties that the covered code
+ * is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire
+ * risk as to the quality and performance of the covered code is with you. Should any covered
+ * code prove defective in any respect, you (not the initial developer or any other contributor)
+ * assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty
+ * constitutes an essential part of this license. No use of any covered code is authorized hereunder
+ * except under this disclaimer. 
+ *
+ */
+
+
+#ifndef _SIMPLE_ABSTRACT_MUTEX_H
+#define _SIMPLE_ABSTRACT_MUTEX_H
+
+typedef struct mutex mutex_t;
+
+typedef enum mutex_status {
+	MUTEX_SUCCESS,
+	MUTEX_FAILURE
+} mutex_status_t;
+
+mutex_status_t iax_mutex_create(mutex_t **mutex);
+mutex_status_t iax_mutex_destroy(mutex_t *mutex);
+mutex_status_t iax_mutex_lock(mutex_t *mutex);
+mutex_status_t iax_mutex_trylock(mutex_t *mutex);
+mutex_status_t iax_mutex_unlock(mutex_t *mutex);
+
+#endif

Added: freeswitch/trunk/src/mod/endpoints/mod_iax/iax.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/iax.c	Thu May  8 19:25:36 2008
@@ -0,0 +1,3366 @@
+ /*
+ * libiax: An implementation of Inter-Asterisk eXchange
+ *
+ * Copyright (C) 2001, Linux Support Services, Inc.
+ *
+ * Mark Spencer <markster at linux-support.net>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU Lesser (Library) General Public License
+ */
+ 
+#ifdef	WIN32
+#undef __STRICT_ANSI__ //for strdup with ms
+
+#include <string.h>
+#include <process.h>
+#include <windows.h>
+#include <winsock.h>
+#include <time.h>
+#include <stdlib.h>
+#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 inline __inline
+#define strdup _strdup
+#endif
+
+void gettimeofday(struct timeval *tv, void /*struct timezone*/ *tz);
+#include "winpoop.h"
+
+#else
+
+#define _BSD_SOURCE 1
+#include <netdb.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/select.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <time.h>
+       
+#endif
+
+#include "iax2.h"
+#include "iax-client.h"
+#include "md5.h"
+
+#ifdef NEWJB
+#include "jitterbuf.h"
+#endif
+#include "iax-mutex.h"
+/*
+	work around jitter-buffer shrinking in asterisk:
+	channels/chan_iax2.c:schedule_delivery() shrinks jitter buffer by 2.
+	this causes frames timestamped 1ms apart to ( sometimes ) be delivered 
+	out of order, and results in garbled audio. our temporary fix is to increase
+	the minimum number of ( timestamped ) milliseconds between frames to 3 ( 2 + 1 ).
+*/
+#define IAX_MIN_TIMESTAMP_INCREMENT 3
+
+/* Define socket options for IAX2 sockets, based on platform
+ * availability of flags */
+#ifdef WIN32
+ #define IAX_SOCKOPTS 0
+#else
+ #ifdef LINUX
+ #define IAX_SOCKOPTS MSG_DONTWAIT | MSG_NOSIGNAL
+ #else
+ #define IAX_SOCKOPTS MSG_DONTWAIT
+ #endif
+#endif
+
+
+
+#ifdef SNOM_HACK
+/* The snom phone seems to improperly execute memset in some cases */
+#include "../../snom_phonecore2/include/snom_memset.h"
+#endif
+
+/* Voice TS Prediction causes libiax2 to clean up the timestamps on
+ * outgoing frames.  It works best with either continuous voice, or
+ * callers who call iax_send_cng to indicate DTX for silence */
+#define USE_VOICE_TS_PREDICTION
+
+/* Define Voice Smoothing to try to make some judgements and adjust timestamps
+   on incoming packets to what they "ought to be" */
+
+#define VOICE_SMOOTHING
+#undef VOICE_SMOOTHING
+
+/* Define Drop Whole Frames to make IAX shrink its jitter buffer by dropping entire
+   frames rather than simply delivering them faster.  Dropping encoded frames, 
+   before they're decoded, usually leads to better results than dropping 
+   decoded frames. */
+
+#define DROP_WHOLE_FRAMES
+
+#define MIN_RETRY_TIME 10
+#define MAX_RETRY_TIME 4000
+#define MEMORY_SIZE 1000
+
+#define TRANSFER_NONE  0
+#define TRANSFER_BEGIN 1
+#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 */
+static int max_extra_jitterbuffer = 50;
+/* 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;
+
+/* configurable jitterbuffer options */
+static long jb_target_extra = -1; 
+
+static int do_shutdown = 0;
+
+/* 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;
+	/* 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 */
+	int svoiceformat;
+	/* Per session capability */
+	int capability;
+	/* Last received timestamp */
+	time_in_ms_t last_ts;
+	/* Last transmitted timestamp */
+	time_in_ms_t lastsent;
+	/* Last transmitted voice timestamp */
+	unsigned int lastvoicets;
+	/* Next predicted voice ts */
+	time_in_ms_t nextpred;
+	/* True if the last voice we transmitted was not silence/CNG */
+	int notsilenttx;
+	/* Our last measured ping time */
+	time_in_ms_t pingtime;
+	/* Address of peer */
+	struct sockaddr_in peeraddr;
+	/* Our call number */
+	int callno;
+	/* Peer's call number */
+	int peercallno;
+	/* Our next outgoing sequence number */
+	unsigned char oseqno;
+	/* Next sequence number they have not yet acknowledged */
+	unsigned char rseqno;
+	/* Our last received incoming sequence number */
+	unsigned char iseqno;
+	/* Last acknowledged sequence number */
+	unsigned char aseqno;
+	/* Peer supported formats */
+	int peerformats;
+	/* Time value that we base our transmission on */
+	time_in_ms_t offset;
+	/* Time value we base our delivery on */
+	time_in_ms_t rxcore;
+	/* History of lags */
+	int history[MEMORY_SIZE];
+	/* Current base jitterbuffer */
+	int jitterbuffer;
+	/* Informational jitter */
+	int jitter;
+	/* Measured lag */
+	int lag;
+	/* Current link state */
+	int state;
+	/* Peer name */
+	char peer[MAXSTRLEN];
+	/* Default Context */
+	char context[MAXSTRLEN];
+	/* Caller ID if available */
+	char callerid[MAXSTRLEN];
+	/* DNID */
+	char dnid[MAXSTRLEN];
+	/* Requested Extension */
+	char exten[MAXSTRLEN];
+	/* Expected Username */
+	char username[MAXSTRLEN];
+	/* Expected Secret */
+	char secret[MAXSTRLEN];
+	/* permitted authentication methods */
+	char methods[MAXSTRLEN];
+	/* MD5 challenge */
+	char challenge[12];
+#ifdef VOICE_SMOOTHING
+	unsigned int lastts;
+#endif
+	/* Refresh if applicable */
+	int refresh;
+
+	/* ping scheduler id */
+	int pingid;
+	
+	/* Transfer stuff */
+	struct sockaddr_in transfer;
+	int transferring;
+	int transfercallno;
+	int transferid;
+	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;
+
+	unsigned short samplemask;
+	/* For linking if there are multiple connections */
+	struct iax_session *next;
+};
+
+char iax_errstr[256];
+
+static void destroy_session(struct iax_session *session);
+
+#define IAXERROR snprintf(iax_errstr, sizeof(iax_errstr), 
+
+#ifdef DEBUG_SUPPORT
+
+#ifdef DEBUG_DEFAULT
+static int debug = 1;
+#else
+static int debug = 0;
+#endif
+
+void iax_enable_debug(void)
+{
+	debug = 1;
+}
+
+void iax_disable_debug(void)
+{
+	debug = 0;
+}
+
+/* This is a little strange, but to debug you call DEBU(G "Hello World!\n"); */ 
+#ifdef WIN32
+#define G __FILE__, __LINE__, __FUNCTION__, 
+#else
+#define G __FILE__, __LINE__, (const char *)__func__, 
+#endif
+
+#define DEBU __debug 
+static int __debug(char *file, int lineno, const char *func, char *fmt, ...) 
+{
+	va_list args;
+	va_start(args, fmt);
+	if (debug) {
+		fprintf(stderr, "%s line %d in %s: ", file, lineno, func);
+		vfprintf(stderr, fmt, args);
+	}
+	va_end(args);
+	return 0;
+}
+
+#else /* No debug support */
+
+#ifdef	WIN32
+#define	DEBU
+#else
+#define DEBU(...) (void)(0)
+#endif
+#define G
+#endif
+
+typedef void (*sched_func)(void *);
+
+struct iax_sched {
+	/* These are scheduled things to be delivered */
+	time_in_ms_t when;
+	/* If event is non-NULL then we're delivering an event */
+	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;
+};
+
+static mutex_t *sched_mutex = NULL;
+static mutex_t *session_mutex = NULL;
+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 time_init = 0;
+
+static void init_time(void)
+{
+#ifdef WIN32_TIME_GET_TIME
+	timeBeginPeriod(1);
+#endif
+	time_init = 1;
+}
+
+static void time_end(void)
+{
+#ifdef WIN32_TIME_GET_TIME
+	timeEndPeriod(1);
+#endif
+	time_init = 0;
+}
+
+static time_in_ms_t current_time_in_ms(void)
+{
+#ifdef WIN32_TIME_GET_TIME
+	return timeGetTime();
+#else
+	struct timeval tv;
+	gettimeofday(&tv, NULL);
+	return ((tv.tv_sec * 1000) + (tv.tv_usec / 1000));
+#endif
+}
+
+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;
+}
+
+
+unsigned int iax_session_get_capability(struct iax_session *s)
+{
+	return s->capability;
+}
+
+
+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_add(struct iax_event *event, struct iax_frame *frame, sched_func func, void *arg, time_in_ms_t 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 && !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) {
+        memset(sched, 0, sizeof(struct iax_sched));
+		sched->when = current_time_in_ms() + ms;
+		sched->event = event;
+		sched->frame = frame;
+		sched->func = func;
+		sched->arg = arg;
+		/* Put it in the list, in order */
+		iax_mutex_lock(sched_mutex);
+		cur = schedq;
+		while(cur && cur->when <= sched->when) {
+			prev = cur;
+			cur = cur->next;
+		}
+		sched->next = cur;
+		if (prev) {
+			prev->next = sched;
+		} else {
+			schedq = sched;
+		}
+		iax_mutex_unlock(sched_mutex);
+		return 0;
+	} else {
+		DEBU(G "Out of memory!\n");
+		return -1;
+	}
+}
+
+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;
+	int ret = 0;
+
+	iax_mutex_lock(sched_mutex);
+	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) {
+				ret = -1;
+				goto done;
+			}
+		} else {
+			prev = cur;
+			cur = cur->next;
+		}
+	}
+ done:
+	iax_mutex_unlock(sched_mutex);
+
+	return 0;
+
+}
+
+
+time_in_ms_t iax_time_to_next_event(void)
+{
+	struct iax_sched *cur = NULL;
+	time_in_ms_t minimum = 999999999;
+	
+	iax_mutex_lock(sched_mutex);
+	cur = schedq;
+
+	/* If there are no pending events, we don't need to timeout */
+	if (!cur) {
+		iax_mutex_unlock(sched_mutex);
+		return -1;
+	}
+	while(cur) {
+		if (cur->when < minimum) {
+			minimum = cur->when;
+		}
+		cur = cur->next;
+	}
+	iax_mutex_unlock(sched_mutex);
+
+	if (minimum <= 0) {
+		return -1;
+	}
+
+
+
+	return minimum - current_time_in_ms();
+}
+
+struct iax_session *iax_session_new(void)
+{
+	struct iax_session *s;
+	s = (struct iax_session *)malloc(sizeof(struct iax_session));
+	if (s) {
+		memset(s, 0, sizeof(struct iax_session));
+		/* Initialize important fields */
+		s->voiceformat = -1;
+		s->svoiceformat = -1;
+		/* Default pingtime to 30 ms */
+		s->pingtime = 30;
+		/* XXX Not quite right -- make sure it's not in use, but that won't matter
+	           unless you've had at least 65k calls.  XXX */
+		s->callno = callnums++;
+		if (callnums > 32767)
+			callnums = 1;
+		s->peercallno = 0;
+		s->transferpeer = 0;		/* for attended transfer */
+
+		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;
+			jbconf.target_extra = jb_target_extra;
+			jb_setconf(s->jb, &jbconf);
+		}
+#endif
+		iax_mutex_lock(session_mutex);
+		s->next = sessions;
+		sessions = s;
+		iax_mutex_unlock(session_mutex);
+	}
+	return s;
+}
+
+static int iax_session_valid(struct iax_session *session)
+{
+	/* Return -1 on a valid iax session pointer, 0 on a failure */
+	struct iax_session *cur;
+
+	iax_mutex_lock(session_mutex);
+	cur = sessions;
+	while(cur) {
+		if (session == cur) {
+			iax_mutex_unlock(session_mutex);
+			return -1;
+		}
+		cur = cur->next;
+	}
+	iax_mutex_unlock(session_mutex);
+
+	return 0;
+}
+
+int iax_get_netstats(struct iax_session *session, time_in_ms_t *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 time_in_ms_t calc_timestamp(struct iax_session *session, time_in_ms_t ts, struct ast_frame *f)
+{
+	time_in_ms_t ms;
+	time_in_ms_t time_in_ms;
+	int voice = 0;
+	int genuine = 0;
+	
+	if (f && f->frametype == AST_FRAME_VOICE) {
+		voice = 1;
+	} else if (!f || f->frametype == AST_FRAME_IAX) {
+		genuine = 1;
+	}
+	
+	/* If this is the first packet we're sending, get our
+	   offset now. */
+	if (!session->offset) {
+		session->offset = current_time_in_ms();
+	}
+	/* If the timestamp is specified, just use their specified
+	   timestamp no matter what.  Usually this is done for
+	   special cases.  */
+	if (ts) {
+		return ts;
+	}
+	/* Otherwise calculate the timestamp from the current time */
+	time_in_ms = current_time_in_ms();
+
+
+	/* Calculate the number of milliseconds since we sent the first packet */
+	ms = time_in_ms - session->offset;
+
+	if (ms < 0) {
+		ms = 0;
+	}
+
+	if(voice) {
+#ifdef USE_VOICE_TS_PREDICTION
+
+		/* If we haven't most recently sent silence, and we're
+		 * close in time, use predicted time */
+		if(session->notsilenttx && iax_abs(ms - session->nextpred) <= 240) {
+		    /* Adjust our txcore, keeping voice and non-voice
+		     * synchronized */
+			session->offset += (int)(ms - session->nextpred)/10;
+		    
+		    if(!session->nextpred) {
+				session->nextpred = ms; 
+			}
+		    ms = session->nextpred; 
+		} else {
+		    /* in this case, just use the actual time, since
+		     * we're either way off (shouldn't happen), or we're
+		     * ending a silent period -- and seed the next predicted
+		     * time.  Also, round ms to the next multiple of
+		     * frame size (so our silent periods are multiples
+		     * of frame size too) */
+		    time_in_ms_t diff = ms % (f->samples / 8);
+		    if(diff)
+			ms += f->samples/8 - diff;
+		    session->nextpred = ms; 
+		}
+#else
+		if(ms <= session->lastsent)
+			ms = session->lastsent + 3;
+#endif
+		session->notsilenttx = 1;
+	} else {
+		/* 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)
+				ms = session->lastsent + 3;
+		} else if (iax_abs(ms - session->lastsent) <= 240) {
+			ms = session->lastsent + 3;
+		}
+	      
+	}
+
+	/* Record the last sent packet for future reference */
+	/* unless an AST_FRAME_IAX */
+	if (!genuine)
+		session->lastsent = ms;
+
+#ifdef USE_VOICE_TS_PREDICTION
+	/* set next predicted ts based on 8khz samples */
+	if(voice)
+	    session->nextpred = session->nextpred + f->samples / 8;
+#endif
+
+	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)
+{
+	/* Send the frame raw */
+#ifdef DEBUG_SUPPORT
+	struct ast_iax2_full_hdr *h = (f->data);
+	if (ntohs(h->scallno) & IAX_FLAG_FULL)
+		iax_showframe(f, NULL, 0, f->transfer ? 
+						&(f->session->transfer) :
+					&(f->session->peeraddr), f->datalen - sizeof(struct ast_iax2_full_hdr));
+#endif
+
+	return f->session->sendto(netfd, (const char *) f->data, f->datalen,
+		IAX_SOCKOPTS,
+					f->transfer ? 
+						(struct sockaddr *)&(f->session->transfer) :
+					(struct sockaddr *)&(f->session->peeraddr), sizeof(f->session->peeraddr));
+}
+
+static int iax_reliable_xmit(struct iax_frame *f)
+{
+	struct iax_frame *fc;
+	struct ast_iax2_full_hdr *fh;
+	fh = (struct ast_iax2_full_hdr *) f->data;
+	if (!fh->type) {
+		DEBU(G "Asked to reliably transmit a non-packet.  Crashing.\n");
+		*((char *)0)=0;
+	}
+	fc = (struct iax_frame *)malloc(sizeof(struct iax_frame));
+	if (fc) {
+		/* Make a copy of the frame */
+		memcpy(fc, f, sizeof(struct iax_frame));
+		/* And a copy of the data if applicable */
+		if (!fc->data || !fc->datalen) {
+			IAXERROR "No frame data?");
+			DEBU(G "No frame data?\n");
+			return -1;
+		} else {
+			fc->data = (char *)malloc(fc->datalen);
+			if (!fc->data) {
+				DEBU(G "Out of memory\n");
+				IAXERROR "Out of memory\n");
+				return -1;
+			}
+			memcpy(fc->data, f->data, f->datalen);
+			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)
+{
+
+	init_time();
+	iax_sendto = st;
+	iax_recvfrom = rf;
+}
+
+int __iax_shutdown(void)
+{
+	struct iax_sched *sp, *fp;
+
+	/* Hangup Calls */
+	if (sessions) {
+		struct iax_session *sp = NULL, *fp = NULL;
+		iax_mutex_lock(session_mutex); 
+		for(sp = sessions; sp ;) {
+			iax_hangup(sp, "System Shutdown");
+			fp = sp;
+			sp = sp->next;
+			destroy_session(fp);
+		}
+		iax_mutex_unlock(session_mutex); 
+	}
+
+	/* Clear Scheduler */
+	iax_mutex_lock(sched_mutex);
+	for(sp = schedq; sp ;) {
+		fp = sp;
+		sp = sp->next;
+		free(fp);
+	}
+	iax_mutex_unlock(sched_mutex);
+	
+	if (netfd > -1) {
+		shutdown(netfd, 2);
+		close(netfd);
+	}
+
+	time_end();
+
+	iax_mutex_destroy(sched_mutex);
+	iax_mutex_destroy(session_mutex);
+
+	return 0;
+}
+
+int iax_shutdown(void)
+{
+	return do_shutdown++;
+}
+
+void iax_set_jb_target_extra( long value )
+{
+	/* store in jb_target_extra, a static global */
+	jb_target_extra = value ;
+}
+
+int iax_init(char *ip, int preferredportno)
+{
+	int portno = preferredportno;
+	struct sockaddr_in sin;
+	unsigned int sinlen;
+	int flags;
+
+	init_time();
+
+	iax_mutex_create(&sched_mutex);
+	iax_mutex_create(&session_mutex);
+
+	if(iax_recvfrom == (recvfrom_t) recvfrom) {
+	    if (netfd > -1) {
+		    /* Sokay, just don't do anything */
+		    DEBU(G "Already initialized.");
+		    return 0;
+	    }
+	    netfd = (int)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)  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) 
+		{
+#if defined(WIN32)  ||  defined(_WIN32_WCE)
+			if (WSAGetLastError() == WSAEADDRINUSE)
+#else
+			if (errno == EADDRINUSE)
+#endif
+			{
+				/*the port is already in use, so bind to a free port chosen by the IP stack*/
+				DEBU(G "Unable to bind to preferred port - port is in use. Trying to bind to a free one");
+				sin.sin_port = htons((short)0);
+				if (bind(netfd, (struct sockaddr *) &sin, sizeof(sin)) < 0)
+				{
+					IAXERROR "Unable to bind UDP socket\n");
+					return -1;
+				}
+			} else
+			{
+				IAXERROR "Unable to bind UDP socket\n");
+				return -1;
+			}
+		}
+		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)) {
+		    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.");
+	    }
+#endif
+	    portno = ntohs(sin.sin_port);
+	}
+	srand((unsigned int)time(NULL));
+	callnums = rand() % 32767 + 1;
+	transfer_id = rand() % 32767 + 1;
+	DEBU(G "Started on port %d\n", portno);
+	return portno;	
+}
+
+
+
+static void convert_reply(char *out, unsigned char *in)
+{
+	int x;
+	for (x=0;x<16;x++)
+		out += sprintf(out, "%2.2x", (int)in[x]);
+}
+
+static unsigned char compress_subclass(int subclass)
+{
+	int x;
+	int power=-1;
+	/* If it's 128 or smaller, just return it */
+	if (subclass < IAX_FLAG_SC_LOG)
+		return subclass;
+	/* Otherwise find its power */
+	for (x = 0; x < IAX_MAX_SHIFT; x++) {
+		if (subclass & (1 << x)) {
+			if (power > -1) {
+				DEBU(G "Can't compress subclass %d\n", subclass);
+				return 0;
+			} else
+				power = x;
+		}
+	}
+	return power | IAX_FLAG_SC_LOG;
+}
+
+static int iax_send(struct iax_session *pvt, struct ast_frame *f, time_in_ms_t ts, int seqno, int now, int transfer, int final) 
+{
+	/* Queue a packet for delivery on a given private structure.  Use "ts" for
+	   timestamp, or calculate if ts is 0.  Send immediately without retransmission
+	   or delayed, with retransmission */
+	struct ast_iax2_full_hdr *fh;
+	struct ast_iax2_mini_hdr *mh;
+	unsigned char	buf[5120];
+	struct iax_frame *fr;
+	int res;
+	int sendmini=0;
+	time_in_ms_t lastsent;
+	time_in_ms_t fts;
+	
+	if (!pvt) {
+		IAXERROR "No private structure for packet?\n");
+		return -1;
+	}
+	
+	/* this must come before the next call to calc_timestamp() since
+	 calc_timestamp() will change lastsent to the returned value */
+	lastsent = pvt->lastsent;
+
+	/* Calculate actual timestamp */
+	fts = calc_timestamp(pvt, ts, f);
+
+	if (((fts & 0xFFFF0000L) == (lastsent & 0xFFFF0000L))
+		/* High two bits are the same on timestamp, or sending on a trunk */ &&
+	    (f->frametype == AST_FRAME_VOICE) 
+		/* is a voice frame */ &&
+		(f->subclass == pvt->svoiceformat) 
+		/* is the same type */ ) {
+			/* Force immediate rather than delayed transmission */
+			now = 1;
+			/* Mark that mini-style frame is appropriate */
+			sendmini = 1;
+	}
+	/* Allocate an iax_frame */
+	if (now) {
+		fr = (struct iax_frame *) buf;
+	} else
+		fr = iax_frame_new(DIRECTION_OUTGRESS, f->datalen);
+	if (!fr) {
+		IAXERROR "Out of memory\n");
+		return -1;
+	}
+	/* Copy our prospective frame into our immediate or retransmitted wrapper */
+	iax_frame_wrap(fr, f);
+
+	fr->ts = fts;
+	if (!fr->ts) {
+		IAXERROR "timestamp is 0?\n");
+		if (!now)
+			iax_frame_free(fr);
+		return -1;
+	}
+
+	fr->callno = pvt->callno;
+	fr->transfer = transfer;
+	fr->final = final;
+	fr->session = pvt;
+	if (!sendmini) {
+		/* We need a full frame */
+		if (seqno > -1)
+			fr->oseqno = seqno;
+		else
+			fr->oseqno = pvt->oseqno++;
+		fr->iseqno = pvt->iseqno;
+		fh = (struct ast_iax2_full_hdr *)(((char *)fr->af.data) - sizeof(struct ast_iax2_full_hdr));
+		fh->scallno = htons(fr->callno | IAX_FLAG_FULL);
+		fh->ts = htonl((long)(fr->ts));
+		fh->oseqno = fr->oseqno;
+		if (transfer) {
+			fh->iseqno = 0;
+		} else
+			fh->iseqno = fr->iseqno;
+		/* Keep track of the last thing we've acknowledged */
+		pvt->aseqno = fr->iseqno;
+		fh->type = fr->af.frametype & 0xFF;
+		fh->csub = compress_subclass(fr->af.subclass);
+		if (transfer) {
+			fr->dcallno = pvt->transfercallno;
+		} else
+			fr->dcallno = pvt->peercallno;
+		fh->dcallno = htons(fr->dcallno);
+		fr->datalen = fr->af.datalen + sizeof(struct ast_iax2_full_hdr);
+		fr->data = fh;
+		fr->retries = maxretries;
+		/* Retry after 2x the ping time has passed */
+		fr->retrytime = pvt->pingtime * 2;
+		if (fr->retrytime < MIN_RETRY_TIME)
+			fr->retrytime = MIN_RETRY_TIME;
+		if (fr->retrytime > MAX_RETRY_TIME)
+			fr->retrytime = MAX_RETRY_TIME;
+		/* Acks' don't get retried */
+		if ((f->frametype == AST_FRAME_IAX) && (f->subclass == IAX_COMMAND_ACK))
+			fr->retries = -1;
+		if (f->frametype == AST_FRAME_VOICE) {
+			pvt->svoiceformat = f->subclass;
+		}
+		if (now) {
+			res = iax_xmit_frame(fr);
+		} else
+			res = iax_reliable_xmit(fr);
+	} else {
+		/* Mini-frames have no sequence number */
+		fr->oseqno = -1;
+		fr->iseqno = -1;
+		/* Mini frame will do */
+		mh = (struct ast_iax2_mini_hdr *)(((char *)fr->af.data) - sizeof(struct ast_iax2_mini_hdr));
+		mh->callno = htons(fr->callno);
+		mh->ts = htons((short)(fr->ts & 0xFFFF));
+		fr->datalen = fr->af.datalen + sizeof(struct ast_iax2_mini_hdr);
+		fr->data = mh;
+		fr->retries = -1;
+		res = iax_xmit_frame(fr);
+	}
+	if( !now && fr!=NULL )
+	        iax_frame_free( fr ); 
+	return res;
+}
+
+#if 0
+static int iax_predestroy(struct iax_session *pvt)
+{
+	if (!pvt) {
+		return -1;
+	}
+	if (!pvt->alreadygone) {
+		/* No more pings or lagrq's */
+		if (pvt->pingid > -1)
+			ast_sched_del(sched, pvt->pingid);
+		if (pvt->lagid > -1)
+			ast_sched_del(sched, pvt->lagid);
+		if (pvt->autoid > -1)
+			ast_sched_del(sched, pvt->autoid);
+		if (pvt->initid > -1)
+			ast_sched_del(sched, pvt->initid);
+		pvt->pingid = -1;
+		pvt->lagid = -1;
+		pvt->autoid = -1;
+		pvt->initid = -1;
+		pvt->alreadygone = 1;
+	}
+	return 0;
+}
+#endif
+
+static int __send_command(struct iax_session *i, char type, int command, time_in_ms_t ts, unsigned char *data, int datalen, int seqno, 
+		int now, int transfer, int final, int samples)
+{
+	struct ast_frame f;
+	f.frametype = type;
+	f.subclass = command;
+	f.datalen = datalen;
+	f.samples = samples;
+	f.mallocd = 0;
+	f.offset = 0;
+#ifdef __GNUC__
+	f.src = (char *) __FUNCTION__;
+#else
+	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, time_in_ms_t 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, unsigned char *data, int datalen, int seqno)
+{
+#if 0
+	/* It is assumed that the callno has already been locked */
+	iax_predestroy(i);
+#endif	
+	int r;
+	r = __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 1, 0);
+	if (r >= 0) {
+		iax_mutex_lock(session_mutex); 
+		destroy_session(i);
+		iax_mutex_unlock(session_mutex);
+	}
+	return r;
+}
+
+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, 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, unsigned char *data, int datalen, int seqno, int samples)
+{
+	return __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 0, samples);
+}
+
+
+int iax_transfer(struct iax_session *session, char *number)
+{	
+	static int res;				//Return Code
+	struct iax_ie_data ied;			//IE Data Structure (Stuff To Send)
+
+	// Clear The Memory Used For IE Buffer
+	memset(&ied, 0, sizeof(ied));
+	
+	// Copy The Transfer Destination Into The IE Structure
+	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);
+	
+	// Return Success
+	return 0;	
+}
+
+static void stop_transfer(struct iax_session *session)
+{
+	struct iax_sched *sch;
+
+	iax_mutex_lock(sched_mutex);
+	sch = schedq;
+	while(sch) {
+		if (sch->frame && (sch->frame->session == session))
+					sch->frame->retries = -1;
+		sch = sch->next;
+	}
+	iax_mutex_unlock(sched_mutex);
+}	/* stop_transfer */
+
+static void complete_transfer(struct iax_session *session, int peercallno, int xfr2peer, int preserveSeq)
+{
+	session->peercallno = peercallno;
+	/* Change from transfer to session now */
+	if (xfr2peer) {
+		memcpy(&session->peeraddr, &session->transfer, sizeof(session->peeraddr));
+		memset(&session->transfer, 0, sizeof(session->transfer));
+		session->transferring = TRANSFER_NONE;
+		session->transferpeer = 0;
+		session->transfer_moh = 0;
+		/* Force retransmission of a real voice packet, and reset all timing */
+		session->svoiceformat = -1;
+		session->voiceformat = 0;
+	}
+	session->rxcore = session->offset = 0;
+	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;
+
+	if (! preserveSeq)
+	{
+		/* Reset sequence numbers */
+		session->aseqno = 0;
+		session->oseqno = 0;
+		session->iseqno = 0;
+	}
+
+	session->lastsent = 0;
+	session->last_ts = 0;
+	session->lastvoicets = 0;
+	session->pingtime = 30;
+	/* We have to dump anything we were going to (re)transmit now that we've been
+	   transferred since they're all invalid and for the old host. */
+	stop_transfer(session);
+}	/* complete_transfer */
+
+int iax_setup_transfer(struct iax_session *org_session, struct iax_session *new_session)
+{
+	int res;
+	struct iax_ie_data ied0;
+	struct iax_ie_data ied1;
+
+	struct iax_session *s0 = org_session;
+	struct iax_session *s1 = new_session;
+
+	memset(&ied0, 0, sizeof(ied0));
+	memset(&ied1, 0, sizeof(ied1));
+
+	/* reversed setup */
+	iax_ie_append_addr(&ied0, IAX_IE_APPARENT_ADDR, &s1->peeraddr);
+	iax_ie_append_short(&ied0, IAX_IE_CALLNO, s1->peercallno);
+	iax_ie_append_int(&ied0, IAX_IE_TRANSFERID, transfer_id);
+
+	iax_ie_append_addr(&ied1, IAX_IE_APPARENT_ADDR, &s0->peeraddr);
+	iax_ie_append_short(&ied1, IAX_IE_CALLNO, s0->peercallno);
+	iax_ie_append_int(&ied1, IAX_IE_TRANSFERID, transfer_id);
+
+	s0->transfer = s1->peeraddr;
+	s1->transfer = s0->peeraddr;
+
+	s0->transferid = transfer_id;
+	s1->transferid = transfer_id;
+
+	s0->transfercallno = s0->peercallno;
+	s1->transfercallno = s1->peercallno;
+
+	s0->transferring = TRANSFER_BEGIN;
+	s1->transferring = TRANSFER_BEGIN;
+
+	s0->transferpeer = s1->callno;
+	s1->transferpeer = s0->callno;
+
+	transfer_id++;
+
+	if (transfer_id > 32767)
+		transfer_id = 1;
+
+	res = send_command(s0, AST_FRAME_IAX, IAX_COMMAND_TXREQ, 0, ied0.buf, ied0.pos, -1);
+	if (res < 0) {
+		return -1;
+	}
+
+	res = send_command(s1, AST_FRAME_IAX, IAX_COMMAND_TXREQ, 0, ied1.buf, ied1.pos, -1);
+	if (res < 0) {
+		return -1;
+	}
+
+	return 0;
+}
+
+static int iax_finish_transfer(struct iax_session *s, short new_peer)
+{
+	int res;
+	struct iax_ie_data ied;
+
+	memset(&ied, 0, sizeof(ied));
+
+	iax_ie_append_short(&ied, IAX_IE_CALLNO, new_peer);
+
+	res = send_command(s, AST_FRAME_IAX, IAX_COMMAND_TXREL, 0, ied.buf, ied.pos, -1);
+
+	complete_transfer(s, new_peer, 0, 1);
+
+	return res;
+
+}
+
+static struct iax_session *iax_find_session2(short callno)
+{
+	struct iax_session *cur;
+
+	iax_mutex_lock(session_mutex); 
+	cur = sessions;
+	while(cur) {
+		if (callno == cur->callno && callno != 0)  {
+			iax_mutex_unlock(session_mutex); 
+			return cur;
+		}
+		cur = cur->next;
+	}
+	iax_mutex_unlock(session_mutex); 
+
+	return NULL;
+}
+
+static int iax_handle_txready(struct iax_session *s)
+{
+	struct iax_session *s0, *s1;
+	short	s0_org_peer, s1_org_peer;
+
+	if (s->transfer_moh) {
+		s->transfer_moh = 0;
+		iax_unquelch(s);
+	}
+
+	complete_transfer(s, s->peercallno, 0, 1);
+
+	s->transferring = TRANSFER_REL;
+
+	s0 = s;
+	s1 = iax_find_session2(s0->transferpeer);
+
+	if (s1 != NULL &&
+	    s1->callno == s0->transferpeer &&
+		 s0->transferring == TRANSFER_REL &&
+		 s1->transferring == TRANSFER_REL) {
+
+		s0_org_peer = s0->peercallno;
+		s1_org_peer = s1->peercallno;
+
+		iax_finish_transfer(s0, s1_org_peer);
+		iax_finish_transfer(s1, s0_org_peer);
+		return 1;
+	}
+
+	return 0;
+}
+
+static void iax_handle_txreject(struct iax_session *s)
+{
+	struct iax_session *s0, *s1;
+
+	s0 = s;
+	s1 = iax_find_session2(s0->transferpeer);
+	if (s1 != NULL &&
+		 s0->transferpeer == s1->callno &&
+		 s1->transferring) {
+		if (s1->transfer_moh) {
+			s1->transfer_moh = 0;
+			send_command_immediate(s1, AST_FRAME_IAX, IAX_COMMAND_UNQUELCH, 0, NULL, 0, s1->iseqno);
+		}
+	}
+	if (s0->transfer_moh) {
+		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)
+{
+	struct iax_session *cur, *prev=NULL;
+	struct iax_sched *curs, *prevs=NULL, *nexts=NULL;
+	int    loop_cnt=0;
+
+	iax_mutex_lock(sched_mutex);
+	curs = schedq;
+	while(curs) {
+		nexts = curs->next;
+		if (curs->frame && curs->frame->session == session) {
+			/* Just mark these frames as if they've been sent */
+			curs->frame->retries = -1;
+		} else if (curs->event && curs->event->session == session) {
+			if (prevs)
+				prevs->next = nexts;
+			else
+				schedq = nexts;
+			if (curs->event)
+				iax_event_free(curs->event);
+			free(curs);
+		} else {
+			prevs = curs;
+		}
+		curs = nexts;
+		loop_cnt++;
+	}
+	iax_mutex_unlock(sched_mutex);
+	
+
+	cur = sessions;
+	while(cur) {
+		if (cur == session) {
+			if (prev)
+				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;
+		}
+		prev = cur;
+		cur = cur->next;
+	}
+}
+
+static int iax_send_lagrp(struct iax_session *session, time_in_ms_t ts);
+static int iax_send_pong(struct iax_session *session, time_in_ms_t ts);
+
+static struct iax_event *handle_event(struct iax_event *event)
+{
+	/* We have a candidate event to be delievered.  Be sure
+	   the session still exists. */
+	if (event) {
+		if (iax_session_valid(event->session)) {
+			/* 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:
+				return event;
+			case IAX_EVENT_LAGRQ:
+				event->etype = IAX_EVENT_LAGRP;
+				iax_send_lagrp(event->session, event->ts);
+				iax_event_free(event);
+				break;
+			case IAX_EVENT_PING:
+				event->etype = IAX_EVENT_PONG;
+				iax_send_pong(event->session, event->ts);
+				iax_event_free(event);
+				break;
+			case IAX_EVENT_POKE:
+				event->etype = IAX_EVENT_PONG;
+				iax_send_pong(event->session, event->ts);
+				iax_destroy(event->session);
+				iax_event_free(event);
+				break;         
+			default:
+				return event;
+			}
+		} else 
+			iax_event_free(event);
+	}
+	return NULL;
+}
+
+static int iax2_vnak(struct iax_session *session)
+{
+	return send_command_immediate(session, AST_FRAME_IAX, IAX_COMMAND_VNAK, 0, NULL, 0, session->iseqno);
+}
+
+int iax_send_dtmf(struct iax_session *session, char digit)
+{
+	return send_command(session, AST_FRAME_DTMF, digit, 0, NULL, 0, -1);
+}
+
+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)
+		return send_command_samples(session, AST_FRAME_VOICE, format, 0, data, datalen, -1, samples);
+	return 0;
+}
+
+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, unsigned char *data, int datalen)
+{
+	/* Send an image frame */
+	return send_command(session, AST_FRAME_IMAGE, format, 0, data, datalen, -1);
+}
+
+int iax_register(struct iax_session *session, char *server, char *peer, char *secret, int refresh)
+{
+	/* Send a registration request */
+	char tmp[256];
+	char *p;
+	int res;
+	int portno = IAX_DEFAULT_PORTNO;
+	struct iax_ie_data ied;
+	struct hostent *hp;
+	
+	tmp[255] = '\0';
+	strncpy(tmp, server, sizeof(tmp) - 1);
+	p = strchr(tmp, ':');
+	if (p) {
+		*p = '\0';
+		portno = atoi(p+1);
+	}
+	
+	memset(&ied, 0, sizeof(ied));
+	if (secret)
+		strncpy(session->secret, secret, sizeof(session->secret) - 1);
+	else
+		strcpy(session->secret, "");
+
+	/* Connect first */
+	hp = gethostbyname(tmp);
+	if (!hp) {
+		snprintf(iax_errstr, sizeof(iax_errstr), "Invalid hostname: %s", tmp);
+		return -1;
+	}
+	memcpy(&session->peeraddr.sin_addr, hp->h_addr, sizeof(session->peeraddr.sin_addr));
+	session->peeraddr.sin_port = htons(portno);
+	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, (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;
+}
+
+int iax_reject_registration(struct iax_session *session, char *reason)
+{
+	struct iax_ie_data ied;
+	memset(&ied, 0, sizeof(ied));
+	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_REGREJ, 0, ied.buf, ied.pos, -1);
+}
+
+int iax_ack_registration(struct iax_session *session)
+{
+	return send_command_final(session, AST_FRAME_IAX, IAX_COMMAND_REGACK, 0, NULL, 0, -1);
+}
+
+int iax_auth_registration(struct iax_session *session)
+{
+	return send_command_final(session, AST_FRAME_IAX, IAX_COMMAND_REGAUTH, 0, NULL, 0, -1);
+}
+
+int iax_reject(struct iax_session *session, const char *reason)
+{
+	struct iax_ie_data ied;
+	memset(&ied, 0, sizeof(ied));
+	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 ? (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, (unsigned char *) url, (int)strlen(url), -1);
+}
+
+int iax_ring_announce(struct iax_session *session)
+{
+	return send_command(session, AST_FRAME_CONTROL, AST_CONTROL_RINGING, 0, NULL, 0, -1);
+}
+
+int iax_lag_request(struct iax_session *session)
+{
+	return send_command(session, AST_FRAME_IAX, IAX_COMMAND_LAGRQ, 0, NULL, 0, -1);
+}
+
+int iax_busy(struct iax_session *session)
+{
+	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;
+	memset(&ied, 0, sizeof(ied));
+	iax_ie_append_int(&ied, IAX_IE_FORMAT, format);
+	return send_command(session, AST_FRAME_IAX, IAX_COMMAND_ACCEPT, 0, ied.buf, ied.pos, -1);
+}
+
+int iax_answer(struct iax_session *session)
+{
+	return send_command(session, AST_FRAME_CONTROL, AST_CONTROL_ANSWER, 0, NULL, 0, -1);
+}
+
+int iax_load_complete(struct iax_session *session)
+{
+	return send_command(session, AST_FRAME_HTML, AST_HTML_LDCOMPLETE, 0, NULL, 0, -1);
+}
+
+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, (unsigned char *) url, (int)strlen(url), -1);
+}
+
+int iax_send_text(struct iax_session *session, char *text)
+{
+	return send_command(session, AST_FRAME_TEXT, 0, 0, (unsigned char *) text, (int)strlen(text) + 1, -1);
+}
+
+int iax_send_unlink(struct iax_session *session)
+{
+	return send_command(session, AST_FRAME_HTML, AST_HTML_UNLINK, 0, NULL, 0, -1);
+}
+
+int iax_send_link_reject(struct iax_session *session)
+{
+	return send_command(session, AST_FRAME_HTML, AST_HTML_LINKREJECT, 0, NULL, 0, -1);
+}
+
+static int iax_send_pong(struct iax_session *session, time_in_ms_t ts)
+{
+        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, (int)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, (unsigned short)(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, time_in_ms_t ts)
+{
+	return send_command(session, AST_FRAME_IAX, IAX_COMMAND_LAGRP, ts, NULL, 0, -1);
+}
+
+static int iax_send_txcnt(struct iax_session *session)
+{
+	struct iax_ie_data ied;
+	memset(&ied, 0, sizeof(ied));
+	iax_ie_append_int(&ied, IAX_IE_TRANSFERID, session->transferid);
+	return send_command_transfer(session, AST_FRAME_IAX, IAX_COMMAND_TXCNT, 0, ied.buf, ied.pos);
+}
+
+static int iax_send_txrej(struct iax_session *session)
+{
+	struct iax_ie_data ied;
+	memset(&ied, 0, sizeof(ied));
+	iax_ie_append_int(&ied, IAX_IE_TRANSFERID, session->transferid);
+	return send_command_transfer(session, AST_FRAME_IAX, IAX_COMMAND_TXREJ, 0, ied.buf, ied.pos);
+}
+
+static int iax_send_txaccept(struct iax_session *session)
+{
+	struct iax_ie_data ied;
+	memset(&ied, 0, sizeof(ied));
+	iax_ie_append_int(&ied, IAX_IE_TRANSFERID, session->transferid);
+	return send_command_transfer(session, AST_FRAME_IAX, IAX_COMMAND_TXACC, 0, ied.buf, ied.pos);
+}
+
+static int iax_send_txready(struct iax_session *session)
+{
+	struct iax_ie_data ied;
+	memset(&ied, 0, sizeof(ied));
+	/* see asterisk chan_iax2.c */
+	iax_ie_append_short(&ied, IAX_IE_CALLNO, session->callno);
+	return send_command(session, AST_FRAME_IAX, IAX_COMMAND_TXREADY, 0, ied.buf, ied.pos, -1);
+}
+
+int iax_auth_reply(struct iax_session *session, char *password, char *challenge, int methods)
+{
+	char reply[16];
+	struct MD5Context md5;
+	char realreply[256];
+	struct iax_ie_data ied;
+	memset(&ied, 0, sizeof(ied));
+	if ((methods & IAX_AUTH_MD5) && challenge) {
+		MD5Init(&md5);
+		MD5Update(&md5, (const unsigned char *) challenge, (unsigned int)strlen(challenge));
+		MD5Update(&md5, (const unsigned char *) password, (unsigned int)strlen(password));
+		MD5Final((unsigned char *) reply, &md5);
+		memset(realreply, 0, sizeof(realreply));
+		convert_reply(realreply, (unsigned char *) reply);
+		iax_ie_append_str(&ied, IAX_IE_MD5_RESULT, (unsigned char *) realreply);
+	} else {
+		iax_ie_append_str(&ied, IAX_IE_PASSWORD, (unsigned char *) password);
+	}
+	return send_command(session, AST_FRAME_IAX, IAX_COMMAND_AUTHREP, 0, ied.buf, ied.pos, -1);
+}
+
+static int iax_regauth_reply(struct iax_session *session, char *password, char *challenge, int methods)
+{
+	char reply[16];
+	struct MD5Context md5;
+	char realreply[256];
+	struct iax_ie_data ied;
+	memset(&ied, 0, sizeof(ied));
+	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, (unsigned int)strlen(challenge));
+		MD5Update(&md5, (const unsigned char *) password, (unsigned int)strlen(password));
+		MD5Final((unsigned char *) reply, &md5);
+		memset(realreply, 0, sizeof(realreply));
+		convert_reply(realreply, (unsigned char *) reply);
+		iax_ie_append_str(&ied, IAX_IE_MD5_RESULT, (unsigned char *) realreply);
+	} else {
+		iax_ie_append_str(&ied, IAX_IE_PASSWORD, (unsigned char *) password);
+	}
+	return send_command(session, AST_FRAME_IAX, IAX_COMMAND_REGREQ, 0, ied.buf, ied.pos, -1);
+}
+
+
+int iax_dial(struct iax_session *session, char *number)
+{
+	struct iax_ie_data ied;
+	memset(&ied, 0, sizeof(ied));
+	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);
+}
+
+int iax_quelch(struct iax_session *session)
+{
+	return send_command(session, AST_FRAME_IAX, IAX_COMMAND_QUELCH, 0, NULL, 0, -1);
+}
+
+int iax_unquelch(struct iax_session *session)
+{
+	return send_command(session, AST_FRAME_IAX, IAX_COMMAND_UNQUELCH, 0, NULL, 0, -1);
+}
+
+int iax_dialplan_request(struct iax_session *session, char *number)
+{
+	struct iax_ie_data ied;
+	memset(&ied, 0, sizeof(ied));
+	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 ((1 << 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';
+	size_t 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 < 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;
+}
+
+void iax_set_samplerate(struct iax_session *session, unsigned short samplemask)
+{
+	session->samplemask = samplemask;
+}
+
+
+int iax_call(struct iax_session *session, const char *cidnum, const char *cidname, char *ich, char *lang, int wait, int formats, int capabilities)
+{
+	char tmp[256]="";
+	char *part1, *part2;
+	int res;
+	int portno;
+	char *username, *hostname, *secret, *context, *exten, *dnid;
+	struct iax_ie_data ied;
+	struct hostent *hp;
+	/* We start by parsing up the temporary variable which is of the form of:
+	   [user@]peer[:portno][/exten[@context]] */
+	if (!ich) {
+		IAXERROR "Invalid IAX Call Handle\n");
+		DEBU(G "Invalid IAX Call Handle\n");
+		return -1;
+	}
+	memset(&ied, 0, sizeof(ied));
+	strncpy(tmp, ich, sizeof(tmp) - 1);	
+
+	iax_ie_append_short(&ied, IAX_IE_VERSION, IAX_PROTO_VERSION);
+    if (session->samplemask) {
+		iax_ie_append_short(&ied, IAX_IE_SAMPLINGRATE, session->samplemask);
+	}
+	if (cidnum)
+		iax_ie_append_str(&ied, IAX_IE_CALLING_NUMBER, (unsigned char *) cidnum);
+	if (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, (unsigned char *) lang);
+	
+	/* Part 1 is [user[:password]@]peer[:port] */
+	part1 = strtok(tmp, "/");
+
+	/* Part 2 is exten[@context] if it is anything all */
+	part2 = strtok(NULL, "/");
+	
+	if (strchr(part1, '@')) {
+		username = strtok(part1, "@");
+		hostname = strtok(NULL, "@");
+	} else {
+		username = NULL;
+		hostname = part1;
+	}
+	
+	if (username && strchr(username, ':')) {
+		username = strtok(username, ":");
+		secret = strtok(NULL, ":");
+	} else
+		secret = NULL;
+
+	if(username)
+	  strncpy(session->username, username, sizeof(session->username) - 1);
+
+	if(secret)
+	  strncpy(session->secret, secret, sizeof(session->secret) - 1);
+	
+	if (strchr(hostname, ':')) {
+		strtok(hostname, ":");
+		portno = atoi(strtok(NULL, ":"));
+	} else {
+		portno = IAX_DEFAULT_PORTNO;
+	}
+	if (part2) {
+		exten = strtok(part2, "@");
+		dnid = exten;
+		context = strtok(NULL, "@");
+	} else {
+		exten = NULL;
+		dnid = NULL;
+		context = NULL;
+	}
+	if (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, (unsigned char *) exten);
+	if (dnid && strlen(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, (unsigned char *) context);
+
+	/* Setup host connection */
+	hp = gethostbyname(hostname);
+	if (!hp) {
+		snprintf(iax_errstr, sizeof(iax_errstr), "Invalid hostname: %s", hostname);
+		return -1;
+	}
+	memcpy(&session->peeraddr.sin_addr, hp->h_addr, sizeof(session->peeraddr.sin_addr));
+	session->peeraddr.sin_port = htons(portno);
+	session->peeraddr.sin_family = AF_INET;
+	res = send_command(session, AST_FRAME_IAX, IAX_COMMAND_NEW, 0, ied.buf, ied.pos, -1);
+	if (res < 0)
+		return res;
+	if (wait) {
+		DEBU(G "Waiting not yet implemented\n");
+		return -1;
+	}
+	return res;
+}
+
+static time_in_ms_t calc_rxstamp(struct iax_session *session)
+{
+	time_in_ms_t time_in_ms;
+
+	time_in_ms = current_time_in_ms();
+
+	if (!session->rxcore) {
+		session->rxcore = time_in_ms;
+	}
+
+	return time_in_ms - session->rxcore;
+}
+
+#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) &&
+		(cur->peeraddr.sin_port == sin->sin_port)) {
+		/* This is the main host */
+		if ((cur->peercallno == callno) || 
+			((dcallno == cur->callno) && !cur->peercallno)) {
+			/* That's us.  Be sure we keep track of the peer call number */
+			cur->peercallno = callno;
+			return 1;
+		}
+	}
+	if ((cur->transfer.sin_addr.s_addr == sin->sin_addr.s_addr) &&
+	    (cur->transfer.sin_port == sin->sin_port) && (cur->transferring)) {
+		/* We're transferring */
+		if (dcallno == cur->callno)
+			return 1;
+	}
+	return 0;
+}
+#endif
+
+/* splitted match into 2 passes otherwise causing problem of matching
+   up the wrong session using the dcallno and the peercallno because
+   during a transfer (2 IAX channels on the same client/system) the
+   same peercallno (from two different asterisks) exist in more than
+	one session.
+ */
+static int forward_match(struct sockaddr_in *sin, short callno, short dcallno, struct iax_session *cur)
+{
+	if ((cur->transfer.sin_addr.s_addr == sin->sin_addr.s_addr) &&
+		(cur->transfer.sin_port == sin->sin_port) && (cur->transferring)) {
+		/* We're transferring */
+		if (dcallno == cur->callno)
+		{
+			return 1;
+		}
+	}
+
+	if ((cur->peeraddr.sin_addr.s_addr == sin->sin_addr.s_addr) &&
+		(cur->peeraddr.sin_port == sin->sin_port)) {
+		if (dcallno == cur->callno && dcallno != 0)  {
+					/* That's us.  Be sure we keep track of the peer call number */
+			if (cur->peercallno == 0) {
+				cur->peercallno = callno;
+			}
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static int reverse_match(struct sockaddr_in *sin, short callno, struct iax_session *cur)
+{
+	if ((cur->transfer.sin_addr.s_addr == sin->sin_addr.s_addr) &&
+		(cur->transfer.sin_port == sin->sin_port) && (cur->transferring)) {
+		/* We're transferring */
+		if (callno == cur->peercallno)  {
+			return 1;
+		}
+	}
+	if ((cur->peeraddr.sin_addr.s_addr == sin->sin_addr.s_addr) &&
+		(cur->peeraddr.sin_port == sin->sin_port)) {
+		if (callno == cur->peercallno)  {
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static struct iax_session *iax_find_session(struct sockaddr_in *sin, 
+											short callno, 
+											short dcallno,
+											int makenew)
+{
+	struct iax_session *cur;
+
+	iax_mutex_lock(session_mutex); 
+	cur = sessions;
+	while(cur) {
+		if (forward_match(sin, callno, dcallno, cur)) {
+			iax_mutex_unlock(session_mutex); 
+			return cur;
+		}
+		cur = cur->next;
+	}
+
+	cur = sessions;
+	while(cur) {
+		if (reverse_match(sin, callno, cur)) {
+			iax_mutex_unlock(session_mutex); 
+			return cur;
+		}
+		cur = cur->next;
+	}
+
+	iax_mutex_unlock(session_mutex); 
+
+	if (makenew && !dcallno) {
+		cur = iax_session_new();
+		cur->peercallno = callno;
+		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);
+	}
+
+	return cur;	
+}
+
+#ifdef EXTREME_DEBUG
+static int display_time(int ms)
+{
+	static int oldms = -1;
+	if (oldms < 0) {
+		DEBU(G "First measure\n");
+		oldms = ms;
+		return 0;
+	}
+	DEBU(G "Time from last frame is %d ms\n", ms - oldms);
+	oldms = ms;
+	return 0;
+}
+#endif
+
+#define FUDGE 1
+
+#ifdef NEWJB
+/* From chan_iax2/steve davies:  need to get permission from steve or digium, I guess */
+static time_in_ms_t unwrap_timestamp(time_in_ms_t ts, time_in_ms_t last)
+{
+        time_in_ms_t 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, time_in_ms_t ts, int updatehistory)
+{
+	/* 
+	 * This is the core of the IAX jitterbuffer delivery mechanism: 
+	 * Dynamically adjust the jitterbuffer and decide how time_in_ms_t 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);
+#endif
+	
+#ifdef VOICE_SMOOTHING
+	if (e->etype == IAX_EVENT_VOICE) {
+		/* Smooth voices if we know enough about the format */
+		switch(e->event.voice.format) {
+		case AST_FORMAT_GSM:
+			/* GSM frames are 20 ms long, although there could be periods of 
+			   silence.  If the time is < 50 ms, assume it ought to be 20 ms */
+			if (ts - e->session->lastts < 50)  
+				ts = e->session->lastts + 20;
+#ifdef EXTREME_DEBUG
+			display_time(ts);
+#endif
+			break;
+		default:
+			/* Can't do anything */
+		}
+		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 */
+	ms = (int)(calc_rxstamp(e->session) - ts);
+
+	/*  
+	   Drop voice frame if timestamp is way off 
+	   if ((e->etype == IAX_EVENT_VOICE) && ((ms > 65536) || (ms < -65536))) {
+	   DEBU(G "Dropping a voice packet with odd ts (ts = %d; ms = %d)\n", ts, ms);
+	   free(e);
+	   return NULL;
+	   }
+	*/
+
+	/* Adjust if voice frame timestamp is off by a step */
+	if (ms > 32768) {
+		/* What likely happened here is that our counter 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. */
+		ms -= 65536;
+	}
+	if (ms < -32768) {
+		/* We got this packet out of order.  Lets add 65536 to it to bring it into our new
+		   time frame */
+		ms += 65536;
+	}
+
+#if 0	
+	printf("rxstamp is %d, timestamp is %d, ms is %d\n", calc_rxstamp(e->session), ts, ms);
+#endif
+	/* Rotate history queue.  Leading 0's are irrelevant. */
+	if (updatehistory) {
+	    for (x=0; x < MEMORY_SIZE - 1; x++) 
+		    e->session->history[x] = e->session->history[x+1];
+	    
+	    /* Add new entry for this time */
+	    e->session->history[x] = ms;
+	}
+	
+	/* We have to find the maximum and minimum time delay we've had to deliver. */
+	min = e->session->history[0];
+	for (z=0;z < iax_dropcount + 1; z++) {
+		/* We drop the top iax_dropcount entries.  iax_dropcount represents
+		   a tradeoff between quality of voice and latency.  3% drop seems to
+		   be unnoticable to the client and can significantly improve latency.  
+		   We add one more to our droplist, but that's the one we actually use, 
+		   and don't drop.  */
+		max = -99999999;
+		for (x=0;x<MEMORY_SIZE;x++) {
+			if (max < e->session->history[x]) {
+				/* New candidate value.  Make sure we haven't dropped it. */
+				match=0;
+				for(y=0;!match && (y<z); y++) 
+					match |= (drops[y] == x);
+				/* If there is no match, this is our new maximum */
+				if (!match) {
+					max = e->session->history[x];
+					maxone = x;
+				}
+			}
+			if (!z) {
+				/* First pass, calcualte our minimum, too */
+				if (min > e->session->history[x])
+					min = e->session->history[x];
+			}
+		}
+		drops[z] = maxone;
+	}
+	/* Again, just for reference.  The "jitter buffer" is the max.  The difference
+	   is the perceived jitter correction. */
+	e->session->jitter = max - min;
+	
+	/* If the jitter buffer is substantially too large, shrink it, slowly enough
+	   that the client won't notice ;-) . */
+	if (max < e->session->jitterbuffer - max_extra_jitterbuffer) {
+#ifdef EXTREME_DEBUG
+		DEBU(G "Shrinking jitterbuffer (target = %d, current = %d...\n", max, e->session->jitterbuffer);
+#endif
+		e->session->jitterbuffer -= 1;
+	}
+		
+	/* Keep the jitter buffer from becoming unreasonably large */
+	if (max > min + max_jitterbuffer) {
+		DEBU(G "Constraining jitter buffer (min = %d, max = %d)...\n", min, max);
+		max = min + max_jitterbuffer;
+	}
+	
+	/* If the jitter buffer is too small, we immediately grow our buffer to
+	   accomodate */
+	if (max > e->session->jitterbuffer)
+		e->session->jitterbuffer = max;
+	
+	/* Start with our jitter buffer delay, and subtract the lateness (or earliness).
+	   Remember these times are all relative to the first packet, so their absolute
+	   values are really irrelevant. */
+	ms = e->session->jitterbuffer - ms - IAX_SCHEDULE_FUZZ;
+	
+	/* If the jitterbuffer is disabled, always deliver immediately */
+	if (!iax_use_jitterbuffer)
+		ms = 0;
+	
+	if (ms < 1) {
+#ifdef EXTREME_DEBUG
+		DEBU(G "Calculated delay is only %d\n", ms);
+#endif
+		if ((ms > -4) || (e->etype != IAX_EVENT_VOICE)) {
+			/* Return the event immediately if it's it's less than 3 milliseconds
+			   too late, or if it's not voice (believe me, you don't want to
+			   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_add(e, NULL, NULL, NULL, 0);
+			return NULL;
+			//return e;
+		}
+		DEBU(G "(not so) Silently dropping a packet (ms = %d)\n", ms);
+		/* Silently discard this as if it were to be delivered */
+		free(e);
+		return NULL;
+	}
+	/* We need this to be delivered in the future, so we use our scheduler */
+	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;
+	
+}
+
+static int uncompress_subclass(unsigned char csub)
+{
+	/* If the SC_LOG flag is set, return 2^csub otherwise csub */
+	if (csub & IAX_FLAG_SC_LOG)
+		return 1 << (csub & ~IAX_FLAG_SC_LOG & IAX_MAX_SHIFT);
+	else
+		return csub;
+}
+
+static inline char *extract(char *src, char *string)
+{
+	/* Extract and duplicate what we need from a string */
+	char *s, *t;
+	s = strstr(src, string);
+	if (s) {
+		s += strlen(string);
+		s = strdup(s);
+		/* End at ; */
+		t = strchr(s, ';');
+		if (t) {
+			*t = '\0';
+		}
+	}
+	return s;
+		
+}
+
+static struct iax_event *iax_header_to_event(struct iax_session *session,
+											 struct ast_iax2_full_hdr *fh,
+											 int datalen, struct sockaddr_in *sin)
+{
+	struct iax_event *e;
+	struct iax_sched *sch;
+	unsigned int ts;
+	int subclass = uncompress_subclass(fh->csub);
+	time_in_ms_t nowts;
+	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 &&
+	    (fh->type == AST_FRAME_IAX && 
+	     subclass != IAX_COMMAND_ACK &&
+	     subclass != IAX_COMMAND_PONG &&
+	     subclass != IAX_COMMAND_LAGRP)) {
+	    session->last_ts = ts;
+	}
+
+
+#ifdef DEBUG_SUPPORT
+	iax_showframe(NULL, fh, 1, sin, datalen);
+#endif
+
+	/* Get things going with it, timestamp wise, if we
+	   haven't already. */
+
+		/* Handle implicit ACKing unless this is an INVAL, and only if this is 
+		   from the real peer, not the transfer peer */
+		if (!inaddrcmp(sin, &session->peeraddr) && 
+			(((subclass != IAX_COMMAND_INVAL)) ||
+			(fh->type != AST_FRAME_IAX))) {
+			unsigned char x;
+			/* XXX This code is not very efficient.  Surely there is a better way which still
+			       properly handles boundary conditions? XXX */
+			/* First we have to qualify that the ACKed value is within our window */
+			for (x=session->rseqno; x != session->oseqno; x++)
+				if (fh->iseqno == x)
+					break;
+			if ((x != session->oseqno) || (session->oseqno == fh->iseqno)) {
+				/* The acknowledgement is within our window.  Time to acknowledge everything
+				   that it says to */
+				for (x=session->rseqno; x != fh->iseqno; x++) {
+					/* Ack the packet with the given timestamp */
+					DEBU(G "Cancelling transmission of packet %d\n", x);
+					iax_mutex_lock(sched_mutex);
+					sch = schedq;
+					while(sch) {
+						if (sch->frame && (sch->frame->session == session) && 
+						    (sch->frame->oseqno == x)) 
+							sch->frame->retries = -1;
+						sch = sch->next;
+					}
+					iax_mutex_unlock(sched_mutex);
+				}
+				/* Note how much we've received acknowledgement for */
+				session->rseqno = fh->iseqno;
+			} else
+				DEBU(G "Received iseqno %d not within window %d->%d\n", fh->iseqno, session->rseqno, session->oseqno);
+		}
+
+	/* Check where we are */
+		if ((ntohs(fh->dcallno) & IAX_FLAG_RETRANS) || (fh->type != AST_FRAME_VOICE))
+			updatehistory = 0;
+		if ((session->iseqno != fh->oseqno) &&
+			(session->iseqno ||
+			   ((subclass != IAX_COMMAND_TXREADY) &&
+			    (subclass != IAX_COMMAND_TXREL) &&
+				(subclass != IAX_COMMAND_TXCNT) &&
+				(subclass != IAX_COMMAND_TXACC)) ||
+			  (fh->type != AST_FRAME_IAX))) {
+			if (
+			 ((subclass != IAX_COMMAND_ACK) &&
+			  (subclass != IAX_COMMAND_INVAL) &&
+			  (subclass != IAX_COMMAND_TXREADY) &&
+			  (subclass != IAX_COMMAND_TXREL) &&
+			  (subclass != IAX_COMMAND_TXCNT) &&
+			  (subclass != IAX_COMMAND_TXACC) &&
+			  (subclass != IAX_COMMAND_VNAK)) ||
+			  (fh->type != AST_FRAME_IAX)) {
+			 	/* If it's not an ACK packet, it's out of order. */
+				DEBU(G "Packet arrived out of order (expecting %d, got %d) (frametype = %d, subclass = %d)\n", 
+					session->iseqno, fh->oseqno, fh->type, subclass);
+				if (session->iseqno > fh->oseqno) {
+					/* If we've already seen it, ack it XXX There's a border condition here XXX */
+					if ((fh->type != AST_FRAME_IAX) || 
+							((subclass != IAX_COMMAND_ACK) && (subclass != IAX_COMMAND_INVAL))) {
+						DEBU(G "Acking anyway\n");
+						/* XXX Maybe we should handle its ack to us, but then again, it's probably outdated anyway, and if
+						   we have anything to send, we'll retransmit and get an ACK back anyway XXX */
+						send_command_immediate(session, AST_FRAME_IAX, IAX_COMMAND_ACK, ts, NULL, 0,fh->iseqno);
+					}
+				} else {
+					/* Send a VNAK requesting retransmission */
+					iax2_vnak(session);
+				}
+				return NULL;
+			}
+		} else {
+			/* Increment unless it's an ACK or VNAK */
+			if (((subclass != IAX_COMMAND_ACK) &&
+			    (subclass != IAX_COMMAND_INVAL) &&
+			    (subclass != IAX_COMMAND_TXCNT) &&
+			    (subclass != IAX_COMMAND_TXACC) &&
+				(subclass != IAX_COMMAND_VNAK)) ||
+			    (fh->type != AST_FRAME_IAX))
+				session->iseqno++;
+		}
+			
+	e = (struct iax_event *)malloc(sizeof(struct iax_event) + datalen + 1);
+
+	if (e) {
+		memset(e, 0, sizeof(struct iax_event) + datalen);
+		/* Set etype to some unknown value so do not inavertently
+		   sending IAX_EVENT_CONNECT event, which is 0 to application.
+		 */
+		e->etype = -1;
+		e->session = session;
+		switch(fh->type) {
+		case AST_FRAME_DTMF:
+			e->etype = IAX_EVENT_DTMF;
+			e->subclass = subclass;
+			/* 
+			 We want the DTMF event deliver immediately so all I/O can be
+			 terminate quickly in an IVR system.
+			e = schedule_delivery(e, ts, updatehistory); */
+			break;
+		case AST_FRAME_VOICE:
+			e->etype = IAX_EVENT_VOICE;
+			e->subclass = subclass;
+			session->voiceformat = subclass;
+			if (datalen) {
+				memcpy(e->data, fh->iedata, datalen);
+				e->datalen = datalen;
+			}
+			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) {
+				memcpy(e->data, fh->iedata, datalen);
+				e->datalen = datalen;
+			}
+			if (iax_parse_ies(&e->ies, e->data, e->datalen)) {
+				IAXERROR "Unable to parse IE's");
+				free(e);
+				e = NULL;
+				break;
+			}
+			switch(subclass) {
+			case IAX_COMMAND_NEW:
+				/* 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 = (int)strlen(session->codec_order);
+				}
+				e->etype = IAX_EVENT_CONNECT;
+				e = schedule_delivery(e, ts, updatehistory);
+				break;
+			case IAX_COMMAND_AUTHREQ:
+				/* This is a request for a call */
+				e->etype = IAX_EVENT_AUTHRQ;
+				if (strlen(session->username) && !strcmp(e->ies.username, session->username) &&
+					strlen(session->secret)) {
+						/* Hey, we already know this one */
+						iax_auth_reply(session, session->secret, e->ies.challenge, e->ies.authmethods);
+						free(e);
+						e = NULL;
+						break;
+				}
+				e = schedule_delivery(e, ts, updatehistory);
+				break;
+			case IAX_COMMAND_HANGUP:
+				e->etype = IAX_EVENT_HANGUP;
+				e = schedule_delivery(e, ts, updatehistory);
+				break;
+			case IAX_COMMAND_INVAL:
+				e->etype = IAX_EVENT_HANGUP;
+				e = schedule_delivery(e, ts, updatehistory);
+				break;
+			case IAX_COMMAND_REJECT:
+				e->etype = IAX_EVENT_REJECT;
+				e = schedule_delivery(e, ts, updatehistory);
+				break;
+			case IAX_COMMAND_ACK:
+				free(e);
+				e = NULL;
+				break;
+			case IAX_COMMAND_LAGRQ:
+				/* Pass this atime_in_ms_t for later handling */
+				e->etype = IAX_EVENT_LAGRQ;
+				e->ts = ts;
+				e = schedule_delivery(e, ts, updatehistory);
+				break;
+			case IAX_COMMAND_POKE:
+				e->etype = IAX_EVENT_POKE;
+				e->ts = ts;
+				break;
+			case IAX_COMMAND_PING:
+				/* 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) {
+					e->etype = IAX_EVENT_ACCEPT;
+				}
+				else {
+					struct iax_ie_data ied;
+					/* Although this should not happen, we added this to make sure
+					   the negotiation protocol is enforced.
+						For lack of event to notify the application we use the defined
+						REJECT event.
+					 */
+					memset(&ied, 0, sizeof(ied));
+					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;
+				}
+				e = schedule_delivery(e, ts, updatehistory);
+				break;
+			case IAX_COMMAND_REGREQ:
+				e->etype = IAX_EVENT_REGREQ;
+				e = schedule_delivery(e, ts, updatehistory);
+				break;
+			case IAX_COMMAND_REGREL:
+				e->etype = IAX_EVENT_REGREQ;
+				e = schedule_delivery(e, ts, updatehistory);
+				break;
+			case IAX_COMMAND_REGACK:
+				e->etype = IAX_EVENT_REGACK;
+				e = schedule_delivery(e, ts, updatehistory);
+				break;
+			case IAX_COMMAND_REGAUTH:
+				iax_regauth_reply(session, session->secret, e->ies.challenge, e->ies.authmethods);
+				free(e);
+				e = NULL;
+				break;
+			case IAX_COMMAND_REGREJ:
+				e->etype = IAX_EVENT_REGREJ;
+				e = schedule_delivery(e, ts, updatehistory);
+				break;
+			case IAX_COMMAND_LAGRP:
+				e->etype = IAX_EVENT_LAGRP;
+				nowts = calc_timestamp(session, 0, NULL);
+				e->ts = nowts - ts;
+				e->subclass = session->jitter;
+				/* Can't call schedule_delivery since timestamp is non-normal */
+				break;;
+			case IAX_COMMAND_TXREQ:
+				/* added check for defensive programming
+				 * - in case the asterisk server
+				 * or another client does not send the
+				 *  apparent transfer address
+				 */
+				if (e->ies.apparent_addr != NULL) {
+				    /* so a full voice frame is sent on the 
+				       next voice output */
+				    session->svoiceformat = -1;	
+				    session->transfer = *e->ies.apparent_addr;
+				    session->transfer.sin_family = AF_INET;
+				    session->transfercallno = e->ies.callno;
+				    session->transferring = TRANSFER_BEGIN;
+				    session->transferid = e->ies.transferid;
+				    iax_send_txcnt(session);
+				}
+				free(e);
+				e = NULL;
+				break;
+			case IAX_COMMAND_DPREP:
+				/* Received dialplan reply */
+				e->etype = IAX_EVENT_DPREP;
+				/* Return immediately, makes no sense to schedule */
+				break;
+			case IAX_COMMAND_TXCNT:
+				if (session->transferring)  {
+					session->transfer = *sin;
+					iax_send_txaccept(session);
+				}
+				free(e);
+				e = NULL;
+				break;
+			case IAX_COMMAND_TXACC:
+				if (session->transferring) {
+					stop_transfer(session);
+					session->transferring = TRANSFER_READY;
+					iax_send_txready(session);
+				}
+				free(e);
+				e = NULL;
+				break;
+			case IAX_COMMAND_TXREL:
+				/* Release the transfer */
+			   send_command_immediate(session, AST_FRAME_IAX, IAX_COMMAND_ACK, fh->ts, NULL, 0, fh->iseqno);
+				if (session->transferring) {
+					complete_transfer(session, e->ies.callno, 1, 0);
+				}
+				else {
+					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;
+				session->quelch = 1;
+				break;
+			case IAX_COMMAND_UNQUELCH:
+				e->etype = IAX_EVENT_UNQUELCH;
+				session->quelch = 0;
+				break;
+			case IAX_COMMAND_TXREJ:
+				e->etype = IAX_EVENT_TXREJECT;
+				iax_handle_txreject(session);
+				break;
+
+			case IAX_COMMAND_TXREADY:
+				send_command_immediate(session, AST_FRAME_IAX, IAX_COMMAND_ACK, ts, NULL, 0, fh->iseqno);
+				if (iax_handle_txready(session)) {
+					e->etype = IAX_EVENT_TXREADY;
+				}
+				else {
+					free(e);
+					e = NULL;
+				}
+				break;
+			default:
+				DEBU(G "Don't know what to do with IAX command %d\n", subclass);
+				free(e);
+				e = NULL;
+			}
+			break;
+		case AST_FRAME_CONTROL:
+			switch(subclass) {
+			case AST_CONTROL_ANSWER:
+				e->etype = IAX_EVENT_ANSWER;
+				e = schedule_delivery(e, ts, updatehistory);
+				break;
+			case AST_CONTROL_CONGESTION:
+			case AST_CONTROL_BUSY:
+				e->etype = IAX_EVENT_BUSY;
+				e = schedule_delivery(e, ts, updatehistory);
+				break;
+			case AST_CONTROL_RINGING:
+				e->etype = IAX_EVENT_RINGA;
+				e = schedule_delivery(e, ts, updatehistory);
+				break;
+			default:
+				DEBU(G "Don't know what to do with AST control %d\n", subclass);
+				free(e);
+				return NULL;
+			}
+			break;
+		case AST_FRAME_IMAGE:
+			e->etype = IAX_EVENT_IMAGE;
+			e->subclass = subclass;
+			if (datalen) {
+				memcpy(e->data, fh->iedata, datalen);
+			}
+			e = schedule_delivery(e, ts, updatehistory);
+			break;
+
+		case AST_FRAME_TEXT:
+			e->etype = IAX_EVENT_TEXT;
+			if (datalen) {
+				memcpy(e->data, fh->iedata, datalen);
+			}
+			e = schedule_delivery(e, ts, updatehistory);
+			break;
+
+		case AST_FRAME_HTML:
+			switch(fh->csub) {
+			case AST_HTML_LINKURL:
+				e->etype = IAX_EVENT_LINKURL;
+				/* Fall through */
+			case AST_HTML_URL:
+				if (e->etype == -1)
+					e->etype = IAX_EVENT_URL;
+				e->subclass = fh->csub;
+				e->datalen = datalen;
+				if (datalen) {
+					memcpy(e->data, fh->iedata, datalen);
+				}
+				e = schedule_delivery(e, ts, updatehistory);
+				break;
+			case AST_HTML_LDCOMPLETE:
+				e->etype = IAX_EVENT_LDCOMPLETE;
+				e = schedule_delivery(e, ts, updatehistory);
+				break;
+			case AST_HTML_UNLINK:
+				e->etype = IAX_EVENT_UNLINK;
+				e = schedule_delivery(e, ts, updatehistory);
+				break;
+			case AST_HTML_LINKREJECT:
+				e->etype = IAX_EVENT_LINKREJECT;
+				e = schedule_delivery(e, ts, updatehistory);
+				break;
+			default:
+				DEBU(G "Don't know how to handle HTML type %d frames\n", fh->csub);
+				free(e);
+				return NULL;
+			}
+			break;
+		default:
+			DEBU(G "Don't know what to do with frame type %d\n", fh->type);
+			free(e);
+			return NULL;
+		}
+	} else
+		DEBU(G "Out of memory\n");
+	    
+	/* Already ack'd iax frames */
+	if (session->aseqno != session->iseqno) {
+	    send_command_immediate(session, AST_FRAME_IAX, IAX_COMMAND_ACK, ts, NULL, 0, fh->iseqno);
+	}
+	return e;
+}
+
+static struct iax_event *iax_miniheader_to_event(struct iax_session *session,
+						struct ast_iax2_mini_hdr *mh,
+						int datalen)
+{
+	struct iax_event *e;
+	time_in_ms_t ts;
+	int updatehistory = 1;
+	e = (struct iax_event *)malloc(sizeof(struct iax_event) + datalen);
+	if (e) {
+		if (session->voiceformat > 0) {
+			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);
+			}
+			ts = (session->last_ts & 0xFFFF0000) | ntohs(mh->ts);
+			return schedule_delivery(e, ts, updatehistory);
+		} else {
+			DEBU(G "No last format received on session %d\n", session->callno);
+			free(e);
+			e = NULL;
+		}
+	} else
+		DEBU(G "Out of memory\n");
+	return e;
+}
+
+void iax_destroy(struct iax_session *session)
+{
+	iax_mutex_lock(session_mutex); 
+	destroy_session(session);
+	iax_mutex_unlock(session_mutex); 
+}
+
+static struct iax_event *iax_net_read(void)
+{
+	unsigned char buf[65536];
+	int res, sinlen;
+	struct sockaddr_in sin;
+
+	sinlen = sizeof(sin);
+	res = iax_recvfrom(netfd, buf, sizeof(buf), 0, (struct sockaddr *) &sin, &sinlen);
+
+	if (res < 0) {
+#ifdef	WIN32
+		if (WSAGetLastError() != WSAEWOULDBLOCK) {
+			DEBU(G "Error on read: %d\n", WSAGetLastError());
+			IAXERROR "Read error on network socket: %s", strerror(errno));
+		}
+#else
+		if (errno != EAGAIN) {
+			DEBU(G "Error on read: %s\n", strerror(errno));
+			IAXERROR "Read error on network socket: %s", strerror(errno));
+		}
+#endif
+		return NULL;
+	}
+	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 */
+	}
+	iax_mutex_lock(session_mutex); 
+	for( cur=sessions; cur; cur=cur->next ) {
+		if ((cur->transferring) && (cur->transferid == 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;		
+		}
+	}
+	iax_mutex_unlock(session_mutex); 
+	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;
+	struct ast_iax2_mini_hdr *mh = (struct ast_iax2_mini_hdr *)buf;
+	struct iax_session *session;
+	
+	if (ntohs(fh->scallno) & IAX_FLAG_FULL) {
+		int subclass = uncompress_subclass(fh->csub);
+		int makenew = 0;
+
+		/* Full size header */
+		if (len < sizeof(struct ast_iax2_full_hdr)) {
+			DEBU(G "Short header received from %s\n", inet_ntoa(sin->sin_addr));
+			IAXERROR "Short header received from %s\n", inet_ntoa(sin->sin_addr));
+			return NULL;
+		}
+		/* Only allow it to make new sessions on types where that makes sense */
+		if ((fh->type == AST_FRAME_IAX) && ((subclass == IAX_COMMAND_NEW) ||
+											(subclass == IAX_COMMAND_POKE) ||
+											(subclass == IAX_COMMAND_REGREL) ||
+											(subclass == IAX_COMMAND_REGREQ))) {
+			makenew = 1;
+		}
+
+		/* We have a full header, process appropriately */
+		session = iax_find_session(sin, ntohs(fh->scallno) & ~IAX_FLAG_FULL, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS, makenew);
+		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);
+		/* if we get here, the frame was invalid for some reason, we should probably send IAX_COMMAND_INVAL (as long as the subclass was not already IAX_COMMAND_INVAL) */
+		DEBU(G "No session?\n");
+		return NULL;
+	} else {
+		if (len < sizeof(struct ast_iax2_mini_hdr)) {
+			DEBU(G "Short header received from %s\n", inet_ntoa(sin->sin_addr));
+			IAXERROR "Short header received from %s\n", inet_ntoa(sin->sin_addr));
+			return NULL;
+		}
+		/* Miniature, voice frame */
+		session = iax_find_session(sin, ntohs(fh->scallno), 0, 0);
+		if (session)
+			return iax_miniheader_to_event(session, mh, len - sizeof(struct ast_iax2_mini_hdr));
+		DEBU(G "No session?\n");
+		return NULL;
+	}
+}
+
+static struct iax_sched *iax_get_sched(time_in_ms_t time_in_ms)
+{
+	struct iax_sched *cur, *prev=NULL;
+	iax_mutex_lock(sched_mutex);
+	cur = schedq;
+	/* Check the event schedule first. */
+	while(cur) {
+		if (time_in_ms > cur->when) {
+			/* Take it out of the event queue */
+			if (prev) {
+				prev->next = cur->next;
+			} else {
+				schedq = cur->next;
+			}
+			iax_mutex_unlock(sched_mutex);
+			return cur;
+		}
+		cur = cur->next;
+	}
+	iax_mutex_unlock(sched_mutex);
+	return NULL;
+}
+
+struct iax_event *iax_get_event(int blocking)
+{
+	struct iax_event *event;
+	struct iax_frame *frame;
+	time_in_ms_t time_in_ms;
+	struct iax_sched *cur;
+	
+	if (do_shutdown) {
+		__iax_shutdown();
+		do_shutdown = 0;
+		return NULL;
+	}
+	time_in_ms = current_time_in_ms();
+	while((cur = iax_get_sched(time_in_ms))) {
+
+		event = cur->event;
+		frame = cur->frame;
+		if (event) {
+
+			/* See if this is an event we need to handle */
+			event = handle_event(event);
+			if (event) {
+				free(cur);
+				return event;
+			}
+		} 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. If final, destroy the session. */
+				if (frame->final) {
+					iax_mutex_lock(session_mutex); 
+					destroy_session(frame->session);
+					iax_mutex_unlock(session_mutex); 
+				}
+				if (frame->data)
+					free(frame->data);
+				free(frame);
+			} else if (frame->retries == 0) {
+				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. If a 
+					   final frame, destroy the session, otherwise, pass up timeout */
+					if (frame->final) {
+						iax_mutex_lock(session_mutex); 
+						destroy_session(frame->session);
+						iax_mutex_unlock(session_mutex); 
+						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 {
+				struct ast_iax2_full_hdr *fh;
+				/* Decrement remaining retries */
+				frame->retries--;
+				/* Multiply next retry time by 4, not above MAX_RETRY_TIME though */
+				frame->retrytime *= 4;
+				/* Keep under 1000 ms if this is a transfer packet */
+				if (!frame->transfer) {
+					if (frame->retrytime > MAX_RETRY_TIME)
+						frame->retrytime = MAX_RETRY_TIME;
+				} else if (frame->retrytime > 1000)
+					frame->retrytime = 1000;
+				fh = (struct ast_iax2_full_hdr *)(frame->data);
+				fh->dcallno = htons(IAX_FLAG_RETRANS | frame->dcallno);
+				iax_xmit_frame(frame);
+				/* Schedule another retransmission */
+				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;
+		iax_mutex_lock(session_mutex); 
+	    for(cur=sessions; cur; cur=cur->next) {
+			int ret;
+			time_in_ms_t now;
+			time_in_ms_t next;
+
+			now = time_in_ms - cur->rxcore;
+			if(now > (next = jb_next(cur->jb))) {
+				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) {
+						iax_mutex_unlock(session_mutex);
+						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) {
+							iax_mutex_unlock(session_mutex);
+							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;
+				}
+			}
+	    }
+		iax_mutex_unlock(session_mutex);
+	}
+
+#endif
+	/* Now look for networking events */
+	if (blocking) {
+		/* Block until there is data if desired */
+		fd_set fds;
+		time_in_ms_t nextEventTime;
+		
+		FD_ZERO(&fds);
+		FD_SET(netfd, &fds);
+
+		nextEventTime = iax_time_to_next_event(); 
+		if(nextEventTime < 0 && blocking > 1) {
+			nextEventTime = blocking;
+		}
+		if(nextEventTime < 0) 
+			select(netfd + 1, &fds, NULL, NULL, NULL);
+		else 
+		{ 
+			struct timeval nextEvent; 
+
+			nextEvent.tv_sec = (long)(nextEventTime / 1000); 
+			nextEvent.tv_usec = (long)((nextEventTime % 1000) * 1000);
+
+			select(netfd + 1, &fds, NULL, NULL, &nextEvent); 
+		} 
+
+	}
+	event = iax_net_read();
+	
+	return handle_event(event);
+}
+
+struct sockaddr_in iax_get_peer_addr(struct iax_session *session)
+{
+	return session->peeraddr;
+}
+
+char *iax_get_peer_ip(struct iax_session *session)
+{
+	return inet_ntoa(session->peeraddr.sin_addr);
+}
+
+char *iax_event_get_apparent_ip(struct iax_event *event)
+{
+	return inet_ntoa(event->ies.apparent_addr->sin_addr);
+}
+
+void iax_session_destroy(struct iax_session **session) 
+{
+	iax_mutex_lock(session_mutex); 
+	destroy_session(*session);
+	*session = NULL;
+	iax_mutex_unlock(session_mutex); 
+}
+
+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 */
+			iax_mutex_lock(session_mutex); 
+			destroy_session(event->session);
+			iax_mutex_unlock(session_mutex); 
+		}
+		break;
+	}
+	free(event);
+}
+
+int iax_get_fd(void) 
+{
+	/* Return our network file descriptor.  The client can select on this (probably with other
+	   things, or can add it to a network add sort of gtk_input_add for example */
+	return netfd;
+}
+
+int iax_quelch_moh(struct iax_session *session, int MOH)
+{
+	
+	struct iax_ie_data ied;			//IE Data Structure (Stuff To Send)
+	memset(&ied, 0, sizeof(ied));	
+	
+	// You can't quelch the quelched
+	if (session->quelch == 1)
+		return -1;
+		
+	if (MOH) {
+		iax_ie_append(&ied, IAX_IE_MUSICONHOLD);
+		session->transfer_moh = 1;
+	}
+		
+	return send_command(session, AST_FRAME_IAX, IAX_COMMAND_QUELCH, 0, ied.buf, ied.pos, -1);
+}

Added: freeswitch/trunk/src/mod/endpoints/mod_iax/iax.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/iax.h	Thu May  8 19:25:36 2008
@@ -0,0 +1,86 @@
+/*
+ * libIAX
+ *
+ * Implementation of Inter-IAXerisk eXchange
+ * 
+ * Copyright (C) 1999, Mark Spencer
+ *
+ * Mark Spencer <markster at linux-support.net>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU Lesser (Library) General Public License
+ */
+ 
+#ifndef _IAX_H
+#define _IAX_H
+
+/* Max version of IAX protocol we support */
+#define IAX_PROTO_VERSION 1
+
+#define IAX_MAX_CALLS 32768
+
+#define IAX_FLAG_FULL		0x8000
+
+#define IAX_FLAG_SC_LOG		0x80
+
+#define IAX_MAX_SHIFT		0x1F
+
+/* Maximum size of an IAX frame (max size of UDP frame) */
+#define IAX_MAX_BUF_SIZE 65536
+
+/* Subclass for IAX_FRAME_IAX */
+#define IAX_COMMAND_NEW		1
+#define IAX_COMMAND_PING	2
+#define IAX_COMMAND_PONG	3
+#define IAX_COMMAND_ACK		4
+#define IAX_COMMAND_HANGUP	5
+#define IAX_COMMAND_REJECT	6
+#define IAX_COMMAND_ACCEPT	7
+#define IAX_COMMAND_AUTHREQ	8
+#define IAX_COMMAND_AUTHREP	9
+#define IAX_COMMAND_INVAL	10
+#define IAX_COMMAND_LAGRQ	11
+#define IAX_COMMAND_LAGRP	12
+#define IAX_COMMAND_REGREQ	13	/* Registration request */
+#define IAX_COMMAND_REGAUTH	14	/* Registration authentication required */
+#define IAX_COMMAND_REGACK	15	/* Registration accepted */
+#define IAX_COMMAND_REGREJ	16	/* Registration rejected */
+#define IAX_COMMAND_REGREL	17	/* Force release of registration */
+#define IAX_COMMAND_VNAK	18	/* If we receive voice before valid first voice frame, send this */
+#define IAX_COMMAND_DPREQ	19	/* Request status of a dialplan entry */
+#define IAX_COMMAND_DPREP	20	/* Request status of a dialplan entry */
+#define IAX_COMMAND_DIAL	21	/* Request a dial on channel brought up TBD */
+#define IAX_COMMAND_TXREQ	22	/* Transfer Request */
+#define IAX_COMMAND_TXCNT	23	/* Transfer Connect */
+#define IAX_COMMAND_TXACC	24	/* Transfer Accepted */
+#define IAX_COMMAND_TXREADY	25	/* Transfer ready */
+#define IAX_COMMAND_TXREL	26	/* Transfer release */
+#define IAX_COMMAND_TXREJ	27	/* Transfer reject */
+#define IAX_COMMAND_QUELCH	28	/* Stop audio/video transmission */
+#define IAX_COMMAND_UNQUELCH 29	/* Resume audio/video transmission */
+
+#define IAX_DEFAULT_REG_EXPIRE 	60
+
+#define IAX_DEFAULT_PORTNO		5036
+
+/* Full frames are always delivered reliably */
+struct iax_full_hdr {
+	short callno;			/* Source call number -- high bit must be 1 */
+	short dcallno;			/* Destination call number */
+	unsigned int ts;		/* 32-bit timestamp in milliseconds */
+	unsigned short seqno;	/* Packet number */
+	char type;				/* Frame type */
+	unsigned char csub;		/* Compressed subclass */
+	char data[];
+};
+
+/* Mini header is used only for voice frames -- delivered unreliably */
+struct iax_mini_hdr {
+	short callno;			/* Source call number -- high bit must be 0 */
+	unsigned short ts;		/* 16-bit Timestamp (high 16 bits from last IAX_full_hdr) */
+							/* Frametype implicitly VOICE_FRAME */
+							/* subclass implicit from last IAX_full_hdr */
+	char data[];
+};
+
+#endif

Added: freeswitch/trunk/src/mod/endpoints/mod_iax/iax2-parser.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/iax2-parser.c	Thu May  8 19:25:36 2008
@@ -0,0 +1,840 @@
+/*
+ * Asterisk -- A telephony toolkit for Linux.
+ *
+ * Implementation of Inter-Asterisk eXchange
+ * 
+ * Copyright (C) 2003-2004, Digium
+ *
+ * Mark Spencer <markster at digium.com>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU Lesser (Library) General Public License
+ */
+
+#ifdef WIN32
+#include <winsock.h>
+#define snprintf _snprintf
+#else
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+
+#ifndef _MSC_VER
+#include <unistd.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "frame.h"
+#include "iax2.h"
+#include "iax2-parser.h"
+
+static int frames = 0;
+static int iframes = 0;
+static int oframes = 0;
+
+#ifdef ALIGN32
+static unsigned int get_uint32(unsigned char *p)
+{
+  return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
+}
+
+static unsigned short get_uint16(unsigned char *p)
+{
+  return (p[0] << 8) | p[1] ;
+}
+
+#else
+#define get_uint32(p) (*((unsigned int *)(p)))
+#define get_uint16(p) (*((unsigned short *)(p)))
+#endif
+
+
+static void internaloutput(const char *str)
+{
+	printf(str);
+}
+
+static void internalerror(const char *str)
+{
+	fprintf(stderr, "WARNING: %s", str);
+}
+
+static void (*outputf)(const char *str) = internaloutput;
+static void (*errorf)(const char *str) = internalerror;
+
+static void dump_addr(char *output, int maxlen, void *value, int len)
+{
+	struct sockaddr_in sin;
+	if (len == sizeof(sin)) {
+		memcpy(&sin, value, len);
+		snprintf(output, maxlen, "IPV4 %s:%d", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
+	} else {
+		snprintf(output, maxlen, "Invalid Address");
+	}
+}
+
+static void dump_string(char *output, int maxlen, void *value, int len)
+{
+	maxlen--;
+	if (maxlen > len)
+		maxlen = len;
+	strncpy(output,value, maxlen);
+	output[maxlen] = '\0';
+}
+
+static void dump_int(char *output, int maxlen, void *value, int len)
+{
+	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 == (int)sizeof(unsigned short))
+		snprintf(output, maxlen, "%d", ntohs(get_uint16(value)));
+	else
+		snprintf(output, maxlen, "Invalid SHORT");
+}
+
+static void dump_byte(char *output, int maxlen, void *value, int len)
+{
+	if (len == (int)sizeof(unsigned char))
+		snprintf(output, maxlen, "%d", *((unsigned char *)value));
+	else
+		snprintf(output, maxlen, "Invalid BYTE");
+}
+
+#if 0
+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");
+}
+#endif
+
+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_32KHZ)
+			strcat(tmp, ",32khz");
+		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;
+	void (*dump)(char *output, int maxlen, void *value, int len);
+} ies[] = {
+	{ IAX_IE_CALLED_NUMBER, "CALLED NUMBER", dump_string },
+	{ IAX_IE_CALLING_NUMBER, "CALLING NUMBER", dump_string },
+	{ IAX_IE_CALLING_ANI, "ANI", dump_string },
+	{ IAX_IE_CALLING_NAME, "CALLING NAME", dump_string },
+	{ IAX_IE_CALLED_CONTEXT, "CALLED CONTEXT", dump_string },
+	{ IAX_IE_USERNAME, "USERNAME", dump_string },
+	{ IAX_IE_PASSWORD, "PASSWORD", dump_string },
+	{ 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 },
+	{ IAX_IE_AUTHMETHODS, "AUTHMETHODS", dump_short },
+	{ IAX_IE_CHALLENGE, "CHALLENGE", dump_string },
+	{ IAX_IE_MD5_RESULT, "MD5 RESULT", dump_string },
+	{ IAX_IE_RSA_RESULT, "RSA RESULT", dump_string },
+	{ IAX_IE_APPARENT_ADDR, "APPARENT ADDRESS", dump_addr },
+	{ IAX_IE_REFRESH, "REFRESH", dump_short },
+	{ IAX_IE_DPSTATUS, "DIALPLAN STATUS", dump_short },
+	{ IAX_IE_CALLNO, "CALL NUMBER", dump_short },
+	{ IAX_IE_CAUSE, "CAUSE", dump_string },
+	{ IAX_IE_IAX_UNKNOWN, "UNKNOWN IAX CMD", dump_byte },
+	{ IAX_IE_MSGCOUNT, "MESSAGE COUNT", dump_short },
+	{ IAX_IE_AUTOANSWER, "AUTO ANSWER REQ" },
+	{ IAX_IE_TRANSFERID, "TRANSFER ID", dump_int },
+	{ IAX_IE_RDNIS, "REFERRING DNIS", dump_string },
+	{ 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_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<(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 -= (int)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 -= (int)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 -= (int)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[1024];
+	char tmp[1024];
+	if (len < 2)
+		return;
+	while(len > 2) {
+		ie = iedata[0];
+		ielen = iedata[1];
+		if (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<(int)sizeof(ies) / (int)sizeof(ies[0]); x++) {
+			if (ies[x].ie == ie) {
+				if (ies[x].dump) {
+					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 {
+					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, (int)sizeof(tmp), "   Unknown IE %03d  : Present\n", ie);
+			outputf(tmp);
+		}
+		iedata += (2 + ielen);
+		len -= (2 + ielen);
+	}
+	outputf("\n");
+}
+
+void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
+{
+	const char *frames[] = {
+		"(0?)",
+		"DTMF   ",
+		"VOICE  ",
+		"VIDEO  ",
+		"CONTROL",
+		"NULL   ",
+		"IAX    ",
+		"TEXT   ",
+		"IMAGE  " };
+	const char *iaxs[] = {
+		"(0?)",
+		"NEW    ",
+		"PING   ",
+		"PONG   ",
+		"ACK    ",
+		"HANGUP ",
+		"REJECT ",
+		"ACCEPT ",
+		"AUTHREQ",
+		"AUTHREP",
+		"INVAL  ",
+		"LAGRQ  ",
+		"LAGRP  ",
+		"REGREQ ",
+		"REGAUTH",
+		"REGACK ",
+		"REGREJ ",
+		"REGREL ",
+		"VNAK   ",
+		"DPREQ  ",
+		"DPREP  ",
+		"DIAL   ",
+		"TXREQ  ",
+		"TXCNT  ",
+		"TXACC  ",
+		"TXREADY",
+		"TXREL  ",
+		"TXREJ  ",
+		"QUELCH ",
+		"UNQULCH",
+		"POKE",
+		"PAGE",
+		"MWI",
+		"UNSUPPORTED",
+		"TRANSFER",
+		"PROVISION",
+		"FWDOWNLD",
+		"FWDATA"
+	};
+	const char *cmds[] = {
+		"(0?)",
+		"HANGUP ",
+		"RING   ",
+		"RINGING",
+		"ANSWER ",
+		"BUSY   ",
+		"TKOFFHK ",
+		"OFFHOOK" };
+	struct ast_iax2_full_hdr *fh;
+	char retries[20];
+	char class2[20];
+	char subclass2[20];
+	const char *class;
+	const char *subclass;
+	char tmp[256];
+
+	if (f) {
+		fh = f->data;
+		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");
+	}
+	if (!(ntohs(fh->scallno) & IAX_FLAG_FULL)) {
+		/* Don't mess with mini-frames */
+		return;
+	}
+	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];
+	}
+	if (fh->type == AST_FRAME_DTMF) {
+		sprintf(subclass2, "%c", fh->csub);
+		subclass = subclass2;
+	} else if (fh->type == AST_FRAME_IAX) {
+		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 > (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, (int)sizeof(subclass2), "%d", fh->csub);
+		subclass = subclass2;
+	}
+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, (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);
+	if (fh->type == AST_FRAME_IAX)
+		dump_ies(fh->iedata, datalen);
+}
+
+int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, const void *data, int datalen)
+{
+	char tmp[256];
+	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;
+	}
+	ied->buf[ied->pos++] = ie;
+	ied->buf[ied->pos++] = datalen;
+	memcpy(ied->buf + ied->pos, data, datalen);
+	ied->pos += datalen;
+	return 0;
+}
+
+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, (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, (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, (int)sizeof(newval));
+}
+
+int iax_ie_append_str(struct iax_ie_data *ied, unsigned char ie, const unsigned char *str)
+{
+	return iax_ie_append_raw(ied, ie, str, (int)strlen((char *) str));
+}
+
+int iax_ie_append_byte(struct iax_ie_data *ied, unsigned char ie, unsigned char dat)
+{
+	return iax_ie_append_raw(ied, ie, &dat, 1);
+}
+
+int iax_ie_append(struct iax_ie_data *ied, unsigned char ie) 
+{
+	return iax_ie_append_raw(ied, ie, NULL, 0);
+}
+
+void iax_set_output(void (*func)(const char *))
+{
+	outputf = func;
+}
+
+void iax_set_error(void (*func)(const char *))
+{
+	errorf = func;
+}
+
+int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
+{
+	/* Parse data into information elements */
+	int len;
+	int ie;
+	char tmp[256];
+	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];
+		if (len > datalen - 2) {
+			errorf("Information element length exceeds message size\n");
+			return -1;
+		}
+		switch(ie) {
+		case IAX_IE_CALLED_NUMBER:
+			ies->called_number = (char *) data + 2;
+			break;
+		case IAX_IE_CALLING_NUMBER:
+			ies->calling_number = (char *) data + 2;
+			break;
+		case IAX_IE_CALLING_ANI:
+			ies->calling_ani = (char *) data + 2;
+			break;
+		case IAX_IE_CALLING_NAME:
+			ies->calling_name = (char *) data + 2;
+			break;
+		case IAX_IE_CALLED_CONTEXT:
+			ies->called_context = (char *) data + 2;
+			break;
+		case IAX_IE_USERNAME:
+			ies->username = (char *) data + 2;
+			break;
+		case IAX_IE_PASSWORD:
+			ies->password = (char *) data + 2;
+			break;
+		case IAX_IE_CAPABILITY:
+			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));
+			break;
+		case IAX_IE_FORMAT:
+			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));
+			break;
+		case IAX_IE_LANGUAGE:
+			ies->language = (char *) data + 2;
+			break;
+		case IAX_IE_CODEC_PREFS:
+			ies->codec_prefs = (char *) data + 2;
+			break;
+		case IAX_IE_VERSION:
+			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));
+			break;
+		case IAX_IE_ADSICPE:
+			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->samprate = ntohs(get_uint16(data + 2));
+			break;
+		case IAX_IE_DNID:
+			ies->dnid = (char *) data + 2;
+			break;
+		case IAX_IE_RDNIS:
+			ies->rdnis = (char *) data + 2;
+			break;
+		case IAX_IE_AUTHMETHODS:
+			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));
+			break;
+		case IAX_IE_CHALLENGE:
+			ies->challenge = (char *) data + 2;
+			break;
+		case IAX_IE_MD5_RESULT:
+			ies->md5_result = (char *) data + 2;
+			break;
+		case IAX_IE_RSA_RESULT:
+			ies->rsa_result = (char *) data + 2;
+			break;
+		case IAX_IE_APPARENT_ADDR:
+			ies->apparent_addr = ((struct sockaddr_in *)(data + 2));
+			break;
+		case IAX_IE_REFRESH:
+			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));
+			break;
+		case IAX_IE_DPSTATUS:
+			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(get_uint16(data + 2));
+			break;
+		case IAX_IE_CALLNO:
+			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));
+			break;
+		case IAX_IE_CAUSE:
+			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, (int)sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len);
+				errorf(tmp);
+			}
+			break;
+		case IAX_IE_MSGCOUNT:
+			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));	
+			break;
+		case IAX_IE_AUTOANSWER:
+			ies->autoanswer = 1;
+			break;
+		case IAX_IE_MUSICONHOLD:
+			ies->musiconhold = 1;
+			break;
+		case IAX_IE_TRANSFERID:
+			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));
+			break;
+		case IAX_IE_DATETIME:
+			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->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, (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;
+		datalen -= (len + 2);
+		data += (len + 2);
+	}
+	/* Null-terminate last field */
+	*data = '\0';
+	if (datalen) {
+		errorf("Invalid information element contents, strange boundary\n");
+		return -1;
+	}
+	return 0;
+}
+
+void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f)
+{
+	fr->af.frametype = f->frametype;
+	fr->af.subclass = f->subclass;
+	fr->af.mallocd = 0;				/* Our frame is static relative to the container */
+	fr->af.datalen = f->datalen;
+	fr->af.samples = f->samples;
+	fr->af.offset = AST_FRIENDLY_OFFSET;
+	fr->af.src = f->src;
+	fr->af.data = fr->afdata;
+	if (fr->af.datalen) 
+		memcpy(fr->af.data, f->data, fr->af.datalen);
+}
+
+struct iax_frame *iax_frame_new(int direction, int datalen)
+{
+	struct iax_frame *fr;
+	fr = malloc((int)sizeof(struct iax_frame) + datalen);
+	if (fr) {
+		fr->direction = direction;
+		fr->retrans = -1;
+		frames++;
+		if (fr->direction == DIRECTION_INGRESS)
+			iframes++;
+		else
+			oframes++;
+	}
+	return fr;
+}
+
+void iax_frame_free(struct iax_frame *fr)
+{
+	/* Note: does not remove from scheduler! */
+	if (fr->direction == DIRECTION_INGRESS)
+		iframes--;
+	else if (fr->direction == DIRECTION_OUTGRESS)
+		oframes--;
+	else {
+		errorf("Attempt to double free frame detected\n");
+		return;
+	}
+	fr->direction = 0;
+	free(fr);
+	frames--;
+}
+
+int iax_get_frames(void) { return frames; }
+int iax_get_iframes(void) { return iframes; }
+int iax_get_oframes(void) { return oframes; }

Added: freeswitch/trunk/src/mod/endpoints/mod_iax/iax2-parser.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/iax2-parser.h	Thu May  8 19:25:36 2008
@@ -0,0 +1,145 @@
+/*
+ * Asterisk -- A telephony toolkit for Linux.
+ *
+ * Implementation of Inter-Asterisk eXchange
+ * 
+ * Copyright (C) 2003, Digium
+ *
+ * Mark Spencer <markster at digium.com>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU Lesser (Library) General Public License
+ */
+ 
+#ifndef _IAX2_PARSER_H
+#define _IAX2_PARSER_H
+
+struct iax_ies {
+	char *called_number;
+	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;
+	char *dnid;
+	char *rdnis;
+	unsigned int authmethods;
+	char *challenge;
+	char *md5_result;
+	char *rsa_result;
+	struct sockaddr_in *apparent_addr;
+	unsigned short refresh;
+	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 */
+	unsigned short dcallno;
+	/* Start of raw frame (outgoing only) */
+	void *data;
+	/* Length of frame (outgoing only) */
+	int datalen;
+	/* How many retries so far? */
+	int retries;
+	/* Outgoing relative timestamp (ms) */
+	time_in_ms_t ts;
+	/* How long to wait before retrying */
+	time_in_ms_t retrytime;
+	/* Are we received out of order?  */
+	int outoforder;
+	/* Have we been sent at all yet? */
+	int sentyet;
+	/* Outgoing Packet sequence number */
+	int oseqno;
+	/* Next expected incoming packet sequence number */
+	int iseqno;
+	/* Non-zero if should be sent to transfer peer */
+	int transfer;
+	/* Non-zero if this is the final message */
+	int final;
+	/* Ingress or outgres */
+	int direction;
+	/* Retransmission ID */
+	int retrans;
+	/* Easy linking */
+	struct iax_frame *next;
+	struct iax_frame *prev;
+	/* Actual, isolated frame header */
+	struct ast_frame af;
+	unsigned char unused[AST_FRIENDLY_OFFSET];
+	unsigned char afdata[];	/* Data for frame */
+};
+
+struct iax_ie_data {
+	unsigned char buf[1024];
+	int pos;
+};
+
+/* Choose a different function for output */
+extern void iax_set_output(void (*output)(const char *data));
+/* Choose a different function for errors */
+extern void iax_set_error(void (*output)(const char *data));
+extern void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen);
+
+extern const char *iax_ie2str(int ie);
+
+extern int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, const void *data, int datalen);
+extern int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, struct sockaddr_in *sin);
+extern int iax_ie_append_int(struct iax_ie_data *ied, unsigned char ie, unsigned int value);
+extern int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsigned short value);
+extern int iax_ie_append_str(struct iax_ie_data *ied, unsigned char ie, const unsigned char *str);
+extern int iax_ie_append_byte(struct iax_ie_data *ied, unsigned char ie, unsigned char dat);
+extern int iax_ie_append(struct iax_ie_data *ied, unsigned char ie);
+extern int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen);
+
+extern int iax_get_frames(void);
+extern int iax_get_iframes(void);
+extern int iax_get_oframes(void);
+extern void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f);
+extern struct iax_frame *iax_frame_new(int direction, int datalen);
+extern void iax_frame_free(struct iax_frame *fr);
+#endif

Added: freeswitch/trunk/src/mod/endpoints/mod_iax/iax2.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/iax2.h	Thu May  8 19:25:36 2008
@@ -0,0 +1,236 @@
+/*
+ * Asterisk -- A telephony toolkit for Linux.
+ *
+ * Implementation of Inter-Asterisk eXchange
+ * 
+ * Copyright (C) 2003, Digium
+ *
+ * Mark Spencer <markster at linux-support.net>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU Lesser (Library) General Public License
+ */
+ 
+#ifndef _IAX2_H
+#define _IAX2_H
+
+typedef long long time_in_ms_t;
+#define iax_abs(x) ((x) >= 0 ? (x) : -(x))
+
+/* Max version of IAX protocol we support */
+#define IAX_PROTO_VERSION 2
+
+#define IAX_MAX_CALLS 32768
+
+#define IAX_FLAG_FULL		0x8000
+
+#define IAX_FLAG_RETRANS	0x8000
+
+#define IAX_FLAG_SC_LOG		0x80
+
+#define IAX_MAX_SHIFT		0x1F
+
+#define IAX_WINDOW			64
+
+/* Subclass for AST_FRAME_IAX */
+#define IAX_COMMAND_NEW		1
+#define IAX_COMMAND_PING	2
+#define IAX_COMMAND_PONG	3
+#define IAX_COMMAND_ACK		4
+#define IAX_COMMAND_HANGUP	5
+#define IAX_COMMAND_REJECT	6
+#define IAX_COMMAND_ACCEPT	7
+#define IAX_COMMAND_AUTHREQ	8
+#define IAX_COMMAND_AUTHREP	9
+#define IAX_COMMAND_INVAL	10
+#define IAX_COMMAND_LAGRQ	11
+#define IAX_COMMAND_LAGRP	12
+#define IAX_COMMAND_REGREQ	13	/* Registration request */
+#define IAX_COMMAND_REGAUTH	14	/* Registration authentication required */
+#define IAX_COMMAND_REGACK	15	/* Registration accepted */
+#define IAX_COMMAND_REGREJ	16	/* Registration rejected */
+#define IAX_COMMAND_REGREL	17	/* Force release of registration */
+#define IAX_COMMAND_VNAK	18	/* If we receive voice before valid first voice frame, send this */
+#define IAX_COMMAND_DPREQ	19	/* Request status of a dialplan entry */
+#define IAX_COMMAND_DPREP	20	/* Request status of a dialplan entry */
+#define IAX_COMMAND_DIAL	21	/* Request a dial on channel brought up TBD */
+#define IAX_COMMAND_TXREQ	22	/* Transfer Request */
+#define IAX_COMMAND_TXCNT	23	/* Transfer Connect */
+#define IAX_COMMAND_TXACC	24	/* Transfer Accepted */
+#define IAX_COMMAND_TXREADY	25	/* Transfer ready */
+#define IAX_COMMAND_TXREL	26	/* Transfer release */
+#define IAX_COMMAND_TXREJ	27	/* Transfer reject */
+#define IAX_COMMAND_QUELCH	28	/* Stop audio/video transmission */
+#define IAX_COMMAND_UNQUELCH 29	/* Resume audio/video transmission */
+#define IAX_COMMAND_POKE    30  /* Like ping, but does not require an open connection */
+#define IAX_COMMAND_PAGE	31	/* Paging description */
+#define IAX_COMMAND_MWI	32	/* Stand-alone message waiting indicator */
+#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 */
+
+#define IAX_LINGER_TIMEOUT		10 /* How long to wait before closing bridged call */
+
+#define IAX_DEFAULT_PORTNO		4569
+
+/* IAX Information elements */
+#define IAX_IE_CALLED_NUMBER		1		/* Number/extension being called - string */
+#define IAX_IE_CALLING_NUMBER		2		/* Calling number - string */
+#define IAX_IE_CALLING_ANI			3		/* Calling number ANI for billing  - string */
+#define IAX_IE_CALLING_NAME			4		/* Name of caller - string */
+#define IAX_IE_CALLED_CONTEXT		5		/* Context for number - string */
+#define IAX_IE_USERNAME				6		/* Username (peer or user) for authentication - string */
+#define IAX_IE_PASSWORD				7		/* Password for authentication - string */
+#define IAX_IE_CAPABILITY			8		/* Actual codec capability - unsigned int */
+#define IAX_IE_FORMAT				9		/* Desired codec format - unsigned int */
+#define IAX_IE_LANGUAGE				10		/* Desired language - string */
+#define IAX_IE_VERSION				11		/* Protocol version - short */
+#define IAX_IE_ADSICPE				12		/* CPE ADSI capability - short */
+#define IAX_IE_DNID					13		/* Originally dialed DNID - string */
+#define IAX_IE_AUTHMETHODS			14		/* Authentication method(s) - short */
+#define IAX_IE_CHALLENGE			15		/* Challenge data for MD5/RSA - string */
+#define IAX_IE_MD5_RESULT			16		/* MD5 challenge result - string */
+#define IAX_IE_RSA_RESULT			17		/* RSA challenge result - string */
+#define IAX_IE_APPARENT_ADDR		18		/* Apparent address of peer - struct sockaddr_in */
+#define IAX_IE_REFRESH				19		/* When to refresh registration - short */
+#define IAX_IE_DPSTATUS				20		/* Dialplan status - short */
+#define IAX_IE_CALLNO				21		/* Call number of peer - short */
+#define IAX_IE_CAUSE				22		/* Cause - string */
+#define IAX_IE_IAX_UNKNOWN			23		/* Unknown IAX command - byte */
+#define IAX_IE_MSGCOUNT				24		/* How many messages waiting - short */
+#define IAX_IE_AUTOANSWER			25		/* Request auto-answering -- none */
+#define IAX_IE_MUSICONHOLD			26		/* Request musiconhold with QUELCH -- none or string */
+#define IAX_IE_TRANSFERID			27		/* Transfer Request Identifier -- int */
+#define IAX_IE_RDNIS				28		/* Referring DNIS -- string */
+#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)
+#define IAX_AUTH_RSA				(1 << 2)
+
+#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_RATE_32KHZ                         (1 << 6) /* 32khz sampling */
+
+#define IAX_DPSTATUS_EXISTS			(1 << 0)
+#define IAX_DPSTATUS_CANEXIST		(1 << 1)
+#define IAX_DPSTATUS_NONEXISTANT	(1 << 2)
+#define IAX_DPSTATUS_IGNOREPAT		(1 << 14)
+#define IAX_DPSTATUS_MATCHMORE		(1 << 15)
+
+#if defined __GNUC__
+#define __PACKED __attribute__ ((__packed__))
+#else
+#if defined (_MSC_VER) 
+#pragma pack(push,1)
+#define __PACKED
+#else
+#pragma pack(1)
+#define __PACKED   
+#endif
+#endif
+
+/* Full frames are always delivered reliably */
+struct ast_iax2_full_hdr {
+	unsigned short scallno;	/* Source call number -- high bit must be 1 */
+	unsigned short dcallno;	/* Destination call number -- high bit is 1 if retransmission */
+	unsigned int ts;		/* 32-bit timestamp in milliseconds (from 1st transmission) */
+	unsigned char oseqno;	/* Packet number (outgoing) */
+	unsigned char iseqno;	/* Packet number (next incoming expected) */
+	char type;				/* Frame type */
+	unsigned char csub;		/* Compressed subclass */
+	unsigned char iedata[];
+} __PACKED;
+
+/* Mini header is used only for voice frames -- delivered unreliably */
+struct ast_iax2_mini_hdr {
+	unsigned short callno;	/* Source call number -- high bit must be 0, rest must be non-zero */
+	unsigned short ts;		/* 16-bit Timestamp (high 16 bits from last ast_iax2_full_hdr) */
+							/* Frametype implicitly VOICE_FRAME */
+							/* subclass implicit from last ast_iax2_full_hdr */
+	unsigned char data[];
+} __PACKED;
+
+struct ast_iax2_meta_hdr {
+	unsigned short zeros;			/* Zeros field -- must be zero */
+	unsigned char metacmd;			/* Meta command */
+	unsigned char cmddata;			/* Command Data */
+	unsigned char data[];
+} __PACKED;
+
+struct ast_iax2_video_hdr {
+	unsigned short zeros;			/* Zeros field -- must be zero */
+	unsigned short callno;			/* Video call number */
+	unsigned short ts;				/* Timestamp and mark if present */
+	unsigned char data[];
+} __PACKED;
+
+struct ast_iax2_meta_trunk_hdr {
+	unsigned int ts;				/* 32-bit timestamp for all messages */
+	unsigned char data[];
+} __PACKED;
+
+struct ast_iax2_meta_trunk_entry {
+	unsigned short callno;			/* Call number */
+	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[];
+} __PACKED;
+
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#else
+#ifndef __GNUC__
+#pragma pack()
+#endif
+#endif
+
+#undef __PACKED
+
+#endif

Added: freeswitch/trunk/src/mod/endpoints/mod_iax/jitterbuf.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/jitterbuf.c	Thu May  8 19:25:36 2008
@@ -0,0 +1,834 @@
+/*
+ * jitterbuf: an application-independent jitterbuffer
+ *
+ * Copyrights:
+ * Copyright (C) 2004-2005, Horizon Wimba, Inc.
+ *
+ * Contributors:
+ * Steve Kann <stevek at 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 "iax2.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "jitterbuf.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(*jb));
+	jb->info.conf = s;
+
+	/* initialize length, using the configured value */
+	jb->info.current = jb->info.target = jb->info.conf.target_extra;
+	jb->info.silence_begin_ts = -1;
+}
+
+jitterbuf * jb_new()
+{
+	jitterbuf *jb;
+
+	if (!(jb = (jitterbuf *)malloc(sizeof(*jb))))
+		return NULL;
+
+	jb->info.conf.target_extra = JB_TARGET_EXTRA;
+
+	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);
+}
+
+
+
+#if 0
+static int longcmp(const void *a, const void *b)
+{
+	return *(long *)a - *(long *)b;
+}
+#endif
+
+/* 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 */
+static int history_put(jitterbuf *jb, time_in_ms_t ts, time_in_ms_t now, long ms)
+{
+	time_in_ms_t delay = now - (ts - jb->info.resync_offset);
+	time_in_ms_t threshold = 2 * jb->info.jitter + jb->info.conf.resync_threshold;
+	time_in_ms_t 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 (iax_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++) {
+	time_in_ms_t 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(jb->hist_maxbuf[0]));
+					/* 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(jb->hist_minbuf[0]));
+					/* 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");
+#endif
+	}
+
+	jb->hist_maxbuf_valid = 1;
+}
+
+static void history_get(jitterbuf *jb)
+{
+    time_in_ms_t 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, const enum jb_frame_type type, long ms, time_in_ms_t ts)
+{
+	jb_frame *frame;
+	jb_frame *p;
+	int head = 0;
+	time_in_ms_t resync_ts = ts - jb->info.resync_offset;
+
+	if ((frame = jb->free)) {
+		jb->free = frame->next;
+	} else if (!(frame = (jb_frame *)malloc(sizeof(*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 (resync_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 time_in_ms_t queue_next(jitterbuf *jb) 
+{
+	if (jb->frames)
+		return jb->frames->ts;
+	else
+		return -1;
+}
+
+static time_in_ms_t queue_last(jitterbuf *jb) 
+{
+	if (jb->frames)
+		return jb->frames->prev->ts;
+	else
+		return -1;
+}
+
+static jb_frame *_queue_get(jitterbuf *jb, time_in_ms_t 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, time_in_ms_t 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
+
+enum jb_return_code jb_put(jitterbuf *jb, void *data, const enum jb_frame_type type, long ms, time_in_ms_t ts, time_in_ms_t 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 enum jb_return_code _jb_get(jitterbuf *jb, jb_frame *frameout, time_in_ms_t now, long interpl)
+{
+	jb_frame *frame;
+	time_in_ms_t 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->info.conf.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 length */
+			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++;
+			/* 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("G");
+			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->info.conf.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++;
+		jb->info.cnt_contig_interp = 0;
+		decrement_losspct(jb);
+		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->info.conf.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;
+		}
+	}
+}
+
+time_in_ms_t jb_next(jitterbuf *jb)
+{
+	if (jb->info.silence_begin_ts) {
+		if (jb->frames) {
+			time_in_ms_t next = queue_next(jb);
+			history_get(jb);
+			/* shrink during silence */
+			if (jb->info.target - jb->info.current < -jb->info.conf.target_extra)
+				return jb->info.last_adjustment + 10;
+			return next + jb->info.target;
+		}
+		else
+			return JB_LONGMAX;
+	} else {
+		return jb->info.next_voice_ts;
+	}
+}
+
+enum jb_return_code jb_get(jitterbuf *jb, jb_frame *frameout, time_in_ms_t now, long interpl)
+{
+	enum jb_return_code 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;
+}
+
+enum jb_return_code jb_getall(jitterbuf *jb, jb_frame *frameout)
+{
+	jb_frame *frame;
+	frame = queue_getall(jb);
+
+	if (!frame) {
+		return JB_NOFRAME;
+	}
+
+	*frameout = *frame;
+	return JB_OK;
+}
+
+
+enum jb_return_code jb_getinfo(jitterbuf *jb, jb_info *stats)
+{
+	history_get(jb);
+
+	*stats = jb->info;
+
+	return JB_OK;
+}
+
+enum jb_return_code 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;
+
+	/* -1 indicates use of the default JB_TARGET_EXTRA value */
+	jb->info.conf.target_extra = ( conf->target_extra == -1 )
+		? JB_TARGET_EXTRA
+		: conf->target_extra
+		;
+
+	/* update these to match new target_extra setting */
+	jb->info.current = jb->info.conf.target_extra;
+	jb->info.target = jb->info.conf.target_extra;
+
+	return JB_OK;
+}
+
+

Added: freeswitch/trunk/src/mod/endpoints/mod_iax/jitterbuf.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/jitterbuf.h	Thu May  8 19:25:36 2008
@@ -0,0 +1,162 @@
+/*
+ * jitterbuf: an application-independent jitterbuffer
+ *
+ * Copyrights:
+ * Copyright (C) 2004-2005, Horizon Wimba, Inc.
+ *
+ * Contributors:
+ * Steve Kann <stevek at 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
+
+enum jb_return_code {
+	/* return codes */
+	JB_OK,            /* 0 */
+	JB_EMPTY,         /* 1 */
+	JB_NOFRAME,       /* 2 */
+	JB_INTERP,        /* 3 */
+	JB_DROP,          /* 4 */
+	JB_SCHED          /* 5 */
+};
+
+enum jb_frame_type {
+/* frame types */
+	JB_TYPE_CONTROL,  /* 0            */
+	JB_TYPE_VOICE,    /* 1            */
+	JB_TYPE_VIDEO,    /* 2 - reserved */
+	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 */
+	long target_extra;      /* amount of additional jitterbuffer adjustment, overrides JB_TARGET_EXTRA */
+} 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.*/
+	time_in_ms_t jitter; 		/* jitter measured within current history interval*/
+	time_in_ms_t min;		/* minimum lateness within current history interval */
+	time_in_ms_t current; 		/* the present jitterbuffer adjustment */
+	time_in_ms_t target; 		/* the target jitterbuffer adjustment */
+	long losspct;		/* recent lost frame percentage (* 1000) */
+	time_in_ms_t 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 */
+	time_in_ms_t silence_begin_ts;	/* the time of the last CNG frame, when in silence */
+	time_in_ms_t last_adjustment;   /* the time of the last adjustment */
+	time_in_ms_t last_delay;        /* the last now added to history */
+	long cnt_delay_discont;	/* the count of discontinuous delays */
+	time_in_ms_t 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 */
+	time_in_ms_t ts;	/* the relative delivery time expected */
+	long ms;                  /* the time covered by this frame, in sec/8000 */
+	enum jb_frame_type type;  /* the type of frame */
+	struct jb_frame *next, *prev;
+} jb_frame;
+
+typedef struct jitterbuf {
+	jb_info info;
+
+	/* history */
+	time_in_ms_t history[JB_HISTORY_SZ];   		/* history */
+	int  hist_ptr;				/* points to index in history for next entry */
+	time_in_ms_t hist_maxbuf[JB_HISTORY_MAXBUF_SZ];	/* a sorted buffer of the max delays (highest first) */
+	time_in_ms_t 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 */
+jitterbuf *		jb_new(void);
+
+/* destroy jitterbuf */
+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 */
+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
+ */
+enum jb_return_code jb_put(jitterbuf *jb, void *data, const enum jb_frame_type type, long ms, time_in_ms_t ts, time_in_ms_t 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.
+ */
+enum jb_return_code jb_get(jitterbuf *jb, jb_frame *frame, time_in_ms_t now, long interpl);
+
+/* unconditionally get frames from jitterbuf until empty */
+enum jb_return_code 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) */
+time_in_ms_t			jb_next(jitterbuf *jb);
+
+/* get jitterbuf info: only "statistics" may be valid */
+enum jb_return_code jb_getinfo(jitterbuf *jb, jb_info *stats);
+
+/* set jitterbuf conf */
+enum jb_return_code 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

Added: freeswitch/trunk/src/mod/endpoints/mod_iax/md5.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/md5.c	Thu May  8 19:25:36 2008
@@ -0,0 +1,297 @@
+/* MD5 checksum routines used for authentication.  Not covered by GPL, but
+   in the public domain as per the copyright below */
+
+#ifdef FREEBSD
+# include <machine/endian.h>
+#elif defined(LINUX)  
+# include <endian.h>
+# 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> /* 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
+
+#ifdef _MSC_VER
+#ifndef __LITTLE_ENDIAN
+#define __LITTLE_ENDIAN 1234
+#endif
+#ifndef __BIG_ENDIAN
+#define __BIG_ENDIAN 4321
+#endif
+#ifndef __BYTE_ORDER
+#define __BYTE_ORDER __LITTLE_ENDIAN
+#endif
+#endif
+
+#if __BYTE_ORDER == __BIG_ENDIAN || BYTE_ORDER == BIG_ENDIAN
+# define HIGHFIRST 1
+#elif __BYTE_ORDER == __LITTLE_ENDIAN || BYTE_ORDER == LITLE_ENDIAN
+# undef HIGHFIRST
+#else
+# error "Please fix <bits/endian.h>"
+#endif
+
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+#include <string.h>		/* for memcpy() */
+#include "md5.h"
+
+#ifndef HIGHFIRST
+#define byteReverse(buf, len)	/* Nothing */
+#else
+void byteReverse(unsigned char *buf, unsigned longs);
+
+#ifndef ASM_MD5
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+void byteReverse(unsigned char *buf, unsigned longs)
+{
+    uint32 t;
+    do {
+	t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+	    ((unsigned) buf[1] << 8 | buf[0]);
+	*(uint32 *) buf = t;
+	buf += 4;
+    } while (--longs);
+}
+#endif
+#endif
+
+/*
+ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void MD5Init(struct MD5Context *ctx)
+{
+    ctx->buf[0] = 0x67452301;
+    ctx->buf[1] = 0xefcdab89;
+    ctx->buf[2] = 0x98badcfe;
+    ctx->buf[3] = 0x10325476;
+
+    ctx->bits[0] = 0;
+    ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
+{
+    uint32 t;
+
+    /* Update bitcount */
+
+    t = ctx->bits[0];
+    if ((ctx->bits[0] = t + ((uint32) len << 3)) < t)
+	ctx->bits[1]++;		/* Carry from low to high */
+    ctx->bits[1] += len >> 29;
+
+    t = (t >> 3) & 0x3f;	/* Bytes already in shsInfo->data */
+
+    /* Handle any leading odd-sized chunks */
+
+    if (t) {
+	unsigned char *p = (unsigned char *) ctx->in + t;
+
+	t = 64 - t;
+	if (len < t) {
+	    memcpy(p, buf, len);
+	    return;
+	}
+	memcpy(p, buf, t);
+	byteReverse(ctx->in, 16);
+	MD5Transform(ctx->buf, (uint32 *) ctx->in);
+	buf += t;
+	len -= t;
+    }
+    /* Process data in 64-byte chunks */
+
+    while (len >= 64) {
+	memcpy(ctx->in, buf, 64);
+	byteReverse(ctx->in, 16);
+	MD5Transform(ctx->buf, (uint32 *) ctx->in);
+	buf += 64;
+	len -= 64;
+    }
+
+    /* Handle any remaining bytes of data. */
+
+    memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern 
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
+{
+    unsigned count;
+    unsigned char *p;
+
+    /* Compute number of bytes mod 64 */
+    count = (ctx->bits[0] >> 3) & 0x3F;
+
+    /* Set the first char of padding to 0x80.  This is safe since there is
+       always at least one byte free */
+    p = ctx->in + count;
+    *p++ = 0x80;
+
+    /* Bytes of padding needed to make 64 bytes */
+    count = 64 - 1 - count;
+
+    /* Pad out to 56 mod 64 */
+    if (count < 8) {
+	/* Two lots of padding:  Pad the first block to 64 bytes */
+	memset(p, 0, count);
+	byteReverse(ctx->in, 16);
+	MD5Transform(ctx->buf, (uint32 *) ctx->in);
+
+	/* Now fill the next block with 56 bytes */
+	memset(ctx->in, 0, 56);
+    } else {
+	/* Pad block to 56 bytes */
+	memset(p, 0, count - 8);
+    }
+    byteReverse(ctx->in, 14);
+
+    /* Append length in bits and transform */
+    ((uint32 *) ctx->in)[14] = ctx->bits[0];
+    ((uint32 *) ctx->in)[15] = ctx->bits[1];
+
+    MD5Transform(ctx->buf, (uint32 *) ctx->in);
+    byteReverse((unsigned char *) ctx->buf, 4);
+    memcpy(digest, ctx->buf, 16);
+    memset(ctx, 0, sizeof(ctx));	/* In case it's sensitive */
+}
+
+#ifndef ASM_MD5
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+	( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data.  MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void MD5Transform(uint32 buf[4], uint32 const in[16])
+{
+    register uint32 a, b, c, d;
+
+    a = buf[0];
+    b = buf[1];
+    c = buf[2];
+    d = buf[3];
+
+    MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+    MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+    MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+    MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+    MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+    MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+    MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+    MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+    MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+    MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+    MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+    MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+    MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+    MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+    MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+    MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+    MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+    MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+    MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+    MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+    MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+    MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+    MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+    MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+    MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+    MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+    MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+    MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+    MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+    MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+    MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+    MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+    MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+    MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+    MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+    MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+    MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+    MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+    MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+    MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+    MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+    MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+    MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+    MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+    MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+    MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+    MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+    MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+    MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+    MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+    MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+    MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+    MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+    MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+    MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+    MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+    MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+    MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+    MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+    MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+    MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+    MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+    MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+    MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+    buf[0] += a;
+    buf[1] += b;
+    buf[2] += c;
+    buf[3] += d;
+}
+
+#endif

Added: freeswitch/trunk/src/mod/endpoints/mod_iax/md5.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/md5.h	Thu May  8 19:25:36 2008
@@ -0,0 +1,27 @@
+#ifndef MD5_H
+#define MD5_H
+
+#if defined(__alpha) || defined(__x86_64)
+typedef unsigned int uint32;
+#else
+typedef unsigned long uint32;
+#endif
+
+struct MD5Context {
+	uint32 buf[4];
+	uint32 bits[2];
+	unsigned char in[64];
+};
+
+void MD5Init(struct MD5Context *context);
+void MD5Update(struct MD5Context *context, unsigned char const *buf,
+	       unsigned len);
+void MD5Final(unsigned char digest[16], struct MD5Context *context);
+void MD5Transform(uint32 buf[4], uint32 const in[16]);
+
+/*
+ * This is needed to make RSAREF happy on some MS-DOS compilers.
+ */
+typedef struct MD5Context MD5_CTX;
+
+#endif /* !MD5_H */

Added: freeswitch/trunk/src/mod/endpoints/mod_iax/winiphone.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/winiphone.c	Thu May  8 19:25:36 2008
@@ -0,0 +1,761 @@
+/*
+ * Miniphone: A simple, command line telephone
+ *
+ * IAX Support for talking to Asterisk and other Gnophone clients
+ *
+ * Copyright (C) 1999, Linux Support Services, Inc.
+ *
+ * Mark Spencer <markster at linux-support.net>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License
+ */
+
+/* #define	PRINTCHUCK /* enable this to indicate chucked incomming packets */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <io.h>
+#include <conio.h>
+#include <stdio.h>
+#include <errno.h>
+#include <time.h>
+#include <process.h>
+#include <windows.h>
+#include <winsock.h>
+#include <mmsystem.h>
+#include <malloc.h>
+#include "gsm.h"
+#include "iax-client.h"
+#include "frame.h"
+#include "miniphone.h"
+
+
+struct peer {
+	int time;
+	gsm gsmin;
+	gsm gsmout;
+
+	struct iax_session *session;
+	struct peer *next;
+};
+
+static struct peer *peers;
+static int answered_call = 0;
+
+/* stuff for wave audio device */
+HWAVEOUT wout;
+HWAVEIN win;
+
+typedef struct whout {
+	WAVEHDR w;
+	short	data[160];
+	struct whout *next;
+} WHOUT;
+
+WHOUT *outqueue = NULL;
+
+/* parameters for audio in */
+#define	NWHIN 8				/* number of input buffer entries */
+/* NOTE the OUT_INTERVAL parameter *SHOULD* be more around 18 to 20 or so, since the packets should
+be spaced by 20 milliseconds. However, in practice, especially in Windoze-95, setting it that high
+caused underruns. 10 is just ever so slightly agressive, and the receiver has to chuck a packet
+every now and then. Thats about the way it should be to be happy. */
+#define	OUT_INTERVAL 10		/* number of ms to wait before sending more data to peer */
+/* parameters for audio out */
+#define	OUT_DEPTH 12		/* number of outbut buffer entries */
+#define	OUT_PAUSE_THRESHOLD 2 /* number of active entries needed to start output (for smoothing) */
+
+/* audio input buffer headers */
+WAVEHDR whin[NWHIN];
+/* audio input buffers */
+char bufin[NWHIN][320];
+
+/* initialize the sequence variables for the audio in stuff */
+unsigned int whinserial = 1,nextwhin = 1;
+
+static struct peer *find_peer(struct iax_session *);
+static void parse_args(FILE *, unsigned char *);
+void do_iax_event(FILE *);
+void call(FILE *, char *);
+void answer_call(void);
+void reject_call(void);
+static void handle_event(FILE *, struct iax_event *e, struct peer *p);
+void parse_cmd(FILE *, int, char **);
+void issue_prompt(FILE *);
+void dump_array(FILE *, char **);
+
+static char *help[] = {
+"Welcome to the miniphone telephony client, the commands are as follows:\n",
+"Help\t\t-\tDisplays this screen.",
+"Call <Number>\t-\tDials the number supplied.",
+"Answer\t\t-\tAnswers an Inbound call.",
+"Reject\t\t-\tRejects an Inbound call.",
+"Dump\t\t-\tDumps (disconnects) the current call.",
+"Dtmf <Digit>\t-\tSends specified DTMF digit.",
+"Status\t\t-\tLists the current sessions and their current status.",
+"Quit\t\t-\tShuts down the client.",
+"",
+0
+};
+
+static struct peer *most_recent_answer;
+static struct iax_session *newcall = 0;
+
+/* holder of the time, relative to startup in system ticks. See our
+gettimeofday() implementation */
+time_t	startuptime;
+
+/* routine called at exit to shutdown audio I/O and close nicely.
+NOTE: If all this isnt done, the system doesnt not handle this
+cleanly and has to be rebooted. What a pile of doo doo!! */
+void killem(void)
+{
+	waveInStop(win);
+	waveInReset(win);
+	waveInClose(win); 
+	waveOutReset(wout);
+	waveOutClose(wout);
+	WSACleanup(); /* dont forget socket stuff too */
+	return;
+}
+
+/* Win-doze doenst have gettimeofday(). This sux. So, what we did is
+provide some gettimeofday-like functionality that works for our purposes.
+In the main(), we take a sample of the system tick counter (into startuptime).
+This function returns the relative time since program startup, more or less,
+which is certainly good enough for our purposes. */
+void gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+	long l = startuptime + GetTickCount();
+
+	tv->tv_sec = l / 1000;
+	tv->tv_usec = (l % 1000) * 1000;
+	return;
+}
+
+
+static struct peer *find_peer(struct iax_session *session)
+{
+	struct peer *cur = peers;
+	while(cur) {
+		if (cur->session == session)
+			return cur;
+		cur = cur->next;
+	}
+	return NULL;
+}
+
+void
+parse_args(FILE *f, unsigned char *cmd)
+{
+	static char *argv[MAXARGS];
+	unsigned char *parse = cmd;
+	int argc = 0, t = 0;
+
+	// Don't mess with anything that doesn't exist...
+	if(!*parse)
+		return;
+
+	memset(argv, 0, sizeof(argv));
+	while(*parse) {
+		if(*parse < 33 || *parse > 128) {
+			*parse = 0, t++;
+			if(t > MAXARG) {
+				fprintf(f, "Warning: Argument exceeds maximum argument size, command ignored!\n");
+				return;
+			}
+		} else if(t || !argc) {
+			if(argc == MAXARGS) {
+				fprintf(f, "Warning: Command ignored, too many arguments\n");
+				return;
+			}
+			argv[argc++] = parse;
+			t = 0;
+		}
+
+		parse++;
+	}
+
+	if(argc)
+		parse_cmd(f, argc, argv);
+}
+
+/* handle all network requests, and a pending scheduled event, if any */
+void service_network(int netfd, FILE *f)
+{
+	fd_set readfd;
+	struct timeval dumbtimer;
+
+	/* set up a timer that falls-through */
+	dumbtimer.tv_sec = 0;
+	dumbtimer.tv_usec = 0;
+
+
+		for(;;) /* suck everything outa network stuff */
+		{
+			FD_ZERO(&readfd);
+			FD_SET(netfd, &readfd);
+			if (select(netfd + 1, &readfd, 0, 0, &dumbtimer) > 0)
+			{
+				if (FD_ISSET(netfd,&readfd))
+				{
+					do_iax_event(f);
+					(void) iax_time_to_next_event();
+				} else break;
+			} else break;
+		}
+		do_iax_event(f); /* do pending event if any */
+}
+
+
+int
+main(int argc, char *argv[])
+{
+	int port;
+	int netfd;
+ 	int c, i;
+	FILE *f;
+	char rcmd[RBUFSIZE];
+	gsm_frame fo;
+	WSADATA foop;
+	time_t	t;
+	WAVEFORMATEX wf;
+	WHOUT *wh,*wh1,*wh2;
+	unsigned long lastouttick = 0;
+
+
+
+	/* get time of day in milliseconds, offset by tick count (see our
+	   gettimeofday() implementation) */
+	time(&t);
+	startuptime = ((t % 86400) * 1000) - GetTickCount();
+
+	f = stdout;
+	_dup2(fileno(stdout),fileno(stderr));
+
+	/* start up the windoze-socket layer stuff */
+	if (WSAStartup(0x0101,&foop)) {
+		fprintf(stderr,"Fatal error: Falied to startup windows sockets\n");
+		return -1;
+	}
+
+
+	/* setup the format for opening audio channels */
+	wf.wFormatTag = WAVE_FORMAT_PCM;
+	wf.nChannels = 1;
+	wf.nSamplesPerSec = 8000;
+	wf.nAvgBytesPerSec = 16000;
+	wf.nBlockAlign = 2;
+	wf.wBitsPerSample = 16;
+	wf.cbSize = 0;
+	/* open the audio out channel */
+	if (waveOutOpen(&wout,0,&wf,0,0,CALLBACK_NULL) != MMSYSERR_NOERROR)
+		{
+			fprintf(stderr,"Fatal Error: Failed to open wave output device\n");
+			return -1;
+		}
+	/* open the audio in channel */
+	if (waveInOpen(&win,0,&wf,0,0,CALLBACK_NULL) != MMSYSERR_NOERROR)
+		{
+			fprintf(stderr,"Fatal Error: Failed to open wave input device\n");
+			waveOutReset(wout);
+			waveOutClose(wout);
+			return -1;
+		}
+	/* activate the exit handler */
+	atexit(killem);
+	/* initialize the audio in buffer structures */
+	memset(&whin,0,sizeof(whin));
+
+	if ( (port = iax_init(0) < 0)) {
+		fprintf(stderr, "Fatal error: failed to initialize iax with port %d\n", port);
+		return -1;
+	}
+
+
+	iax_set_formats(AST_FORMAT_GSM);
+	netfd = iax_get_fd();
+
+	fprintf(f, "Text Based Telephony Client.\n\n");
+	issue_prompt(f);
+
+	/* main tight loop */
+	while(1) {
+		/* service the network stuff */
+		service_network(netfd,f);
+		if (outqueue) /* if stuff in audio output queue, free it up if its available */
+		{
+			/* go through audio output queue */
+			for(wh = outqueue,wh1 = wh2 = NULL,i = 0; wh != NULL; wh = wh->next)
+			{
+				service_network(netfd,f); /* service network here for better performance */
+				/* if last one was removed from queue, zot it here */
+				if (i && wh1)
+				{ 
+					free(wh1);
+					wh1 = wh2;
+				}
+				i = 0; /* reset "last one removed" flag */
+				if (wh->w.dwFlags & WHDR_DONE) /* if this one is done */
+				{
+					/* prepare audio header */
+					if ((c = waveOutUnprepareHeader(wout,&wh->w,sizeof(WAVEHDR))) != MMSYSERR_NOERROR)
+					{ 
+						fprintf(stderr,"Cannot unprepare audio out header, error %d\n",c);
+						exit(255);
+					}
+					if (wh1 != NULL) /* if there was a last one */
+					{
+						wh1->next = wh->next;
+					} 
+					if (outqueue == wh) /* is first one, so set outqueue to next one */
+					{
+						outqueue = wh->next;
+					}
+					i = 1; /* set 'to free' flag */
+				}
+				wh2 = wh1;	/* save old,old wh pointer */
+				wh1 = wh; /* save the old wh pointer */
+			}
+		}
+		/* go through all audio in buffers, and prepare and queue ones that are currently idle */
+		for(i = 0; i < NWHIN; i++)
+		{
+			service_network(netfd,f); /* service network stuff here for better performance */
+			if (!(whin[i].dwFlags & WHDR_PREPARED)) /* if not prepared, do so */
+			{
+				/* setup this input buffer header */
+				memset(&whin[i],0,sizeof(WAVEHDR));
+				whin[i].lpData = bufin[i];
+				whin[i].dwBufferLength = 320;
+				whin[i].dwUser = whinserial++; /* set 'user data' to current serial number */
+				/* prepare the buffer */
+				if (waveInPrepareHeader(win,&whin[i],sizeof(WAVEHDR)))
+				{
+					fprintf(stderr,"Unable to prepare header for input\n");
+					return -1;
+				}
+				/* add it to device (queue) */
+				if (waveInAddBuffer(win,&whin[i],sizeof(WAVEHDR)))
+				{
+					fprintf(stderr,"Unable to prepare header for input\n");
+					return -1;
+				}
+			}
+			waveInStart(win); /* start it (if not already started) */
+		}
+		
+		/* if key pressed, do command stuff */
+		if(_kbhit())
+		{
+				if ( ( fgets(&*rcmd, 256, stdin))) {
+					rcmd[strlen(rcmd)-1] = 0;
+					parse_args(f, &*rcmd);
+				} else fprintf(f, "Fatal error: failed to read data!\n");
+
+				issue_prompt(f);
+		}
+		/* do audio input stuff for buffers that have received data from audio in device already. Must
+			do them in serial number order (the order in which they were originally queued). */
+		if(answered_call) /* send audio only if call answered */
+		{
+			for(;;) /* loop until all are found */
+			{
+				for(i = 0; i < NWHIN; i++) /* find an available one that's the one we are looking for */
+				{
+					service_network(netfd,f); /* service network here for better performance */
+					/* if not time to send any more, dont */
+					if (GetTickCount() < (lastouttick + OUT_INTERVAL))
+					{
+						i = NWHIN; /* set to value that WILL exit loop */
+						break;
+					}
+					if ((whin[i].dwUser == nextwhin) && (whin[i].dwFlags & WHDR_DONE)) { /* if audio is ready */
+
+						/* must have read exactly 320 bytes */
+						if (whin[i].dwBytesRecorded != whin[i].dwBufferLength)
+						{
+							fprintf(stderr,"Short audio read, got %d bytes, expected %d bytes\n", whin[i].dwBytesRecorded,
+								whin[i].dwBufferLength);
+							return -1;
+						}
+						if(!most_recent_answer->gsmout)
+								most_recent_answer->gsmout = gsm_create();
+
+						service_network(netfd,f); /* service network here for better performance */
+						/* encode the audio from the buffer into GSM format */
+						gsm_encode(most_recent_answer->gsmout, (short *) ((char *) whin[i].lpData), fo);
+						if(iax_send_voice(most_recent_answer->session,
+							AST_FORMAT_GSM, (char *)fo, sizeof(gsm_frame)) == -1)
+									puts("Failed to send voice!"); 
+						lastouttick = GetTickCount(); /* save time of last output */
+
+						/* unprepare (free) the header */
+						waveInUnprepareHeader(win,&whin[i],sizeof(WAVEHDR));
+						/* initialize the buffer */
+						memset(&whin[i],0,sizeof(WAVEHDR));
+						/* bump the serial number to look for the next time */
+						nextwhin++;
+						/* exit the loop so that we can start at lowest buffer again */
+						break;
+					}
+				} 
+				if (i >= NWHIN) break; /* if all found, get out of loop */
+			}
+		}
+
+	}
+	return 0;
+}
+
+void
+do_iax_event(FILE *f) {
+	int sessions = 0;
+	struct iax_event *e = 0;
+	struct peer *peer;
+
+	while ( (e = iax_get_event(0))) {
+		peer = find_peer(e->session);
+		if(peer) {
+			handle_event(f, e, peer);
+		} else {
+			if(e->etype != IAX_EVENT_CONNECT) {
+				fprintf(stderr, "Huh? This is an event for a non-existant session?\n");
+			}
+			sessions++;
+
+			if(sessions >= MAX_SESSIONS) {
+				fprintf(f, "Missed a call... too many sessions open.\n");
+			}
+
+
+			if(e->event.connect.callerid && e->event.connect.dnid)
+				fprintf(f, "Call from '%s' for '%s'", e->event.connect.callerid, 
+				e->event.connect.dnid);
+			else if(e->event.connect.dnid) {
+				fprintf(f, "Call from '%s'", e->event.connect.dnid);
+			} else if(e->event.connect.callerid) {
+				fprintf(f, "Call from '%s'", e->event.connect.callerid);
+			} else printf("Call from");
+			fprintf(f, " (%s)\n", inet_ntoa(iax_get_peer_addr(e->session).sin_addr));
+
+			if(most_recent_answer) {
+				fprintf(f, "Incoming call ignored, there's already a call waiting for answer... \
+please accept or reject first\n");
+				iax_reject(e->session, "Too many calls, we're busy!");
+			} else {
+				if ( !(peer = malloc(sizeof(struct peer)))) {
+					fprintf(f, "Warning: Unable to allocate memory!\n");
+					return;
+				}
+
+				peer->time = time(0);
+				peer->session = e->session;
+				peer->gsmin = 0;
+				peer->gsmout = 0;
+
+				peer->next = peers;
+				peers = peer;
+
+				iax_accept(peer->session);
+				iax_ring_announce(peer->session);
+				most_recent_answer = peer;
+				fprintf(f, "Incoming call!\n");
+			}
+			iax_event_free(e);
+			issue_prompt(f);
+		}
+	}
+}
+
+void
+call(FILE *f, char *num)
+{
+	struct peer *peer;
+
+	if(!newcall)
+		newcall = iax_session_new();
+	else {
+		fprintf(f, "Already attempting to call somewhere, please cancel first!\n");
+		return;
+	}
+
+	if ( !(peer = malloc(sizeof(struct peer)))) {
+		fprintf(f, "Warning: Unable to allocate memory!\n");
+		return;
+	}
+
+	peer->time = time(0);
+	peer->session = newcall;
+	peer->gsmin = 0;
+	peer->gsmout = 0;
+
+	peer->next = peers;
+	peers = peer;
+
+	most_recent_answer = peer;
+
+	iax_call(peer->session, num, 10);
+}
+
+void
+answer_call(void)
+{
+	if(most_recent_answer)
+		iax_answer(most_recent_answer->session);
+	printf("Answering call!\n");
+	answered_call = 1;
+}
+
+void
+dump_call(void)
+{
+	if(most_recent_answer)
+	{
+		iax_hangup(most_recent_answer->session,"");
+		free(most_recent_answer);
+	}
+	printf("Dumping call!\n");
+	answered_call = 0;
+	most_recent_answer = 0;
+	answered_call = 0;
+	peers = 0;
+	newcall = 0;
+}
+
+void
+reject_call(void)
+{
+	iax_reject(most_recent_answer->session, "Call rejected manually.");
+	most_recent_answer = 0;
+}
+
+void
+handle_event(FILE *f, struct iax_event *e, struct peer *p)
+{
+	int len,n;
+	WHOUT *wh,*wh1;
+	short fr[160];
+	static paused_xmit = 0;
+
+
+	switch(e->etype) {
+		case IAX_EVENT_HANGUP:
+			iax_hangup(most_recent_answer->session, "Byeee!");
+			fprintf(f, "Call disconnected by peer\n");
+			free(most_recent_answer);
+			most_recent_answer = 0;
+			answered_call = 0;
+			peers = 0;
+			newcall = 0;
+			
+			break;
+
+		case IAX_EVENT_REJECT:
+			fprintf(f, "Authentication was rejected\n");
+			break;
+		case IAX_EVENT_ACCEPT:
+			fprintf(f, "Waiting for answer... RING RING\n");
+			issue_prompt(f);
+			break;
+		case IAX_EVENT_ANSWER:
+			answer_call();
+ 			break;
+		case IAX_EVENT_VOICE:
+			switch(e->event.voice.format) {
+				case AST_FORMAT_GSM:
+					if(e->event.voice.datalen % 33) {
+						fprintf(stderr, "Weird gsm frame, not a multiple of 33.\n");
+						break;
+					}
+
+					if (!p->gsmin)
+						p->gsmin = gsm_create();
+
+					len = 0;
+					while(len < e->event.voice.datalen) {
+						if(gsm_decode(p->gsmin, (char *) e->event.voice.data + len, fr)) {
+							fprintf(stderr, "Bad GSM data\n");
+							break;
+						} else {  /* its an audio packet to be output to user */
+
+							/* get count of pending items in audio output queue */
+							n = 0; 
+							if (outqueue) 
+							{	/* determine number of pending out queue items */
+								for(wh = outqueue; wh != NULL; wh = wh->next)
+								{
+									if (!(wh->w.dwFlags & WHDR_DONE)) n++;
+								}
+							}
+							/* if not too many, send to user, otherwise chuck packet */
+							if (n <= OUT_DEPTH) /* if not to chuck packet */
+							{
+								/* malloc the memory for the queue item */
+								wh = (WHOUT *) malloc(sizeof(WHOUT));
+								if (wh == (WHOUT *) NULL) /* if error, bail */
+								{
+									fprintf(stderr,"Outa memory!!!!\n");
+									exit(255);
+								}
+								/* initialize the queue entry */
+								memset(wh,0,sizeof(WHOUT));
+								/* copy the PCM data from the gsm conversion buffer */
+								memcpy((char *)wh->data,(char *)fr,sizeof(fr));
+								/* set parameters for data */
+								wh->w.lpData = (char *) wh->data;
+								wh->w.dwBufferLength = 320;
+								
+								/* prepare buffer for output */
+								if (waveOutPrepareHeader(wout,&wh->w,sizeof(WAVEHDR)))
+								{
+									fprintf(stderr,"Cannot prepare header for audio out\n");
+									exit(255);
+								}
+								/* if not currently transmitting, hold off a couple of packets for 
+									smooth sounding output */
+								if ((!n) && (!paused_xmit))
+								{
+									/* pause output (before starting) */
+									waveOutPause(wout);
+									/* indicate as such */
+									paused_xmit = 1;
+								}
+								/* queue packet for output on audio device */
+								if (waveOutWrite(wout,&wh->w,sizeof(WAVEHDR)))
+								{
+									fprintf(stderr,"Cannot output to wave output device\n");
+									exit(255);
+								}
+								/* if we are paused, and we have enough packets, start audio */
+								if ((n > OUT_PAUSE_THRESHOLD) && paused_xmit)
+								{
+									/* start the output */
+									waveOutRestart(wout);
+									/* indicate as such */
+									paused_xmit = 0;
+								}
+								/* insert it onto tail of outqueue */
+								if (outqueue == NULL) /* if empty queue */
+									outqueue = wh; /* point queue to new entry */
+								else /* otherwise is non-empty queue */
+								{
+									wh1 = outqueue;
+									while(wh1->next) wh1 = wh1->next; /* find last entry in queue */
+									wh1->next = wh; /* point it to new entry */
+								}
+							} 
+#ifdef	PRINTCHUCK
+							else printf("Chucking packet!!\n");
+#endif
+						}
+						len += 33;
+					}
+					break;
+				default :
+					fprintf(f, "Don't know how to handle that format %d\n", e->event.voice.format);
+			}
+			break;
+		case IAX_EVENT_RINGA:
+			break;
+		default:
+			fprintf(f, "Unknown event: %d\n", e->etype);
+			break;
+	}
+}
+
+void
+parse_cmd(FILE *f, int argc, char **argv)
+{
+	_strupr(argv[0]);
+	if(!strcmp(argv[0], "HELP")) {
+		if(argc == 1)
+			dump_array(f, help);
+		else if(argc == 2) {
+			if(!strcmp(argv[1], "HELP"))
+				fprintf(f, "Help <Command>\t-\tDisplays general help or specific help on command if supplied an arguement\n");
+			else if(!strcmp(argv[1], "QUIT"))
+				fprintf(f, "Quit\t\t-\tShuts down the miniphone\n");
+			else fprintf(f, "No help available on %s\n", argv[1]);
+		} else {
+			fprintf(f, "Too many arguements for command help.\n");
+		}
+	} else if(!strcmp(argv[0], "STATUS")) {
+		if(argc == 1) {
+			int c = 0;
+			struct peer *peerptr = peers;
+
+			if(!peerptr)
+				fprintf(f, "No session matches found.\n");
+			else while(peerptr) {
+	 			fprintf(f, "Listing sessions:\n\n");
+				fprintf(f, "Session %d\n", ++c);
+				fprintf(f, "Session existed for %d seconds\n", (int)time(0)-peerptr->time);
+				if(answered_call)
+					fprintf(f, "Call answered.\n");
+				else fprintf(f, "Call ringing.\n");
+
+				peerptr = peerptr->next;
+			}
+		} else fprintf(f, "Too many arguments for command status.\n");
+	} else if(!strcmp(argv[0], "ANSWER")) {
+		if(argc > 1)
+			fprintf(f, "Too many arguements for command answer\n");
+		else answer_call();
+	} else if(!strcmp(argv[0], "REJECT")) {
+		if(argc > 1)
+			fprintf(f, "Too many arguements for command reject\n");
+		else {
+			fprintf(f, "Rejecting current phone call.\n");
+			reject_call();
+		}
+	} else if(!strcmp(argv[0], "CALL")) {
+		if(argc > 2)
+			fprintf(f, "Too many arguements for command call\n");
+		else {
+			call(f, argv[1]);
+		}
+	} else if(!strcmp(argv[0], "DUMP")) {
+		if(argc > 1)
+			fprintf(f, "Too many arguements for command dump\n");
+		else {
+			dump_call();
+		}
+	} else if(!strcmp(argv[0], "DTMF")) {
+		if(argc > 2)
+		{
+			fprintf(f, "Too many arguements for command dtmf\n");
+			return;
+		}
+		if (argc < 1)
+		{
+			fprintf(f, "Too many arguements for command dtmf\n");
+			return;
+		}
+		if(most_recent_answer)
+				iax_send_dtmf(most_recent_answer->session,*argv[1]);
+	} else if(!strcmp(argv[0], "QUIT")) {
+		if(argc > 1)
+			fprintf(f, "Too many arguements for command quit\n");
+		else {
+			fprintf(f, "Good bye!\n");
+			exit(1);
+		}
+	} else fprintf(f, "Unknown command of %s\n", argv[0]);
+}
+
+void
+issue_prompt(FILE *f)
+{
+	fprintf(f, "TeleClient> ");
+	fflush(f);
+}
+
+void
+dump_array(FILE *f, char **array) {
+	while(*array)
+		fprintf(f, "%s\n", *array++);
+}

Added: freeswitch/trunk/src/mod/endpoints/mod_iax/winpoop.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/winpoop.h	Thu May  8 19:25:36 2008
@@ -0,0 +1,40 @@
+/* 
+ * Functions Windows doesn't have... but should
+ * Copyright(C) 2001, Linux Support Services, Inc.
+ *
+ * Distributed under GNU LGPL.
+ *
+ * These are NOT fully compliant with BSD 4.3 and are not
+ * threadsafe.
+ *
+ */
+
+#ifndef _winpoop_h
+#define _winpoop_h
+
+#if defined(_MSC_VER)
+#define INLINE __inline
+#else
+#define INLINE inline
+#endif
+
+#include <winsock.h>
+
+void gettimeofday(struct timeval *tv, void /*struct timezone*/ *tz);
+
+static INLINE int inet_aton(char *cp, struct in_addr *inp)
+{
+	int a1, a2, a3, a4;
+	unsigned int saddr;
+	if (sscanf(cp, "%d.%d.%d.%d", &a1, &a2, &a3, &a4) != 4)
+		return 0;
+	a1 &= 0xff;
+	a2 &= 0xff;
+	a3 &= 0xff;
+	a4 &= 0xff; 
+	saddr = (a1 << 24) | (a2 << 16) | (a3 << 8) | a4;
+	inp->s_addr = htonl(saddr);
+	return 1;
+}
+
+#endif



More information about the Freeswitch-svn mailing list