+++ /dev/null
-include $(top_srcdir)/build/modmake.rulesam
-MODNAME=mod_iax
-
-mod_LTLIBRARIES = mod_iax.la
-mod_iax_la_SOURCES = mod_iax.c iax2-parser.c iax.c md5.c jitterbuf.c iax-mutex.c
-mod_iax_la_CFLAGS = $(AM_CFLAGS) -I. -DNEWJB -DLIBIAX -DDEBUG_SUPPORT
-mod_iax_la_LIBADD = $(switch_builddir)/libfreeswitch.la
-mod_iax_la_LDFLAGS = -avoid-version -module -no-undefined -shared
+++ /dev/null
-/*
- * 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 };
+++ /dev/null
-/*
- * libiax: An implementation of the Inter-Asterisk eXchange protocol
- *
- * Asterisk internal frame definitions.
- *
- * Copyright (C) 1999, Mark Spencer
- *
- * Mark Spencer <markster@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
+++ /dev/null
-/*
- * Asterisk -- A telephony toolkit for Linux.
- *
- * Implementation of Inter-Asterisk eXchange
- *
- * Copyright (C) 1999, Mark Spencer
- *
- * Mark Spencer <markster@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 */
+++ /dev/null
-/*
- * 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;
-}
+++ /dev/null
-/*
- * 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
+++ /dev/null
- /*
- * libiax: An implementation of Inter-Asterisk eXchange
- *
- * Copyright (C) 2001, Linux Support Services, Inc.
- *
- * Mark Spencer <markster@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 = (unsigned char) (data[byte] << (n - rem));
- ret |= (data[byte + 1] >> (8 - n + rem));
- } else {
- ret = (unsigned char) (data[byte] >> (rem - n));
- }
-
- return (unsigned char) (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;
-#ifdef WIN32
- socklen_t sinlen;
-#else
- unsigned int sinlen;
-#endif
- 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 (unsigned char) 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 (unsigned char) (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 = (unsigned short) 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 = (unsigned char) fr->oseqno;
- if (transfer) {
- fh->iseqno = 0;
- } else
- fh->iseqno = (unsigned char) fr->iseqno;
- /* Keep track of the last thing we've acknowledged */
- pvt->aseqno = (unsigned char) fr->iseqno;
- fh->type = (char) (fr->af.frametype & 0xFF);
- fh->csub = compress_subclass(fr->af.subclass);
- if (transfer) {
- fr->dcallno = (unsigned short) pvt->transfercallno;
- } else
- fr->dcallno = (unsigned short) 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, (unsigned short) 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, (unsigned short) 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((short) s0->transferpeer);
-
- if (s1 != NULL && s1->callno == s0->transferpeer && s0->transferring == TRANSFER_REL && s1->transferring == TRANSFER_REL) {
-
- s0_org_peer = (short) s0->peercallno;
- s1_org_peer = (short) 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((short) 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((unsigned short) 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, (unsigned short) 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, (unsigned short) 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, (unsigned short) 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) {
- unsigned char x;
- for (x = 0; x < 32; x++) {
- if ((unsigned) (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++] = (char) ((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 = (char) (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((unsigned short) 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;
-#ifndef __Linux__
- socklen_t sinlen;
-#else
- unsigned int sinlen;
-#endif
- struct sockaddr_in sin;
-
- sinlen = sizeof(sin);
- res = iax_recvfrom(netfd, (char *) 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 == (int) ies.transferid) && (cur->callno == dcallno) && (cur->transfercallno == callno)) {
- /* We're transferring ---
- * skip address/port checking which would fail while remote peer behind symmetric NAT
- * verify transferid instead
- */
- cur->transfer.sin_addr.s_addr = sin->sin_addr.s_addr; /* setup for further handling */
- cur->transfer.sin_port = sin->sin_port;
- break;
- }
- }
- 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);
-}
+++ /dev/null
-/*
- * libIAX
- *
- * Implementation of Inter-IAXerisk eXchange
- *
- * Copyright (C) 1999, Mark Spencer
- *
- * Mark Spencer <markster@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
+++ /dev/null
-/*
- * Asterisk -- A telephony toolkit for Linux.
- *
- * Implementation of Inter-Asterisk eXchange
- *
- * Copyright (C) 2003-2004, Digium
- *
- * Mark Spencer <markster@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 frame_count = 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("%s", 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",
- "CONGSTN",
- "FLASH ",
- "WINK ",
- "OPTION ",
- "RDKEY ",
- "RDUNKEY",
- "PROGRES",
- "PROCDNG",
- "HOLD ",
- "UNHOLD ",
- "VIDUPDT",
- "T38 ",
- "SRCUPDT",
- "TXFER ",
- "CNLINE ",
- "REDIR ",
- };
-
- 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 *)) - 1) {
- 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++] = (unsigned char) 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 *my_ies, unsigned char *data, int datalen)
-{
- /* Parse data into information elements */
- int len;
- int ie;
- char tmp[256];
- memset(my_ies, 0, (int) sizeof(struct iax_ies));
- my_ies->msgcount = -1;
- my_ies->firmwarever = -1;
- my_ies->calling_ton = -1;
- my_ies->calling_tns = -1;
- my_ies->calling_pres = -1;
- my_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:
- my_ies->called_number = (char *) data + 2;
- break;
- case IAX_IE_CALLING_NUMBER:
- my_ies->calling_number = (char *) data + 2;
- break;
- case IAX_IE_CALLING_ANI:
- my_ies->calling_ani = (char *) data + 2;
- break;
- case IAX_IE_CALLING_NAME:
- my_ies->calling_name = (char *) data + 2;
- break;
- case IAX_IE_CALLED_CONTEXT:
- my_ies->called_context = (char *) data + 2;
- break;
- case IAX_IE_USERNAME:
- my_ies->username = (char *) data + 2;
- break;
- case IAX_IE_PASSWORD:
- my_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
- my_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
- my_ies->format = ntohl(get_uint32(data + 2));
- break;
- case IAX_IE_LANGUAGE:
- my_ies->language = (char *) data + 2;
- break;
- case IAX_IE_CODEC_PREFS:
- my_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
- my_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
- my_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
- my_ies->samprate = ntohs(get_uint16(data + 2));
- break;
- case IAX_IE_DNID:
- my_ies->dnid = (char *) data + 2;
- break;
- case IAX_IE_RDNIS:
- my_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
- my_ies->authmethods = ntohs(get_uint16(data + 2));
- break;
- case IAX_IE_CHALLENGE:
- my_ies->challenge = (char *) data + 2;
- break;
- case IAX_IE_MD5_RESULT:
- my_ies->md5_result = (char *) data + 2;
- break;
- case IAX_IE_RSA_RESULT:
- my_ies->rsa_result = (char *) data + 2;
- break;
- case IAX_IE_APPARENT_ADDR:
- my_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
- my_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
- my_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
- my_ies->callno = ntohs(get_uint16(data + 2));
- break;
- case IAX_IE_CAUSE:
- my_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 {
- my_ies->causecode = data[2];
- }
- break;
- case IAX_IE_IAX_UNKNOWN:
- if (len == 1)
- my_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
- my_ies->msgcount = ntohs(get_uint16(data + 2));
- break;
- case IAX_IE_AUTOANSWER:
- my_ies->autoanswer = 1;
- break;
- case IAX_IE_MUSICONHOLD:
- my_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
- my_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
- my_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
- my_ies->firmwarever = ntohs(get_uint16(data + 2));
- break;
- case IAX_IE_DEVICETYPE:
- my_ies->devicetype = (char *) data + 2;
- break;
- case IAX_IE_SERVICEIDENT:
- my_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
- my_ies->fwdesc = ntohl(get_uint32(data + 2));
- break;
- case IAX_IE_FWBLOCKDATA:
- my_ies->fwdata = data + 2;
- my_ies->fwdatalen = (unsigned char) 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 {
- my_ies->provverpres = 1;
- my_ies->provver = ntohl(get_uint32(data + 2));
- }
- break;
- case IAX_IE_CALLINGPRES:
- if (len == 1)
- my_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)
- my_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
- my_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 {
- my_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 {
- my_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 {
- my_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 {
- my_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 {
- my_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 {
- my_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;
- frame_count++;
- 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);
- frame_count--;
-}
-
-int iax_get_frames(void)
-{
- return frame_count;
-}
-int iax_get_iframes(void)
-{
- return iframes;
-}
-int iax_get_oframes(void)
-{
- return oframes;
-}
+++ /dev/null
-/*
- * Asterisk -- A telephony toolkit for Linux.
- *
- * Implementation of Inter-Asterisk eXchange
- *
- * Copyright (C) 2003, Digium
- *
- * Mark Spencer <markster@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
+++ /dev/null
-/*
- * Asterisk -- A telephony toolkit for Linux.
- *
- * Implementation of Inter-Asterisk eXchange
- *
- * Copyright (C) 2003, Digium
- *
- * Mark Spencer <markster@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
+++ /dev/null
-/*
- * jitterbuf: an application-independent jitterbuffer
- *
- * Copyrights:
- * Copyright (C) 2004-2005, Horizon Wimba, Inc.
- *
- * Contributors:
- * Steve Kann <stevek@stevek.com>
- *
- * This program is free software, distributed under the terms of
- * the GNU Lesser (Library) General Public License
- *
- * Copyright on this file is disclaimed to Digium for inclusion in Asterisk
- */
-
-#include "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 = (jitterbuf *) malloc(sizeof(*jb));
-
- if (!jb)
- return NULL;
-
- jb->info.conf.target_extra = JB_TARGET_EXTRA;
-
- jb_reset(jb);
-
- return jb;
-}
-
-void jb_destroy(jitterbuf * jb)
-{
- jb_frame *frame;
-
- /* 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)
-{
- 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->free;
- jb_frame *p;
- int head = 0;
- time_in_ms_t resync_ts = ts - jb->info.resync_offset;
-
- if (frame) {
- jb->free = frame->next;
- } else {
- frame = (jb_frame *) malloc(sizeof(*frame));
- if (!frame) {
- jb_err("cannot allocate frame\n");
- return 0;
- }
- }
-
- jb->info.frames_cur++;
-
- frame->data = data;
- frame->ts = resync_ts;
- frame->ms = ms;
- frame->type = type;
-
- /*
- * frames are a circular list, jb-frames points to to the lowest ts,
- * jb->frames->prev points to the highest ts
- */
-
- if (!jb->frames) { /* queue is empty */
- jb->frames = frame;
- frame->next = frame;
- frame->prev = frame;
- head = 1;
- } else if (resync_ts < jb->frames->ts) {
- frame->next = jb->frames;
- frame->prev = jb->frames->prev;
-
- frame->next->prev = frame;
- frame->prev->next = frame;
-
- /* frame is out of order */
- jb->info.frames_ooo++;
-
- jb->frames = frame;
- head = 1;
- } else {
- p = jb->frames;
-
- /* frame is out of order */
- if (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->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))
- 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;
-}
+++ /dev/null
-/*
- * jitterbuf: an application-independent jitterbuffer
- *
- * Copyrights:
- * Copyright (C) 2004-2005, Horizon Wimba, Inc.
- *
- * Contributors:
- * Steve Kann <stevek@stevek.com>
- *
- * This program is free software, distributed under the terms of
- * the GNU Lesser (Library) General Public License
- *
- * Copyright on this file is disclaimed to Digium for inclusion in Asterisk
- */
-
-#ifndef _JITTERBUF_H_
-#define _JITTERBUF_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* configuration constants */
- /* Number of historical timestamps to use in calculating jitter and drift */
-#define JB_HISTORY_SZ 500
- /* what percentage of timestamps should we drop from the history when we examine it;
- * this might eventually be something made configurable */
-#define JB_HISTORY_DROPPCT 3
- /* the maximum droppct we can handle (say it was configurable). */
-#define JB_HISTORY_DROPPCT_MAX 4
- /* the size of the buffer we use to keep the top and botton timestamps for dropping */
-#define JB_HISTORY_MAXBUF_SZ JB_HISTORY_SZ * JB_HISTORY_DROPPCT_MAX / 100
- /* amount of additional jitterbuffer adjustment */
-#define JB_TARGET_EXTRA 40
- /* ms between growing and shrinking; may not be honored if jitterbuffer runs out of space */
-#define JB_ADJUST_DELAY 40
-
-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
+++ /dev/null
-/* 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
+++ /dev/null
-#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 */
+++ /dev/null
-<?xml version="1.0" encoding="Windows-1252"?>\r
-<VisualStudioProject\r
- ProjectType="Visual C++"\r
- Version="9.00"\r
- Name="mod_iax"\r
- ProjectGUID="{3A5B9131-F20C-4A85-9447-6C1610941CEE}"\r
- RootNamespace="mod_iax"\r
- Keyword="Win32Proj"\r
- TargetFrameworkVersion="131072"\r
- >\r
- <Platforms>\r
- <Platform\r
- Name="Win32"\r
- />\r
- <Platform\r
- Name="x64"\r
- />\r
- </Platforms>\r
- <ToolFiles>\r
- </ToolFiles>\r
- <Configurations>\r
- <Configuration\r
- Name="Debug|Win32"\r
- ConfigurationType="2"\r
- InheritedPropertySheets="..\..\..\..\w32\module_debug.vsprops"\r
- CharacterSet="2"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- AdditionalIncludeDirectories="."\r
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;WIN32_TIME_GET_TIME;LIBIAX;NEWJB;_CRT_SECURE_NO_DEPRECATE;DEBUG_SUPPORT"\r
- UsePrecompiledHeader="0"\r
- DisableSpecificWarnings="4201;4200;4100;4127;6246;6053;6031;6262;4706"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalLibraryDirectories=""..\..\..\..\libs\iax\$(OutDir)""\r
- RandomizedBaseAddress="1"\r
- DataExecutionPrevention="0"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Debug|x64"\r
- ConfigurationType="2"\r
- InheritedPropertySheets="..\..\..\..\w32\module_debug.vsprops"\r
- CharacterSet="2"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- TargetEnvironment="3"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- AdditionalIncludeDirectories="."\r
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;WIN32_TIME_GET_TIME;LIBIAX;NEWJB;_CRT_SECURE_NO_DEPRECATE;DEBUG_SUPPORT"\r
- UsePrecompiledHeader="0"\r
- DisableSpecificWarnings="4201;4200;4100;4127;6246;6053;6031;6262;4706"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- OutputFile="$(SolutionDir)$(PlatformName)\$(ConfigurationName)/mod/$(ProjectName).dll"\r
- AdditionalLibraryDirectories=""..\..\..\..\libs\iax\$(OutDir)""\r
- RandomizedBaseAddress="1"\r
- DataExecutionPrevention="0"\r
- TargetMachine="17"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Release|Win32"\r
- ConfigurationType="2"\r
- InheritedPropertySheets="..\..\..\..\w32\module_release.vsprops"\r
- CharacterSet="2"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- AdditionalIncludeDirectories="."\r
- PreprocessorDefinitions="WIN32;_WINDOWS;_USRDLL;MOD_EXPORTS;LIBIAX;WIN32_TIME_GET_TIME;DEBUG_SUPPORT;NEWJB;_CRT_SECURE_NO_DEPRECATE"\r
- UsePrecompiledHeader="0"\r
- DisableSpecificWarnings="4201;4200;4100;4127;6246;6053;6031;6262;4706"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalLibraryDirectories=""..\..\..\..\libs\iax\$(OutDir)""\r
- RandomizedBaseAddress="1"\r
- DataExecutionPrevention="0"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Release|x64"\r
- ConfigurationType="2"\r
- InheritedPropertySheets="..\..\..\..\w32\module_release.vsprops"\r
- CharacterSet="2"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- TargetEnvironment="3"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- AdditionalIncludeDirectories="."\r
- PreprocessorDefinitions="WIN32;_WINDOWS;_USRDLL;MOD_EXPORTS;LIBIAX;WIN32_TIME_GET_TIME;DEBUG_SUPPORT;NEWJB;_CRT_SECURE_NO_DEPRECATE"\r
- UsePrecompiledHeader="0"\r
- DisableSpecificWarnings="4201;4200;4100;4127;6246;6053;6031;6262;4706"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- OutputFile="$(SolutionDir)$(PlatformName)\$(ConfigurationName)/mod/$(ProjectName).dll"\r
- AdditionalLibraryDirectories=""..\..\..\..\libs\iax\$(OutDir)""\r
- RandomizedBaseAddress="1"\r
- DataExecutionPrevention="0"\r
- TargetMachine="17"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- />\r
- </Configuration>\r
- </Configurations>\r
- <References>\r
- </References>\r
- <Files>\r
- <File\r
- RelativePath=".\iax-mutex.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\iax.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\iax2-parser.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\jitterbuf.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\md5.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\mod_iax.c"\r
- >\r
- </File>\r
- </Files>\r
- <Globals>\r
- </Globals>\r
-</VisualStudioProject>\r
+++ /dev/null
-/*
- * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
- * Copyright (C) 2005-2009, Anthony Minessale II <anthm@freeswitch.org>
- *
- * Version: MPL 1.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
- *
- * The Initial Developer of the Original Code is
- * Anthony Minessale II <anthm@freeswitch.org>
- * Portions created by the Initial Developer are Copyright (C)
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * Anthony Minessale II <anthm@freeswitch.org>
- *
- *
- * mod_iax.c -- IAX2 Endpoint Module
- *
- */
-#include <switch.h>
-
-SWITCH_MODULE_LOAD_FUNCTION(mod_iax_load);
-SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_iax_shutdown);
-SWITCH_MODULE_RUNTIME_FUNCTION(mod_iax_runtime);
-SWITCH_MODULE_DEFINITION(mod_iax, mod_iax_load, mod_iax_shutdown, mod_iax_runtime);
-
-#include <iax2.h>
-#include <iax-client.h>
-#include <iax2-parser.h>
-#ifdef WIN32
-#include <sys/timeb.h>
-#endif
-
-switch_endpoint_interface_t *iax_endpoint_interface;
-static switch_memory_pool_t *module_pool = NULL;
-static int running = 1;
-
-
-typedef enum {
- TFLAG_IO = (1 << 0),
- TFLAG_INBOUND = (1 << 1),
- TFLAG_OUTBOUND = (1 << 2),
- TFLAG_DTMF = (1 << 3),
- TFLAG_VOICE = (1 << 4),
- TFLAG_HANGUP = (1 << 5),
- TFLAG_LINEAR = (1 << 6),
- TFLAG_CODEC = (1 << 7),
- TFLAG_BREAK = (1 << 8)
-} TFLAGS;
-
-typedef enum {
- GFLAG_MY_CODEC_PREFS = (1 << 0)
-} GFLAGS;
-
-static struct {
- int debug;
- char *ip;
- int port;
- char *dialplan;
- char *codec_string;
- char *codec_order[SWITCH_MAX_CODECS];
- int codec_order_last;
- char *codec_rates_string;
- char *codec_rates[SWITCH_MAX_CODECS];
- int codec_rates_last;
- unsigned int flags;
- int fd;
- int calls;
- switch_mutex_t *mutex;
- int media_timeout;
-} globals;
-
-struct private_object {
- unsigned int flags;
- switch_codec_t read_codec;
- switch_codec_t write_codec;
- switch_frame_t *read_frame;
- switch_frame_t cng_frame;
- unsigned char cng_databuf[10];
- switch_core_session_t *session;
- struct iax_session *iax_session;
- switch_caller_profile_t *caller_profile;
- unsigned int codec;
- unsigned int codecs;
- unsigned short samprate;
- switch_mutex_t *mutex;
- switch_mutex_t *flag_mutex;
- int cng_count;
- switch_timer_t timer;
- switch_queue_t *frame_queue;
- int media_timeout;
- //switch_thread_cond_t *cond;
-};
-
-typedef struct private_object private_t;
-
-
-SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_dialplan, globals.dialplan);
-SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_codec_string, globals.codec_string);
-SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_codec_rates_string, globals.codec_rates_string);
-SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_ip, globals.ip);
-
-
-static char *IAXNAMES[] = { "IAX_EVENT_CONNECT", "IAX_EVENT_ACCEPT", "IAX_EVENT_HANGUP", "IAX_EVENT_REJECT", "IAX_EVENT_VOICE",
- "IAX_EVENT_DTMF", "IAX_EVENT_TIMEOUT", "IAX_EVENT_LAGRQ", "IAX_EVENT_LAGRP", "IAX_EVENT_RINGA",
- "IAX_EVENT_PING", "IAX_EVENT_PONG", "IAX_EVENT_BUSY", "IAX_EVENT_ANSWER", "IAX_EVENT_IMAGE",
- "IAX_EVENT_AUTHRQ", "IAX_EVENT_AUTHRP", "IAX_EVENT_REGREQ", "IAX_EVENT_REGACK",
- "IAX_EVENT_URL", "IAX_EVENT_LDCOMPLETE", "IAX_EVENT_TRANSFER", "IAX_EVENT_DPREQ",
- "IAX_EVENT_DPREP", "IAX_EVENT_DIAL", "IAX_EVENT_QUELCH", "IAX_EVENT_UNQUELCH",
- "IAX_EVENT_UNLINK", "IAX_EVENT_LINKREJECT", "IAX_EVENT_TEXT", "IAX_EVENT_REGREJ",
- "IAX_EVENT_LINKURL", "IAX_EVENT_CNG", "IAX_EVENT_REREQUEST", "IAX_EVENT_TXREPLY",
- "IAX_EVENT_TXREJECT", "IAX_EVENT_TXACCEPT", "IAX_EVENT_TXREADY"
-};
-
-
-struct ast_iana {
- const unsigned int ast;
- const int iana;
- char *name;
-};
-
-//999 means it's wrong nad i dont know the real one
-static struct ast_iana AST_IANA[] = { {AST_FORMAT_G723_1, 4, "g723.1"},
-{AST_FORMAT_GSM, 3, "gsm"},
-{AST_FORMAT_ULAW, 0, "ulaw"},
-{AST_FORMAT_ALAW, 8, "alaw"},
-{AST_FORMAT_G726, 999, "g726"},
-{AST_FORMAT_ADPCM, 999, "adpcm"},
-{AST_FORMAT_SLINEAR, 10, "slinear"},
-{AST_FORMAT_LPC10, 7, "lpc10"},
-{AST_FORMAT_G729A, 18, "g729"},
-{AST_FORMAT_SPEEX, 97, "speex"},
-{AST_FORMAT_SPEEX, 98, "speex"},
-{AST_FORMAT_ILBC, 102, "ilbc"},
-{AST_FORMAT_MAX_AUDIO, 999, ""},
-{AST_FORMAT_JPEG, 999, ""},
-{AST_FORMAT_PNG, 999, ""},
-{AST_FORMAT_H261, 999, ""},
-{AST_FORMAT_H263, 999, ""},
-{AST_FORMAT_MAX_VIDEO, 999, ""},
-{0, 0}
-};
-
-static char *ast2str(int ast)
-{
- int x;
- for (x = 0; x < 19; x++) {
- if ((1 << x) == ast) {
- return AST_IANA[x].name;
- }
- }
- return "";
-}
-
-static unsigned int iana2ast(int iana)
-{
- int x = 0;
- unsigned int ast = 0;
-
- for (x = 0; AST_IANA[x].ast; x++) {
- if (AST_IANA[x].iana == iana) {
- ast = AST_IANA[x].ast;
- break;
- }
- }
-
- return ast;
-}
-
-static unsigned short iax_build_codec_rates(void)
-{
- int x;
- unsigned short samples = 0;
-
- for (x = 0; x < globals.codec_rates_last; x++) {
- int rate = atoi(globals.codec_rates[x]);
- switch (rate) {
- case 8:
- samples |= IAX_RATE_8KHZ;
- break;
- case 16:
- samples |= IAX_RATE_16KHZ;
- break;
- case 22:
- samples |= IAX_RATE_22KHZ;
- break;
- case 32:
- samples |= IAX_RATE_32KHZ;
- break;
- case 44:
- samples |= IAX_RATE_44KHZ;
- break;
- case 48:
- samples |= IAX_RATE_48KHZ;
- break;
- default:
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "I don't know rate %d\n", rate);
- break;
- }
- }
- return samples;
-}
-
-typedef enum {
- IAX_SET = 1,
- IAX_QUERY = 2
-} iax_io_t;
-
-static switch_status_t iax_set_codec(private_t *tech_pvt, struct iax_session *iax_session,
- unsigned int *format, unsigned int *cababilities, unsigned short *samprate, iax_io_t io)
-{
- char *dname = NULL;
- switch_channel_t *channel;
- const switch_codec_implementation_t *codecs[SWITCH_MAX_CODECS];
- int num_codecs = 0;
- unsigned int local_cap = 0, mixed_cap = 0, chosen = 0, leading = 0;
- int x, srate = 8000;
- uint32_t interval = 0;
- const switch_codec_implementation_t *read_impl;
-
- if (globals.codec_string) {
- num_codecs = switch_loadable_module_get_codecs_sorted(codecs, SWITCH_MAX_CODECS, globals.codec_order, globals.codec_order_last);
- } else {
- num_codecs = switch_loadable_module_get_codecs(codecs, SWITCH_MAX_CODECS);
- }
-
- if (num_codecs <= 0) {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "NO codecs?\n");
- return SWITCH_STATUS_GENERR;
- }
-
- for (x = 0; x < num_codecs; x++) {
- static const switch_codec_implementation_t *imp;
- for (imp = codecs[x]; imp; imp = imp->next) {
- unsigned int codec = iana2ast(imp->ianacode);
- if (io == IAX_QUERY && !(codec & local_cap)) {
- iax_pref_codec_add(iax_session, codec);
- }
- local_cap |= codec;
- }
- }
-
- switch_assert(codecs[0]);
-
- if (io == IAX_SET) {
- mixed_cap = (local_cap & *cababilities);
- } else {
- mixed_cap = local_cap;
- }
-
- leading = iana2ast(codecs[0]->ianacode);
- interval = codecs[0]->microseconds_per_packet / 1000;
- if (io == IAX_QUERY) {
- chosen = leading;
- *format = chosen;
- *cababilities = local_cap;
- if (globals.codec_rates_last) {
- *samprate = iax_build_codec_rates();
- tech_pvt->samprate = *samprate;
- }
- return SWITCH_STATUS_SUCCESS;
- } else if (switch_test_flag(&globals, GFLAG_MY_CODEC_PREFS) && (leading & mixed_cap)) {
- chosen = leading;
- dname = codecs[0]->iananame;
- } else {
- unsigned int prefs[32];
- int len = 0;
-
- if (!switch_test_flag(&globals, GFLAG_MY_CODEC_PREFS)) {
- len = iax_pref_codec_get(iax_session, prefs, sizeof(prefs));
- }
-
- if (len) { /*they sent us a pref and we don't want to be codec master */
- char pref_str[256] = "(";
-
- for (x = 0; x < len; x++) {
- strncat(pref_str, ast2str(prefs[x]), sizeof(pref_str) - 1);
- strncat(pref_str, x == len - 1 ? ")" : ",", sizeof(pref_str) - 1);
- }
-
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_INFO, "Codec Prefs Detected: %s\n", pref_str);
-
- for (x = 0; x < len; x++) {
- if ((prefs[x] & mixed_cap)) {
- int z;
- chosen = prefs[x];
- for (z = 0; z < num_codecs; z++) {
- static const switch_codec_implementation_t *imp;
- for (imp = codecs[z]; imp; imp = imp->next) {
- if (prefs[x] == iana2ast(imp->ianacode)) {
- dname = imp->iananame;
- interval = imp->microseconds_per_packet / 1000;
- break;
- }
- }
- }
- break;
- }
- }
- } else {
- if (*format & mixed_cap) { /* is the one we asked for here? */
- chosen = *format;
- for (x = 0; x < num_codecs; x++) {
- static const switch_codec_implementation_t *imp;
- for (imp = codecs[x]; imp; imp = imp->next) {
- unsigned int cap = iana2ast(imp->ianacode);
- if (cap == chosen) {
- dname = imp->iananame;
- interval = imp->microseconds_per_packet / 1000;
- break;
- }
- }
- }
- } else { /* c'mon there has to be SOMETHING... */
- for (x = 0; x < num_codecs; x++) {
- static const switch_codec_implementation_t *imp;
- for (imp = codecs[x]; imp; imp = imp->next) {
- unsigned int cap = iana2ast(imp->ianacode);
- if (cap & mixed_cap) {
- chosen = cap;
- dname = imp->iananame;
- interval = imp->microseconds_per_packet / 1000;
- break;
- }
- }
- }
- }
- }
- }
-
- if (!dname && !chosen) {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "NO codecs?\n");
- return SWITCH_STATUS_GENERR;
- }
-
- channel = switch_core_session_get_channel(tech_pvt->session);
-
- if (tech_pvt->samprate || *samprate) {
- unsigned short samples = iax_build_codec_rates();
- unsigned short mixed = ((tech_pvt->samprate ? tech_pvt->samprate : *samprate) & samples);
-
- srate = 8000;
-
- if (mixed & IAX_RATE_16KHZ) {
- srate = 16000;
- }
- if (mixed & IAX_RATE_22KHZ) {
- srate = 22050;
- }
- if (mixed & IAX_RATE_32KHZ) {
- srate = 32000;
- }
- if (mixed & IAX_RATE_44KHZ) {
- srate = 44000;
- }
- if (mixed & IAX_RATE_48KHZ) {
- srate = 48000;
- }
- }
-
- if (!strcasecmp(dname, "l16")) {
- switch_set_flag_locked(tech_pvt, TFLAG_LINEAR);
- }
- if (switch_core_codec_init(&tech_pvt->read_codec,
- dname,
- NULL,
- srate,
- interval,
- 1,
- SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
- NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Can't load codec?\n");
- return SWITCH_STATUS_GENERR;
- } else {
- if (switch_core_codec_init(&tech_pvt->write_codec,
- dname,
- NULL,
- srate,
- interval,
- 1,
- SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
- NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Can't load codec?\n");
- switch_core_codec_destroy(&tech_pvt->read_codec);
- return SWITCH_STATUS_GENERR;
- } else {
- int ms;
- int rate;
- ms = tech_pvt->write_codec.implementation->microseconds_per_packet / 1000;
- rate = tech_pvt->write_codec.implementation->samples_per_second;
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_INFO, "Activate Codec %s/%d %d ms\n", dname, rate, ms);
- switch_core_session_set_read_codec(tech_pvt->session, &tech_pvt->read_codec);
- switch_core_session_set_write_codec(tech_pvt->session, &tech_pvt->write_codec);
- switch_set_flag_locked(tech_pvt, TFLAG_CODEC);
- }
- tech_pvt->codec = chosen;
- tech_pvt->codecs = local_cap;
- }
-
- read_impl = tech_pvt->read_codec.implementation;
-
- switch_core_timer_init(&tech_pvt->timer, "soft",
- read_impl->microseconds_per_packet / 1000,
- read_impl->samples_per_packet,
- switch_core_session_get_pool(tech_pvt->session));
-
- tech_pvt->media_timeout = (read_impl->samples_per_second * globals.media_timeout) / read_impl->samples_per_packet;
-
-
- if (io == IAX_QUERY) {
- *format = tech_pvt->codec;
- *cababilities = local_cap;
- }
-
- return SWITCH_STATUS_SUCCESS;
-}
-
-static switch_status_t channel_on_init(switch_core_session_t *session);
-static switch_status_t channel_on_hangup(switch_core_session_t *session);
-static switch_status_t channel_on_destroy(switch_core_session_t *session);
-static switch_status_t channel_on_routing(switch_core_session_t *session);
-static switch_status_t channel_on_exchange_media(switch_core_session_t *session);
-static switch_status_t channel_on_soft_execute(switch_core_session_t *session);
-static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event,
- switch_caller_profile_t *outbound_profile,
- switch_core_session_t **new_session, switch_memory_pool_t **pool, switch_originate_flag_t flags, switch_call_cause_t *cancel_cause);
-static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id);
-static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id);
-static switch_status_t channel_kill_channel(switch_core_session_t *session, int sig);
-
-
-static void iax_err_cb(const char *s)
-{
- switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, "IAX ERR: %s", s);
-}
-
-static void iax_out_cb(const char *s)
-{
- if (globals.debug > 1) {
- switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "IAX INFO: %s", s);
- }
-}
-
-static void tech_init(private_t *tech_pvt, switch_core_session_t *session)
-{
- tech_pvt->cng_frame.data = tech_pvt->cng_databuf;
- tech_pvt->cng_frame.buflen = sizeof(tech_pvt->cng_databuf);
- switch_set_flag((&tech_pvt->cng_frame), SFF_CNG);
- tech_pvt->cng_frame.datalen = 2;
- switch_mutex_init(&tech_pvt->mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
- switch_mutex_init(&tech_pvt->flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
- switch_queue_create(&tech_pvt->frame_queue, 50000, switch_core_session_get_pool(session));
- switch_core_session_set_private(session, tech_pvt);
- tech_pvt->session = session;
-}
-
-/*
- State methods they get called when the state changes to the specific state
- returning SWITCH_STATUS_SUCCESS tells the core to execute the standard state method next
- so if you fully implement the state you can return SWITCH_STATUS_FALSE to skip it.
-*/
-static switch_status_t channel_on_init(switch_core_session_t *session)
-{
- private_t *tech_pvt = switch_core_session_get_private(session);
- switch_assert(tech_pvt != NULL);
-
- iax_set_private(tech_pvt->iax_session, tech_pvt);
-
- switch_set_flag_locked(tech_pvt, TFLAG_IO);
-
- /* Move channel's state machine to ROUTING */
- switch_channel_set_state(switch_core_session_get_channel(session), CS_ROUTING);
- switch_mutex_lock(globals.mutex);
- globals.calls++;
- switch_mutex_unlock(globals.mutex);
-
- return SWITCH_STATUS_SUCCESS;
-}
-
-static switch_status_t channel_on_routing(switch_core_session_t *session)
-{
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s CHANNEL ROUTING\n", switch_channel_get_name(switch_core_session_get_channel(session)));
- return SWITCH_STATUS_SUCCESS;
-}
-
-static switch_status_t channel_on_execute(switch_core_session_t *session)
-{
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s CHANNEL EXECUTE\n", switch_channel_get_name(switch_core_session_get_channel(session)));
- return SWITCH_STATUS_SUCCESS;
-}
-
-static switch_status_t channel_on_destroy(switch_core_session_t *session)
-{
- private_t *tech_pvt = switch_core_session_get_private(session);
- void *pop;
-
- if (tech_pvt) {
- if (switch_core_codec_ready(&tech_pvt->read_codec)) {
- switch_core_codec_destroy(&tech_pvt->read_codec);
- }
-
- if (!switch_core_codec_ready(&tech_pvt->write_codec)) {
- switch_core_codec_destroy(&tech_pvt->write_codec);
- }
-
- while (switch_queue_trypop(tech_pvt->frame_queue, &pop) == SWITCH_STATUS_SUCCESS && pop) {
- switch_frame_t *frame = (switch_frame_t *) pop;
- switch_frame_free(&frame);
- }
- }
-
- return SWITCH_STATUS_SUCCESS;
-}
-
-static switch_status_t channel_on_hangup(switch_core_session_t *session)
-{
- private_t *tech_pvt = switch_core_session_get_private(session);
-
- switch_assert(tech_pvt != NULL);
-
- switch_clear_flag_locked(tech_pvt, TFLAG_IO);
- switch_clear_flag_locked(tech_pvt, TFLAG_VOICE);
- switch_clear_flag_locked(tech_pvt, TFLAG_CODEC);
-
- switch_mutex_lock(globals.mutex);
- if (tech_pvt->iax_session) {
- if (!switch_test_flag(tech_pvt, TFLAG_HANGUP)) {
- iax_hangup(tech_pvt->iax_session, "Hangup");
- switch_set_flag_locked(tech_pvt, TFLAG_HANGUP);
- }
- iax_session_destroy(&tech_pvt->iax_session);
- }
-
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s CHANNEL HANGUP\n", switch_channel_get_name(switch_core_session_get_channel(session)));
- globals.calls--;
- if (globals.calls < 0) {
- globals.calls = 0;
- }
- switch_mutex_unlock(globals.mutex);
-
- return SWITCH_STATUS_SUCCESS;
-}
-
-static switch_status_t channel_kill_channel(switch_core_session_t *session, int sig)
-{
- private_t *tech_pvt = switch_core_session_get_private(session);
- switch_assert(tech_pvt != NULL);
-
- switch (sig) {
- case SWITCH_SIG_KILL:
- switch_clear_flag_locked(tech_pvt, TFLAG_IO);
- switch_clear_flag_locked(tech_pvt, TFLAG_VOICE);
- switch_channel_hangup(switch_core_session_get_channel(session), SWITCH_CAUSE_NORMAL_CLEARING);
- break;
- case SWITCH_SIG_BREAK:
- switch_set_flag_locked(tech_pvt, TFLAG_BREAK);
- break;
- default:
- break;
- }
-
- return SWITCH_STATUS_SUCCESS;
-}
-
-static switch_status_t channel_on_exchange_media(switch_core_session_t *session)
-{
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "CHANNEL LOOPBACK\n");
- return SWITCH_STATUS_SUCCESS;
-}
-
-static switch_status_t channel_on_soft_execute(switch_core_session_t *session)
-{
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "CHANNEL TRANSMIT\n");
- return SWITCH_STATUS_SUCCESS;
-}
-
-static switch_status_t channel_send_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf)
-{
- private_t *tech_pvt = switch_core_session_get_private(session);
- switch_assert(tech_pvt != NULL);
- if (tech_pvt->iax_session) {
- switch_mutex_lock(globals.mutex);
- iax_send_dtmf(tech_pvt->iax_session, dtmf->digit);
- switch_mutex_unlock(globals.mutex);
- }
-
- return SWITCH_STATUS_SUCCESS;
-}
-
-static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id)
-{
- private_t *tech_pvt = switch_core_session_get_private(session);
- switch_byte_t *data;
- void *pop;
-
- switch_assert(tech_pvt != NULL);
- *frame = NULL;
-
- while (switch_test_flag(tech_pvt, TFLAG_IO)) {
-
- if (!switch_test_flag(tech_pvt, TFLAG_CODEC)) {
- switch_cond_next();
- continue;
- }
- if (switch_test_flag(tech_pvt, TFLAG_BREAK)) {
- switch_clear_flag(tech_pvt, TFLAG_BREAK);
- goto cng;
- }
-
- if (!switch_test_flag(tech_pvt, TFLAG_IO)) {
- return SWITCH_STATUS_FALSE;
- }
-
- if (!switch_queue_size(tech_pvt->frame_queue)) {
- switch_core_timer_next(&tech_pvt->timer);
- }
-
- if (switch_queue_trypop(tech_pvt->frame_queue, &pop) == SWITCH_STATUS_SUCCESS && pop) {
- if (tech_pvt->read_frame) {
- switch_frame_free(&tech_pvt->read_frame);
- }
-
- tech_pvt->read_frame = (switch_frame_t *) pop;
- tech_pvt->read_frame->codec = &tech_pvt->read_codec;
- *frame = tech_pvt->read_frame;
-
-#if SWITCH_BYTE_ORDER == __BIG_ENDIAN
- if (switch_test_flag(tech_pvt, TFLAG_LINEAR)) {
- switch_swap_linear((*frame)->data, (int) (*frame)->datalen / 2);
- }
-#endif
- switch_clear_flag_locked(tech_pvt, TFLAG_VOICE);
- tech_pvt->cng_count = tech_pvt->media_timeout;
- return SWITCH_STATUS_SUCCESS;
- } else {
- if (tech_pvt->cng_count && --tech_pvt->cng_count == 0) {
- break;
- }
- goto cng;
- }
-
-
- }
-
- return SWITCH_STATUS_FALSE;
-
- cng:
- data = (switch_byte_t *) tech_pvt->cng_frame.data;
- data[0] = 65;
- data[1] = 0;
- tech_pvt->cng_frame.datalen = 2;
- tech_pvt->cng_frame.flags = SFF_CNG;
- *frame = &tech_pvt->cng_frame;
- return SWITCH_STATUS_SUCCESS;
-}
-
-static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id)
-{
- private_t *tech_pvt = switch_core_session_get_private(session);
- switch_assert(tech_pvt != NULL);
-
- if (!switch_test_flag(tech_pvt, TFLAG_IO)) {
- return SWITCH_STATUS_FALSE;
- }
-#if SWITCH_BYTE_ORDER == __BIG_ENDIAN
- if (switch_test_flag(tech_pvt, TFLAG_LINEAR)) {
- switch_swap_linear(frame->data, (int) frame->datalen / 2);
- }
-#endif
- iax_send_voice(tech_pvt->iax_session, tech_pvt->codec, frame->data, (int) frame->datalen, tech_pvt->write_codec.implementation->samples_per_packet);
-
- return SWITCH_STATUS_SUCCESS;
-
-}
-
-static switch_status_t channel_answer_channel(switch_core_session_t *session)
-{
- private_t *tech_pvt = switch_core_session_get_private(session);
- switch_assert(tech_pvt != NULL);
-
- if (!switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) {
- switch_mutex_lock(globals.mutex);
- iax_answer(tech_pvt->iax_session);
- switch_mutex_unlock(globals.mutex);
- }
- return SWITCH_STATUS_SUCCESS;
-}
-
-
-static switch_status_t channel_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg)
-{
- private_t *tech_pvt = (private_t *) switch_core_session_get_private(session);
- switch_assert(tech_pvt != NULL);
-
- switch (msg->message_id) {
- case SWITCH_MESSAGE_INDICATE_RESPOND:
- {
- if (tech_pvt->iax_session) {
- switch_mutex_lock(globals.mutex);
- iax_reject(tech_pvt->iax_session, msg->string_arg ? msg->string_arg : "Call Rejected");
- switch_set_flag(tech_pvt, TFLAG_HANGUP);
- switch_mutex_unlock(globals.mutex);
- }
- }
- break;
- case SWITCH_MESSAGE_INDICATE_ANSWER:
- {
- channel_answer_channel(session);
- }
- break;
-
- case SWITCH_MESSAGE_INDICATE_BRIDGE:
- case SWITCH_MESSAGE_INDICATE_UNBRIDGE:
- case SWITCH_MESSAGE_INDICATE_AUDIO_SYNC:
- {
- void *pop;
-
- while (switch_queue_trypop(tech_pvt->frame_queue, &pop) == SWITCH_STATUS_SUCCESS && pop) {
- switch_frame_t *frame = (switch_frame_t *) pop;
- switch_frame_free(&frame);
- }
- }
- default:
- break;
- }
-
- return SWITCH_STATUS_SUCCESS;
-}
-
-/* Make sure when you have 2 sessions in the same scope that you pass the appropriate one to the routines
- that allocate memory or you will have 1 channel with memory allocated from another channel's pool!
-*/
-static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event,
- switch_caller_profile_t *outbound_profile,
- switch_core_session_t **new_session, switch_memory_pool_t **pool, switch_originate_flag_t flags, switch_call_cause_t *cancel_cause)
-{
- if ((*new_session = switch_core_session_request(iax_endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, pool)) != 0) {
- private_t *tech_pvt;
- switch_channel_t *channel;
- switch_caller_profile_t *caller_profile;
- unsigned int req = 0, cap = 0;
- unsigned short samprate = 0;
-
- switch_core_session_add_stream(*new_session, NULL);
- if ((tech_pvt = (private_t *) switch_core_session_alloc(*new_session, sizeof(private_t))) != 0) {
- channel = switch_core_session_get_channel(*new_session);
- tech_init(tech_pvt, *new_session);
- } else {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Hey where is my memory pool?\n");
- switch_core_session_destroy(new_session);
- return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
- }
-
- if (outbound_profile) {
- char name[128];
-
- switch_snprintf(name, sizeof(name), "IAX/%s-%04x", outbound_profile->destination_number, rand() & 0xffff);
- switch_channel_set_name(channel, name);
-
- caller_profile = switch_caller_profile_clone(*new_session, outbound_profile);
- switch_channel_set_caller_profile(channel, caller_profile);
- tech_pvt->caller_profile = caller_profile;
- } else {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(*new_session), SWITCH_LOG_ERROR, "Doh! no caller profile\n");
- switch_core_session_destroy(new_session);
- return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
- }
-
- switch_mutex_lock(globals.mutex);
- tech_pvt->iax_session = iax_session_new();
- switch_mutex_unlock(globals.mutex);
-
- if (!tech_pvt->iax_session) {
- switch_core_session_destroy(new_session);
- return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
- }
-
- if (iax_set_codec(tech_pvt, tech_pvt->iax_session, &req, &cap, &samprate, IAX_QUERY) != SWITCH_STATUS_SUCCESS) {
- switch_core_session_destroy(new_session);
- return SWITCH_CAUSE_BEARERCAPABILITY_NOTIMPL;
- }
-
- if (samprate) {
- iax_set_samplerate(tech_pvt->iax_session, samprate);
- }
-
- iax_call(tech_pvt->iax_session,
- caller_profile->caller_id_number, caller_profile->caller_id_name, caller_profile->destination_number, NULL, 0, req, cap);
-
- switch_channel_set_flag(channel, CF_OUTBOUND);
- switch_set_flag_locked(tech_pvt, TFLAG_OUTBOUND);
- switch_channel_set_state(channel, CS_INIT);
- return SWITCH_CAUSE_SUCCESS;
- }
-
- return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
-}
-
-static switch_status_t channel_receive_event(switch_core_session_t *session, switch_event_t *event)
-{
- struct private_object *tech_pvt = switch_core_session_get_private(session);
- char *body = switch_event_get_body(event);
-
- switch_assert(tech_pvt != NULL);
-
- if (!body) {
- body = "";
- }
-
- iax_send_text(tech_pvt->iax_session, body);
-
- return SWITCH_STATUS_SUCCESS;
-}
-
-
-switch_state_handler_table_t iax_state_handlers = {
- /*.on_init */ channel_on_init,
- /*.on_routing */ channel_on_routing,
- /*.on_execute */ channel_on_execute,
- /*.on_hangup */ channel_on_hangup,
- /*.on_exchange_media */ channel_on_exchange_media,
- /*.on_soft_execute */ channel_on_soft_execute,
- /*.on_consume_media*/ NULL,
- /*.on_hibernate*/ NULL,
- /*.on_reset*/ NULL,
- /*.on_park*/ NULL,
- /*.on_reporting*/ NULL,
- /*.on_destroy*/ channel_on_destroy
-};
-
-switch_io_routines_t iax_io_routines = {
- /*.outgoing_channel */ channel_outgoing_channel,
- /*.read_frame */ channel_read_frame,
- /*.write_frame */ channel_write_frame,
- /*.kill_channel */ channel_kill_channel,
- /*.send_dtmf */ channel_send_dtmf,
- /*.receive_message */ channel_receive_message,
- /*.receive_event */ channel_receive_event
-};
-
-SWITCH_MODULE_LOAD_FUNCTION(mod_iax_load)
-{
- memset(&globals, 0, sizeof(globals));
-
- module_pool = pool;
-
- *module_interface = switch_loadable_module_create_module_interface(pool, modname);
- iax_endpoint_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_ENDPOINT_INTERFACE);
- iax_endpoint_interface->interface_name = "iax";
- iax_endpoint_interface->io_routines = &iax_io_routines;
- iax_endpoint_interface->state_handler = &iax_state_handlers;
-
- /* indicate that the module should continue to be loaded */
- return SWITCH_STATUS_SUCCESS;
-}
-
-#define PHONE_FREED 0
-#define PHONE_CALLACCEPTED 1
-#define PHONE_RINGING 2
-#define PHONE_ANSWERED 3
-#define PHONE_CONNECTED 4
-
-static switch_status_t load_config(void)
-{
- char *cf = "iax.conf";
- switch_xml_t cfg, xml, settings, param;
-
- memset(&globals, 0, sizeof(globals));
- switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, module_pool);
- if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", cf);
- return SWITCH_STATUS_TERM;
- }
-
- globals.media_timeout = 300;
-
- if ((settings = switch_xml_child(cfg, "settings"))) {
- for (param = switch_xml_child(settings, "param"); param; param = param->next) {
- char *var = (char *) switch_xml_attr_soft(param, "name");
- char *val = (char *) switch_xml_attr_soft(param, "value");
-
- if (!strcmp(var, "debug")) {
- globals.debug = atoi(val);
- } else if (!strcmp(var, "port")) {
- globals.port = atoi(val);
- } else if (!strcmp(var, "ip")) {
- set_global_ip(val);
- } else if (!strcmp(var, "codec-master")) {
- if (!strcasecmp(val, "us")) {
- switch_set_flag(&globals, GFLAG_MY_CODEC_PREFS);
- }
- } else if (!strcmp(var, "media-timeout")) {
- int mt = atoi(val);
- if (mt > 0) {
- globals.media_timeout = mt;
- }
- } else if (!strcmp(var, "dialplan")) {
- set_global_dialplan(val);
- } else if (!strcmp(var, "codec-prefs")) {
- set_global_codec_string(val);
- globals.codec_order_last = switch_separate_string(globals.codec_string, ',', globals.codec_order, SWITCH_MAX_CODECS);
- } else if (!strcmp(var, "codec-rates")) {
- set_global_codec_rates_string(val);
- globals.codec_rates_last = switch_separate_string(globals.codec_rates_string, ',', globals.codec_rates, SWITCH_MAX_CODECS);
- }
- }
- }
-
- if (!globals.dialplan) {
- set_global_dialplan("default");
- }
-
- if (!globals.port) {
- globals.port = 4569;
- }
-
- switch_xml_free(xml);
-
- return SWITCH_STATUS_SUCCESS;
-}
-
-static switch_status_t tech_media(private_t *tech_pvt, struct iax_event *iaxevent)
-{
- unsigned int cap = iax_session_get_capability(iaxevent->session);
- unsigned int format = iaxevent->ies.format;
- switch_status_t status = SWITCH_STATUS_SUCCESS;
-
- if (!switch_test_flag(tech_pvt, TFLAG_CODEC) &&
- (status = iax_set_codec(tech_pvt, iaxevent->session, &format, &cap, &iaxevent->ies.samprate, IAX_SET)) != SWITCH_STATUS_SUCCESS) {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Codec Error %u %u\n", iaxevent->ies.format, iaxevent->ies.capability);
- }
-
- return status;
-}
-
-SWITCH_MODULE_RUNTIME_FUNCTION(mod_iax_runtime)
-{
- struct iax_event *iaxevent = NULL;
- switch_event_t *s_event;
- if (load_config() != SWITCH_STATUS_SUCCESS) {
- return SWITCH_STATUS_TERM;
- }
-
- if (globals.debug > 1) {
- iax_enable_debug();
- }
- if (iax_init(globals.ip, globals.port) < 0) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Binding Port!\n");
- return SWITCH_STATUS_TERM;
- }
-
- iax_set_error(iax_err_cb);
- iax_set_output(iax_out_cb);
- globals.fd = iax_get_fd();
-
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "IAX Ready Port %d\n", globals.port);
-
- if (switch_event_create(&s_event, SWITCH_EVENT_PUBLISH) == SWITCH_STATUS_SUCCESS) {
- switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "service", "_iax2._udp");
- switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "port", "%d", globals.port);
- switch_event_fire(&s_event);
- }
-
- for (;;) {
- if (running == -1) {
- break;
- }
-
- /* Wait for an event. */
- if ((iaxevent = iax_get_event(0)) == NULL) {
- int waitlen = 0;
-
- if (globals.calls == 0) {
- waitlen = 10000;
- } else if (globals.calls < 10) {
- waitlen = 1000;
- } else {
- waitlen = 500;
- }
-
- switch_yield(waitlen);
- continue;
- } else {
- private_t *tech_pvt = NULL;
- switch_channel_t *channel = NULL;
-
- if ((tech_pvt = iax_get_private(iaxevent->session))) {
- channel = switch_core_session_get_channel(tech_pvt->session);
- }
-
- if (globals.debug && iaxevent->etype != IAX_EVENT_VOICE) {
- switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "Event %d [%s]!\n", iaxevent->etype, IAXNAMES[iaxevent->etype]);
- }
-
- switch_mutex_lock(globals.mutex);
- switch (iaxevent->etype) {
- case IAX_EVENT_REGACK:
- switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_NOTICE, "Registration completed successfully.\n");
- //if (iaxevent->ies.refresh)
- //refresh = iaxevent->ies.refresh;
- break;
- case IAX_EVENT_REGREJ:
- switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_NOTICE, "Registration failed.\n");
- break;
- case IAX_EVENT_REGREQ:
- /* what is the right way to handle this? */
- iax_reject_registration(iaxevent->session, NULL);
- break;
- case IAX_EVENT_TIMEOUT:
- break;
- case IAX_EVENT_ACCEPT:
- if (channel && !switch_channel_test_flag(channel, CF_ANSWERED)) {
- if (tech_media(tech_pvt, iaxevent) == SWITCH_STATUS_SUCCESS) {
- switch_channel_mark_pre_answered(channel);
- } else {
- switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
- }
- }
- switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_NOTICE, "Call accepted.\n");
- break;
- case IAX_EVENT_RINGA:
- if (channel) {
- switch_channel_mark_ring_ready(channel);
- }
- switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_NOTICE, "Ringing heard.\n");
- break;
- case IAX_EVENT_PONG:
- // informative only
- break;
- case IAX_EVENT_ANSWER:
- // the other side answered our call
- if (channel) {
- if (tech_media(tech_pvt, iaxevent) == SWITCH_STATUS_SUCCESS) {
- if (switch_channel_test_flag(channel, CF_ANSWERED)) {
- switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_WARNING, "Multiple Answer %s?\n", switch_channel_get_name(channel));
-
- } else {
- switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_NOTICE, "Answer %s\n", switch_channel_get_name(channel));
- switch_channel_mark_answered(channel);
- }
- } else {
- switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
- }
- }
- break;
- case IAX_EVENT_CONNECT:
- // incoming call detected
- switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_NOTICE,
- "Incoming call connected %s, %s, %s %u/%u\n",
- iaxevent->ies.called_number,
- iaxevent->ies.calling_number, iaxevent->ies.calling_name, iaxevent->ies.format, iaxevent->ies.capability);
-
- if (iaxevent) {
- switch_core_session_t *session;
-
- switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_NOTICE, "New Inbound Channel %s!\n", iaxevent->ies.calling_name);
- if ((session = switch_core_session_request(iax_endpoint_interface, SWITCH_CALL_DIRECTION_INBOUND, NULL)) != 0) {
- switch_core_session_add_stream(session, NULL);
- if ((tech_pvt = (private_t *) switch_core_session_alloc(session, sizeof(private_t))) != 0) {
- channel = switch_core_session_get_channel(session);
- tech_init(tech_pvt, session);
- } else {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Hey where is my memory pool?\n");
- switch_core_session_destroy(&session);
- break;
- }
-
- if ((tech_pvt->caller_profile = switch_caller_profile_new(switch_core_session_get_pool(session),
- iaxevent->ies.username,
- globals.dialplan,
- iaxevent->ies.calling_name,
- iaxevent->ies.calling_number,
- iax_get_peer_ip(iaxevent->session),
- iaxevent->ies.calling_ani,
- NULL,
- NULL,
- modname,
- iaxevent->ies.called_context, iaxevent->ies.called_number)) != 0) {
- char name[128];
- switch_snprintf(name, sizeof(name), "IAX/%s-%04x", tech_pvt->caller_profile->destination_number, rand() & 0xffff);
- switch_channel_set_name(channel, name);
- switch_channel_set_caller_profile(channel, tech_pvt->caller_profile);
- }
-
- if (iax_set_codec(tech_pvt, iaxevent->session,
- &iaxevent->ies.format, &iaxevent->ies.capability, &iaxevent->ies.samprate, IAX_SET) != SWITCH_STATUS_SUCCESS) {
- iax_reject(iaxevent->session, "Codec Error!");
- switch_core_session_destroy(&session);
- } else {
- tech_pvt->iax_session = iaxevent->session;
- tech_pvt->session = session;
- iax_accept(tech_pvt->iax_session, tech_pvt->codec);
- iax_ring_announce(tech_pvt->iax_session);
- switch_channel_set_state(channel, CS_INIT);
- if (switch_core_session_thread_launch(session) != SWITCH_STATUS_SUCCESS) {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Error spawning thread\n");
- switch_core_session_destroy(&session);
- }
- }
- }
- }
- break;
- case IAX_EVENT_REJECT:
- switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_NOTICE, "Rejected call.\n");
- case IAX_EVENT_BUSY:
- case IAX_EVENT_HANGUP:
- if (channel) {
- switch_mutex_lock(globals.mutex);
- switch_mutex_lock(tech_pvt->flag_mutex);
- switch_clear_flag(tech_pvt, TFLAG_IO);
- switch_clear_flag(tech_pvt, TFLAG_VOICE);
- switch_mutex_unlock(tech_pvt->flag_mutex);
-
-
- switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_NOTICE, "Hangup %s\n", switch_channel_get_name(channel));
- switch_set_flag_locked(tech_pvt, TFLAG_HANGUP);
- switch_channel_hangup(channel, iaxevent->etype == IAX_EVENT_HANGUP ? SWITCH_CAUSE_NORMAL_CLEARING : SWITCH_CAUSE_FACILITY_REJECTED);
- iaxevent->session = NULL;
- switch_mutex_unlock(globals.mutex);
- }
- break;
- case IAX_EVENT_CNG:
- // pseudo-silence
- switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_NOTICE, "sending silence\n");
- break;
- case IAX_EVENT_VOICE:
- if (tech_pvt && iaxevent->datalen) {
- if (channel && switch_channel_up(channel)) {
- int bytes = 0, frames = 1;
- switch_frame_t *frame = NULL;
-
- if (!switch_test_flag(tech_pvt, TFLAG_CODEC) || !tech_pvt->read_codec.implementation ||
- !switch_core_codec_ready(&tech_pvt->read_codec)) {
- switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
- break;
- }
-
- if (tech_pvt->read_codec.implementation->encoded_bytes_per_packet) {
- bytes = tech_pvt->read_codec.implementation->encoded_bytes_per_packet;
- frames = (int) (iaxevent->datalen / bytes);
- }
-
- switch_frame_alloc(&frame, iaxevent->datalen);
-
- memcpy(frame->data, iaxevent->data, iaxevent->datalen);
- frame->datalen = iaxevent->datalen;
- switch_queue_push(tech_pvt->frame_queue, frame);
- frame = NULL;
-
- /* wake up the i/o thread */
- switch_set_flag_locked(tech_pvt, TFLAG_VOICE);
- }
- }
- break;
- case IAX_EVENT_TRANSFER:
- switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_NOTICE, "Call transfer occurred.\n");
- break;
- case IAX_EVENT_DTMF:
- if (channel) {
- switch_dtmf_t dtmf = { (char) iaxevent->subclass, switch_core_default_dtmf_duration(0) };
- if (globals.debug) {
- switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_INFO, "%c DTMF %s\n", dtmf.digit, switch_channel_get_name(channel));
- }
- switch_mutex_lock(tech_pvt->flag_mutex);
- switch_channel_queue_dtmf(channel, &dtmf);
- switch_set_flag(tech_pvt, TFLAG_DTMF);
- switch_mutex_unlock(tech_pvt->flag_mutex);
- }
-
- break;
- default:
- switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "Don't know what to do with IAX event %d.\n", iaxevent->etype);
- break;
- }
- iax_event_free(iaxevent);
- switch_mutex_unlock(globals.mutex);
- }
- }
-
- running = 0;
-
- return SWITCH_STATUS_TERM;
-}
-
-
-SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_iax_shutdown)
-{
- int x = 0;
-
- running = -1;
-
- if (globals.fd) {
- /* Die Mutha $%#$@% Die Mutha $#%#$^ Die */
- shutdown(globals.fd, 2);
- }
- iax_shutdown();
-
- while (running) {
- if (x++ > 100) {
- break;
- }
- switch_yield(20000);
- }
-
- switch_safe_free(globals.dialplan);
- switch_safe_free(globals.codec_string);
- switch_safe_free(globals.codec_rates_string);
- switch_safe_free(globals.ip);
-
- return SWITCH_STATUS_SUCCESS;
-}
-
-/* For Emacs:
- * Local Variables:
- * mode:c
- * indent-tabs-mode:t
- * tab-width:4
- * c-basic-offset:4
- * End:
- * For VIM:
- * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
- */
+++ /dev/null
-<?xml version="1.0" encoding="Windows-1252"?>\r
-<VisualStudioProject\r
- ProjectType="Visual C++"\r
- Version="8.00"\r
- Name="mod_iax"\r
- ProjectGUID="{3A5B9131-F20C-4A85-9447-6C1610941CEE}"\r
- RootNamespace="mod_iax"\r
- Keyword="Win32Proj"\r
- TargetFrameworkVersion="131072"\r
- >\r
- <Platforms>\r
- <Platform\r
- Name="Win32"\r
- />\r
- </Platforms>\r
- <ToolFiles>\r
- </ToolFiles>\r
- <Configurations>\r
- <Configuration\r
- Name="Debug|Win32"\r
- ConfigurationType="2"\r
- InheritedPropertySheets="..\..\..\..\w32\module_debug.vsprops"\r
- CharacterSet="2"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- AdditionalIncludeDirectories="."\r
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;WIN32_TIME_GET_TIME;LIBIAX;NEWJB;_CRT_SECURE_NO_DEPRECATE;DEBUG_SUPPORT"\r
- UsePrecompiledHeader="0"\r
- DisableSpecificWarnings="4201;4200;4100;4127;6246;6053;6031;6262;4706"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalLibraryDirectories=""..\..\..\..\libs\iax\$(OutDir)""\r
- RandomizedBaseAddress="1"\r
- DataExecutionPrevention="0"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Release|Win32"\r
- ConfigurationType="2"\r
- InheritedPropertySheets="..\..\..\..\w32\module_release.vsprops"\r
- CharacterSet="2"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- AdditionalIncludeDirectories="."\r
- PreprocessorDefinitions="WIN32;_WINDOWS;_USRDLL;MOD_EXPORTS;LIBIAX;WIN32_TIME_GET_TIME;DEBUG_SUPPORT;NEWJB;_CRT_SECURE_NO_DEPRECATE"\r
- UsePrecompiledHeader="0"\r
- DisableSpecificWarnings="4201;4200;4100;4127;6246;6053;6031;6262;4706"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalLibraryDirectories=""..\..\..\..\libs\iax\$(OutDir)""\r
- RandomizedBaseAddress="1"\r
- DataExecutionPrevention="0"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- />\r
- </Configuration>\r
- </Configurations>\r
- <References>\r
- </References>\r
- <Files>\r
- <File\r
- RelativePath=".\iax-mutex.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\iax.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\iax2-parser.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\jitterbuf.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\md5.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\mod_iax.c"\r
- >\r
- </File>\r
- </Files>\r
- <Globals>\r
- </Globals>\r
-</VisualStudioProject>\r
+++ /dev/null
-/*
- * 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