first commit

This commit is contained in:
Your Name
2022-10-20 20:29:11 +08:00
commit 4d531f8044
3238 changed files with 1387862 additions and 0 deletions
+22
View File
@@ -0,0 +1,22 @@
AM_CFLAGS = -Wall -O2
AM_CFLAGS += -g -Wall -Wstrict-prototypes -I .
AM_CFLAGS += -DDEBUG_SUPPORT -DLIBIAX
AM_CFLAGS += -fsigned-char
# -DDEBUG_DEFAULT
AM_CFLAGS += $(UCFLAGS)
pkgdir = $(libdir)
pkg_LTLIBRARIES=libiax.la
libiax_la_SOURCES = iax2-parser.c iax.c md5.c jitterbuf.c
EXTRA_DIST = md5.h frame.h iax-client.h iax2.h iax2-parser.h jitterbuf.h
install-data-local:
mkdir -p $(includedir)/iax
install -m 644 md5.h $(includedir)/iax
install -m 644 frame.h $(includedir)/iax
install -m 644 iax.h $(includedir)/iax
install -m 644 iax2.h $(includedir)/iax
install -m 644 iax2-parser.h $(includedir)/iax
install -m 644 iax-client.h $(includedir)/iax
+237
View File
@@ -0,0 +1,237 @@
/*
* Signed 16-bit audio data
*
* Source: answer.raw
*
* Copyright (C) 1999, Mark Spencer and Linux Support Services
*
* Distributed under the terms of the GNU General Public License
*
*/
static signed short answer[] = {
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 0x19b7, 0x0245, 0xeee5, 0xb875, 0xd9a4, 0x6018, 0x660a, 0xc3c6,
0x8741, 0xff55, 0x4c2e, 0x2146, 0xfed2, 0xf079, 0xcbd4, 0xe561, 0x3c41, 0x3166,
0xd425, 0xdc59, 0x2748, 0x087d, 0xc72b, 0xfe3a, 0x4681, 0x14c6, 0xcf45, 0xdd38,
0xf8dd, 0x0a39, 0x3a5a, 0x32b9, 0xbfec, 0x957f, 0x15a3, 0x70f4, 0x1d95, 0xbfc4,
0xd367, 0xfda0, 0x0dc0, 0x29eb, 0x1fc2, 0xd684, 0xcab1, 0x19c7, 0x29ef, 0xe679,
0xe9d0, 0x2b82, 0x151a, 0xca9f, 0xdb68, 0x1f4a, 0x271c, 0x0e2a, 0xfb32, 0xd1b2,
0xc8ff, 0x2382, 0x6380, 0x0a52, 0xa118, 0xccbf, 0x2ddc, 0x33fd, 0x0964, 0xf2a4,
0xdd81, 0xe092, 0x1a00, 0x325c, 0xf5e3, 0xd6a1, 0x0b6c, 0x1c75, 0xe4f8, 0xe07c,
0x2082, 0x2b3e, 0xf445, 0xdaa9, 0xea13, 0xff3c, 0x245c, 0x35c1, 0xf308, 0xab53,
0xdf59, 0x4698, 0x3f3b, 0xe7f7, 0xca84, 0xed4d, 0x0c3f, 0x1e94, 0x1c2d, 0xf06f,
0xd4df, 0xff34, 0x23d8, 0x001e, 0xe3f1, 0x0b15, 0x2113, 0xf3fd, 0xd768, 0xf9a0,
0x1d31, 0x1c6e, 0x0797, 0xe3a0, 0xce6c, 0xfd7b, 0x422a, 0x2c4c, 0xd364, 0xbf42,
0x0278, 0x303e, 0x1c51, 0xf737, 0xe25a, 0xe75f, 0x0a8f, 0x22ab, 0x05f4, 0xe3f9,
0xf8c4, 0x1705, 0x0162, 0xe49f, 0xfb8b, 0x1e2b, 0x13ac, 0xf044, 0xe07b, 0xf01a,
0x1567, 0x2cbf, 0x0b75, 0xd01b, 0xd206, 0x1563, 0x38d7, 0x0f2e, 0xdb32, 0xdc30,
0x023b, 0x1e44, 0x16eb, 0xf5f7, 0xe425, 0xfa33, 0x14d5, 0x0968, 0xeff2, 0xf762,
0x1137, 0x0e59, 0xf13a, 0xe651, 0xff41, 0x1d60, 0x18fd, 0xf1e6, 0xd75f, 0xf097,
0x20ec, 0x27fa, 0xfba4, 0xd5b8, 0xe68e, 0x1657, 0x2518, 0x04f6, 0xe5a3, 0xe976,
0x0578, 0x18fa, 0x0a92, 0xec0a, 0xef2a, 0x111f, 0x12f4, 0xeec3, 0xe95e, 0x0d3a,
0x18fd, 0xff72, 0xeefc, 0xf114, 0xfaaa, 0x14ee, 0x21db, 0xf56e, 0xcb49, 0xf621,
0x3323, 0x1947, 0xe017, 0xe7e9, 0x0819, 0x0707, 0x084c, 0x0f57, 0xf152, 0xdf92,
0x104a, 0x28eb, 0xedcc, 0xd4ad, 0x1415, 0x296d, 0xed9a, 0xdf57, 0x0cc2, 0x0d95,
0xf7b5, 0x0deb, 0x0b34, 0xd713, 0xea08, 0x38d6, 0x216d, 0xc727, 0xdc32, 0x2cd2,
0x1822, 0xe2d5, 0xfeb3, 0x106c, 0xe6e5, 0xf81e, 0x2fe8, 0x01af, 0xc180, 0x037a,
0x42d8, 0xf88d, 0xc344, 0x0a4f, 0x2c4e, 0xf19d, 0xebeb, 0x162c, 0xf9e9, 0xde93,
0x1b56, 0x2c60, 0xd8aa, 0xce3e, 0x2a41, 0x2eeb, 0xdab1, 0xde32, 0x1c32, 0x0aba,
0xeabe, 0x1008, 0x136d, 0xda2f, 0xec3b, 0x31dd, 0x1130, 0xca79, 0xf5b8, 0x3423,
0x0274, 0xd27d, 0x035e, 0x1e68, 0xf641, 0xf904, 0x1691, 0xef7d, 0xd57a, 0x1c3b,
0x3c23, 0xe881, 0xc274, 0x0af5, 0x2962, 0xfa34, 0xf676, 0x0f71, 0xefcc, 0xe01f,
0x19e7, 0x276f, 0xe694, 0xe134, 0x1c3a, 0x0e8b, 0xd8e7, 0xfa81, 0x2f8b, 0x07c5,
0xd904, 0xf6fa, 0x0ca5, 0xf9a2, 0x0dc7, 0x2623, 0xec54, 0xbe23, 0x02b6, 0x4296,
0x10cd, 0xda61, 0xf11c, 0x0103, 0xf41c, 0x10b4, 0x2a03, 0xf63c, 0xce1a, 0xfdbd,
0x1fb4, 0xfc51, 0xf727, 0x1c8a, 0x04ff, 0xcf41, 0xec05, 0x2913, 0x1ce8, 0xf70c,
0xf744, 0xede8, 0xdd77, 0x0d99, 0x43f1, 0x119c, 0xc14f, 0xd60e, 0x17cb, 0x1e19,
0x0d4e, 0x0c95, 0xeed1, 0xcdf4, 0xf7a5, 0x331f, 0x1cd0, 0xeb17, 0xf082, 0xfb19,
0xe899, 0xfdeb, 0x323c, 0x2036, 0xdad3, 0xd134, 0xfd03, 0x1345, 0x1c10, 0x2239,
0xf656, 0xbc22, 0xdc3f, 0x3392, 0x3d59, 0xfd77, 0xdb4d, 0xe23f, 0xedbe, 0x0f7e,
0x35cc, 0x1947, 0xd5dc, 0xd1bf, 0x035d, 0x16fc, 0x1174, 0x1675, 0x0249, 0xd2d4,
0xd851, 0x184d, 0x32fe, 0x0f91, 0xee14, 0xe1e6, 0xdf9b, 0x016b, 0x3668, 0x2b2b,
0xe20c, 0xc554, 0xf257, 0x1c05, 0x1fc5, 0x14f0, 0xf891, 0xd41c, 0xdf83, 0x1865,
0x2de1, 0x0b16, 0xed58, 0xea0c, 0xea79, 0xfbd9, 0x22af, 0x2732, 0xf62f, 0xd389,
0xe7d9, 0x0b39, 0x1cdc, 0x1de3, 0x038a, 0xd809, 0xd5f7, 0x0b55, 0x305e, 0x1910,
0xf02e, 0xe089, 0xe7c7, 0x0195, 0x2265, 0x21da, 0xf743, 0xd8f2, 0xe978, 0x09a1,
0x190a, 0x17c5, 0x045a, 0xe46d, 0xdd06, 0xffb2, 0x2293, 0x1cfe, 0xfd4d, 0xe4f9,
0xe310, 0xfaf1, 0x1d22, 0x2376, 0x0113, 0xde3a, 0xe21b, 0x0204, 0x1ba1, 0x1bd6,
0x0333, 0xe563, 0xe104, 0xfd51, 0x1bc1, 0x1ccf, 0x0285, 0xe757, 0xe35e, 0xfaf2,
0x185d, 0x1d46, 0x06b7, 0xec13, 0xe108, 0xef6e, 0x121d, 0x2a17, 0x16a6, 0xe32c,
0xc9a9, 0xf070, 0x2f48, 0x3788, 0xfa4e, 0xc32a, 0xd9c2, 0x1fa1, 0x36fe, 0x07fa,
0xd9e4, 0xe577, 0x0e5e, 0x1755, 0xfb53, 0xed71, 0x0540, 0x19e0, 0x0301, 0xdc97,
0xe391, 0x1937, 0x367c, 0x0bc9, 0xca4c, 0xc96b, 0x105d, 0x461f, 0x2416, 0xd481,
0xbc97, 0xf8b7, 0x39af, 0x2ec9, 0xecc6, 0xcb50, 0xeee3, 0x1ffe, 0x1e8e, 0xf700,
0xe66a, 0xff58, 0x149f, 0x02e5, 0xe792, 0xf2d8, 0x1a4d, 0x225a, 0xf642, 0xce7f,
0xe6a6, 0x25e2, 0x38f5, 0x01d0, 0xc50f, 0xd243, 0x19bd, 0x3fc6, 0x14f0, 0xd2d7,
0xcdb6, 0x069a, 0x2ffe, 0x1847, 0xe6f8, 0xdf0a, 0x0337, 0x1a90, 0x067a, 0xeb5b,
0xf541, 0x143b, 0x14f2, 0xf092, 0xdc02, 0xfb91, 0x28a3, 0x2274, 0xeaa8, 0xc9e7,
0xef48, 0x2d01, 0x322e, 0xf6d2, 0xc7cb, 0xe13b, 0x1fda, 0x3217, 0x0458, 0xd690,
0xe2bf, 0x11c4, 0x21d5, 0x0291, 0xe5c8, 0xf3a9, 0x12ba, 0x11aa, 0xf22b, 0xe627,
0x03ec, 0x219a, 0x1036, 0xe2f2, 0xd93f, 0x059c, 0x2ed6, 0x1b75, 0xe227, 0xce55,
0xfb19, 0x2de0, 0x2477, 0xed08, 0xd148, 0xf307, 0x21d4, 0x2002, 0xf543, 0xdeac,
0xf7f9, 0x18a9, 0x11d6, 0xf0ef, 0xe8e4, 0x05ea, 0x1ba5, 0x0727, 0xe448, 0xe748,
0x100e, 0x265e, 0x07fc, 0xdbae, 0xde78, 0x0efa, 0x2ce0, 0x0f94, 0xddf1, 0xd9ea,
0x0797, 0x28f6, 0x12eb, 0xe60c, 0xdf46, 0x0469, 0x1fbb, 0x0ced, 0xe9f6, 0xe95f,
0x09fe, 0x1ab9, 0x02cb, 0xe5a4, 0xef2a, 0x1327, 0x1d7b, 0xfd07, 0xde3d, 0xed9c,
0x17e5, 0x22e7, 0xfe3a, 0xdb38, 0xe9b9, 0x161a, 0x2416, 0x0175, 0xde3d, 0xe9de,
0x1294, 0x1fc9, 0x00ea, 0xe2a7, 0xeee2, 0x1298, 0x1a7d, 0xfc1d, 0xe3bb, 0xf47a,
0x1642, 0x185e, 0xf727, 0xe1af, 0xf709, 0x19c3, 0x18e7, 0xf50d, 0xe010, 0xf75b,
0x1a9c, 0x18d8, 0xf4c5, 0xe0c9, 0xf865, 0x1a1c, 0x16d5, 0xf3a6, 0xe257, 0xfaf2,
0x1a44, 0x14d5, 0xf34f, 0xe4b6, 0xfc77, 0x17d5, 0x0ff8, 0xf133, 0xe8b7, 0x0344,
0x1a37, 0x0ad5, 0xe95e, 0xe61a, 0x08a5, 0x227e, 0x0e33, 0xe4a7, 0xdd70, 0x03b0,
0x25f4, 0x17b2, 0xec0a, 0xdb4e, 0xf898, 0x1ba3, 0x18f6, 0xf973, 0xe87f, 0xf77a,
0x0b93, 0x096c, 0xfb0e, 0xfb03, 0x0896, 0x0940, 0xf51d, 0xe904, 0xfdc7, 0x1dda,
0x1bf9, 0xf29b, 0xd37f, 0xea1b, 0x1f37, 0x3175, 0x07eb, 0xd3f7, 0xd46b, 0x077d,
0x2eeb, 0x1e67, 0xeeae, 0xd8c7, 0xef85, 0x1119, 0x18d3, 0x088e, 0xf953, 0xf5ad,
0xf556, 0xf63d, 0x0234, 0x167a, 0x19a1, 0xfbf9, 0xd873, 0xdd4b, 0x0f06, 0x3748,
0x21e6, 0xe181, 0xc032, 0xe79a, 0x2bec, 0x3e76, 0x0b1b, 0xce41, 0xcb23, 0xff96,
0x2d79, 0x26d1, 0xfcc7, 0xdf8a, 0xe525, 0xfd83, 0x10f1, 0x16d7, 0x0f50, 0xfaea,
0xe3f1, 0xe20f, 0x0158, 0x27d9, 0x2866, 0xf96f, 0xcb34, 0xd563, 0x11d6, 0x3d25,
0x2424, 0xe254, 0xc2c9, 0xe7cd, 0x248d, 0x34f5, 0x0c42, 0xdcd0, 0xd827, 0xfa65,
0x19eb, 0x1b50, 0x0721, 0xf396, 0xeb9c, 0xefde, 0x0016, 0x1594, 0x1cc1, 0x0658,
0xe22b, 0xd852, 0xfb3e, 0x2923, 0x2c78, 0xfc87, 0xcdb5, 0xd69c, 0x0e3c, 0x3527,
0x201f, 0xe993, 0xcf9e, 0xeb21, 0x183f, 0x25ea, 0x0c93, 0xed4d, 0xe5f9, 0xf548,
0x07fb, 0x117c, 0x0ff2, 0x0398, 0xf08c, 0xe628, 0xf489, 0x143b, 0x2419, 0x0ccf,
0xe2cc, 0xd5a6, 0xf861, 0x2615, 0x2a1b, 0xfeb4, 0xd543, 0xdc53, 0x09b4, 0x2901,
0x19ff, 0xf24a, 0xde86, 0xeec4, 0x0b7b, 0x1733, 0x0d0a, 0xfc24, 0xf1bb, 0xf110,
0xfa03, 0x0a0f, 0x15d4, 0x0e21, 0xf435, 0xe17e, 0xee90, 0x1225, 0x2527, 0x0efa,
0xe61f, 0xd916, 0xf7b8, 0x1f50, 0x2326, 0x0099, 0xe01e, 0xe473, 0x0491, 0x1b37,
0x1360, 0xfb17, 0xecd9, 0xf20d, 0x0051, 0x0aec, 0x0d4a, 0x073d, 0xfa5a, 0xeeb8,
0xf165, 0x0516, 0x17dc, 0x12da, 0xf71b, 0xe213, 0xed85, 0x0eef, 0x20c8, 0x0e09,
0xebcc, 0xe0d4, 0xf848, 0x1637, 0x19d6, 0x026b, 0xec09, 0xed00, 0xff9b, 0x0e5a,
0x0d6b, 0x026c, 0xf865, 0xf4da, 0xf888, 0x025a, 0x0cbb, 0x0d53, 0xff96, 0xeefa,
0xee80, 0x021c, 0x15d6, 0x126a, 0xf9c1, 0xe724, 0xf017, 0x0aa1, 0x18b6, 0x0b4e,
0xf2d7, 0xea91, 0xf957, 0x0cac, 0x1061, 0x03f4, 0xf6ad, 0xf476, 0xfbdf, 0x0489,
0x08b1, 0x06df, 0xffcf, 0xf766, 0xf537, 0xfddf, 0x0ad4, 0x0e15, 0x01da, 0xf205,
0xf0a0, 0x0082, 0x1066, 0x0e41, 0xfc71, 0xef1b, 0xf4ad, 0x05cd, 0x0f32, 0x07ed,
0xf9c8, 0xf401, 0xfa93, 0x04af, 0x088c, 0x04a7, 0xfe15, 0xf9f1, 0xfa64, 0xff1e,
0x0539, 0x078c, 0x02af, 0xfa1a, 0xf69d, 0xfd09, 0x075b, 0x0a3d, 0x01f2, 0xf761,
0xf642, 0xffa7, 0x08f3, 0x0830, 0xff05, 0xf7db, 0xf9bc, 0x0174, 0x068b, 0x04b2,
0xfeff, 0xfb39, 0xfc1a, 000000, 0x0371, 0x03d7, 0x00fe, 0xfd37, 0xfbe0, 0xfe78,
0x02af, 0x044a, 0x0180, 0xfd43, 0xfc00, 0xfed1, 0x02aa, 0x0346, 0x00dd, 0xfde0,
0xfbfe, 0x0114, 0x0987, 0x04bc, 0xf49d, 0xf23a, 0x06ab, 0x162e, 0x0544, 0xe76b,
0xea25, 0x1015, 0x2474, 0x0431, 0xd7d3, 0xe1ec, 0x1923, 0x2df5, 0x01cd, 0xd386,
0xe3d9, 0x1b9d, 0x2c62, 0xfeb8, 0xd31a, 0xe6ba, 0x1dbd, 0x2abb, 0xfbab, 0xd2ed,
0xe9ab, 0x1fa7, 0x28ef, 0xf8b3, 0xd2f5, 0xeca5, 0x2160, 0x26fd, 0xf5d7, 0xd334,
0xefa1, 0x22e5, 0x24ea, 0xf31b, 0xd3a9, 0xf29f, 0x2435, 0x22b6, 0xf07e, 0xd44e,
0xf59b, 0x2551, 0x2067, 0xee08, 0xd527, 0xf88e, 0x2639, 0x1e00, 0xebb6, 0xd62d,
0xfb77, 0x26eb, 0x1b85, 0xe98b, 0xd75f, 0xfe51, 0x276b, 0x18f9, 0xe78e, 0xd8b9,
0x011a, 0x27b6, 0x1660, 0xe5bb, 0xda3a, 0x03cc, 0x27cf, 0x13bd, 0xe415, 0xdbdf,
0x066a, 0x27b7, 0x1117, 0xe29e, 0xdda5, 0x08ec, 0x276e, 0x0e6d, 0xe154, 0xdf89,
0x0b52, 0x26f6, 0x0bc7, 0xe039, 0xe185, 0x0d96, 0x2653, 0x0924, 0xdf4e, 0xe399,
0x0fb9, 0x2584, 0x068b, 0xde93, 0xe5c0, 0x11b8, 0x248e, 0x03fd, 0xde08, 0xe7f8,
0x1390, 0x2372, 0x0180, 0xddaa, 0xea3c, 0x1544, 0x2231, 0xff12, 0xdd7a, 0xec89,
0x16cf, 0x20d0, 0xfcb9, 0xdd77, 0xeedb, 0x1831, 0x1f52, 0xfa77, 0xdd9f, 0xf132,
0x1969, 0x1db7, 0xf850, 0xddf1, 0xf385, 0x1a75, 0x1c06, 0xf645, 0xde6b, 0xf5d7,
0x1b5b, 0x1a3f, 0xf457, 0xdf0d, 0xf820, 0x1c13, 0x1867, 0xf288, 0xdfd2, 0xfa5f,
0x1ca1, 0x167f, 0xf0db, 0xe0ba, 0xfc92, 0x1d06, 0x148b, 0xef50, 0xe1c1, 0xfeb5,
0x1d43, 0x1290, 0xede9, 0xe2e6, 0x00c6, 0x1d58, 0x108e, 0xeca7, 0xe426, 0x02c4,
0x1d45, 0x0e8a, 0xeb8a, 0xe57f, 0x04a9, 0x1d0e, 0x0c87, 0xea92, 0xe6ec, 0x0677,
0x1cb2, 0x0a87, 0xe9be, 0xe86e, 0x082a, 0x1c34, 0x088b, 0xe912, 0xe9fe, 0x09c1,
0x1b95, 0x069c, 0xe88c, 0xeb9c, 0x0b3a, 0x1ad9, 0x04b6, 0xe82a, 0xed43, 0x0c96,
0x1a00, 0x02df, 0xe7eb, 0xeef3, 0x0dd0, 0x190d, 0x0116, 0xe7d0, 0xf0a8, 0x0eec,
0x1804, 0xff61, 0xe7d8, 0xf25d, 0x0fe6, 0x16e3, 0xfdc0, 0xe800, 0xf412, 0x10bf,
0x15b1, 0xfc36, 0xe848, 0xf5c5, 0x1176, 0x146e, 0xfac2, 0xe8ad, 0xf771, 0x120d,
0x1320, 0xf969, 0xe92e, 0xf913, 0x1282, 0x11c4, 0xf828, 0xe9cb, 0xfaac, 0x12d8,
0x1062, 0xf703, 0xea7e, 0xfc38, 0x130e, 0x0efa, 0xf5fb, 0xeb49, 0xfdb5, 0x1325,
0x0d8e, 0xf50e, 0xec26, 0xff20, 0x131e, 0x0c21, 0xf43f, 0xed15, 0x007a, 0x12fa,
0x0ab6, 0xf38d, 0xee15, 0x01be, 0x12bd, 0x094f, 0xf2f9, 0xef22, 0x02ef, 0x1265,
0x07f0, 0xf283, 0xf037, 0x0408, 0x11f6, 0x0699, 0xf226, 0xf156, 0x050a, 0x1170,
0x054b, 0xf1e8, 0xf27a, 0x05f4, 0x10d8, 0x040c, 0xf1c5, 0xf3a3, 0x06c2, 0x102c,
0x02da, 0xf1bc, 0xf4cc, 0x0779, 0x0f71, 0x01b7, 0xf1cc, 0xf5f5, 0x0815, 0x0ea7,
0x00a8, 0xf1f4, 0xf719, 0x0899, 0x0dd2, 0xffab, 0xf233, 0xf839, 0x0902, 0x0cf4,
0xfec0, 0xf288, 0xf950, 0x0952, 0x0c0e, 0xfdec, 0xf2ee, 0xfa5d, 0x0989, 0x0b23,
0xfd2d, 0xf368, 0xfb62, 0x09a7, 0x0a35, 0xfc85, 0xf3f1, 0xfc58, 0x09af, 0x0946,
0xfbf2, 0xf488, 0xfd3f, 0x09a1, 0x0859, 0xfb77, 0xf52c, 0xfe17, 0x097d, 0x076f,
0xfb14, 0xf5d8, 0xfede, 0x0945, 0x068a, 0xfac6, 0xf68d, 0xff93, 0x08fb, 0x05ad,
0xfa8e, 0xf747, 0x0034, 0x08a1, 0x04da, 0xfa6f, 0xf805, 0x00c2, 0x0836, 0x0410,
0xfa63, 0xf8c6, 0x013c, 0x07bf, 0x0354, 0xfa6c, 0xf985, 0x01a1, 0x073b, 0x02a4,
0xfa8a, 0xfa43, 0x01f1, 0x06af, 0x0204, 0xfab9, 0xfafc, 0x022c, 0x0619, 0x0175,
0xfafa, 0xfbae, 0x0252, 0x057f, 0x00f6, 0xfb4b, 0xfc5a, 0x0263, 0x04e0, 0x008b,
0xfbaa, 0xfcfa, 0x0262, 0x0440, 0x0032, 0xfc16, 0xfd90, 0x024b, 0x03a0, 0xffec,
0xfc8c, 0xfe19, 0x0225, 0x0301, 0xffb9, 0xfd0c, 0xfe93, 0x01ea, 0x0267, 0xff9c,
0xfd95, 0xfefe, 0x01a0, 0x01d3, 0xff90, 0xfe22, 0xff5a, 0x0147, 0x0145, 0xff99,
0xfeb3, 0xffa1, 0x00e0, 0x00c3, 0xffb6, 0xff46, 0xffd9, 0x006d, 0x004b, 0xffe5,
0xffda, 0xfffc, 000000, 0xfffe, 000000, 0xffff, 000000, 0xffff, 0xffff, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
000000 };
+55
View File
@@ -0,0 +1,55 @@
/* busy.h: Generated from frequencies 480 and 620
by gensound. 400 samples */
static short busy[400] = {
0, 13697, 24766, 31109, 31585, 26222, 16198, 3569,
-9162, -19575, -25812, -26935, -23069, -15322, -5493, 4339,
12277, 16985, 17934, 15440, 10519, 4585, -908, -4827,
-6592, -6269, -4489, -2220, -467, 30, -983, -3203,
-5839, -7844, -8215, -6301, -2035, 3975, 10543, 16141,
19260, 18787, 14322, 6338, -3845, -14296, -22858, -27611,
-27309, -21691, -11585, 1213, 14285, 25068, 31388, 31915,
26457, 16010, 2568, -11282, -22885, -30054, -31509, -27120,
-17908, -5805, 6760, 17379, 24147, 26028, 23020, 16094,
6931, -2478, -10279, -15136, -16474, -14538, -10253, -4949,
0, 3515, 5052, 4688, 3045, 1069, -268, -272,
1269, 3996, 7067, 9381, 9889, 7910, 3365, -3123,
-10320, -16622, -20424, -20510, -16384, -8448, 2006, 13026,
22383, 28040, 28613, 23696, 13996, 1232, -12193, -23670,
-30918, -32459, -27935, -18190, -5103, 8795, 20838, 28764,
31164, 27753, 19395, 7893, -4412, -15136, -22342, -24909,
-22717, -16609, -8143, 780, 8361, 13272, 14909, 13455,
9758, 5067, 678, -2387, -3624, -3133, -1538, 224,
1209, 751, -1315, -4580, -8145, -10848, -11585, -9628,
-4878, 2038, 9844, 16867, 21403, 22124, 18429, 10638,
0, -11524, -21643, -28211, -29702, -25561, -16364, -3737,
9946, 22044, 30180, 32733, 29182, 20210, 7573, -6269,
-18655, -27259, -30558, -28117, -20645, -9807, 2148, 12878,
20426, 23599, 22173, 16865, 9117, 731, -6552, -11426,
-13269, -12216, -9050, -4941, -1118, 1460, 2335, 1635,
0, -1635, -2335, -1460, 1118, 4941, 9050, 12216,
13269, 11426, 6552, -731, -9117, -16865, -22173, -23599,
-20426, -12878, -2148, 9807, 20645, 28117, 30558, 27259,
18655, 6269, -7573, -20210, -29182, -32733, -30180, -22044,
-9946, 3737, 16364, 25561, 29702, 28211, 21643, 11524,
0, -10638, -18429, -22124, -21403, -16867, -9844, -2038,
4878, 9628, 11585, 10848, 8145, 4580, 1315, -751,
-1209, -224, 1538, 3133, 3624, 2387, -678, -5067,
-9758, -13455, -14909, -13272, -8361, -780, 8143, 16609,
22717, 24909, 22342, 15136, 4412, -7893, -19395, -27753,
-31164, -28764, -20838, -8795, 5103, 18190, 27935, 32459,
30918, 23670, 12193, -1232, -13996, -23696, -28613, -28040,
-22383, -13026, -2006, 8448, 16384, 20510, 20424, 16622,
10320, 3123, -3365, -7910, -9889, -9381, -7067, -3996,
-1269, 272, 268, -1069, -3045, -4688, -5052, -3515,
0, 4949, 10253, 14538, 16474, 15136, 10279, 2478,
-6931, -16094, -23020, -26028, -24147, -17379, -6760, 5805,
17908, 27120, 31509, 30054, 22885, 11282, -2568, -16010,
-26457, -31915, -31388, -25068, -14285, -1213, 11585, 21691,
27309, 27611, 22858, 14296, 3845, -6338, -14322, -18787,
-19260, -16141, -10543, -3975, 2035, 6301, 8215, 7844,
5839, 3203, 983, -30, 467, 2220, 4489, 6269,
6592, 4827, 908, -4585, -10519, -15440, -17934, -16985,
-12277, -4339, 5493, 15322, 23069, 26935, 25812, 19575,
9162, -3569, -16198, -26222, -31585, -31109, -24766, -13697,
};
+105
View File
@@ -0,0 +1,105 @@
/* dialtone.h: Generated from frequencies 350 and 440
by gensound. 800 samples */
static short dialtone[800] = {
0, 9997, 19004, 26133, 30692, 32251, 30690, 26206,
19286, 10657, 1206, -8116, -16396, -22848, -26895, -28221,
-26797, -22878, -16960, -9723, -1954, 5545, 12044, 16954,
19887, 20687, 19434, 16420, 12107, 7061, 1881, -2866,
-6721, -9365, -10657, -10634, -9491, -7547, -5190, -2822,
-801, 607, 1263, 1168, 454, -633, -1784, -2669,
-2993, -2548, -1247, 855, 3558, 6538, 9388, 11665,
12955, 12933, 11408, 8370, 3996, -1349, -7152, -12797,
-17635, -21060, -22583, -21895, -18914, -13807, -6985, 934,
9180, 16913, 23309, 27654, 29422, 28342, 24429, 17998,
9630, 123, -9589, -18538, -25813, -30667, -32588, -31360,
-27088, -20185, -11332, -1411, 8594, 17694, 24997, 29805,
31675, 30473, 26374, 19844, 11585, 2455, -6618, -14745,
-21156, -25284, -26815, -25713, -22213, -16785, -10073, -2824,
4203, 10318, 14969, 17794, 18653, 17628, 14998, 11197,
6753, 2217, -1899, -5189, -7386, -8388, -8261, -7212,
-5555, -3657, -1881, -536, 169, 157, -515, -1664,
-3009, -4217, -4954, -4940, -3996, -2080, 697, 4081,
7689, 11059, 13710, 15199, 15187, 13489, 10114, 5272,
-630, -7031, -13263, -18632, -22491, -24320, -23794, -20823,
-15582, -8498, -218, 8457, 16651, 23507, 28276, 30407,
29606, 25876, 19524, 11134, 1511, -8401, -17616, -25208,
-30406, -32682, -31800, -27845, -21215, -12576, -2796, 7150,
16278, 23700, 28713, 30868, 30015, 26312, 20199, 12351,
3598, -5164, -13071, -19378, -23531, -25223, -24413, -21318,
-16384, -10218, -3526, 2980, 8655, 12985, 15642, 16505,
15661, 13381, 10073, 6228, 2348, -1110, -3796, -5495,
-6152, -5863, -4853, -3434, -1954, -744, -62, -60,
-757, -2037, -3664, -5317, -6637, -7283, -6985, -5590,
-3096, 334, 4390, 8631, 12544, 15605, 17339, 17393,
15582, 11928, 6672, 258, -6705, -13506, -19403, -23711,
-25879, -25558, -22653, -17341, -10061, -1480, 7570, 16185,
23475, 28661, 31164, 30670, 27167, 20951, 12603, 2930,
-7116, -16540, -24401, -29915, -32533, -32003, -28391, -22075,
-13704, -4128, 5690, 14781, 22262, 27432, 29838, 29319,
26014, 20339, 12940, 4614, -3777, -11401, -17540, -21660,
-23463, -22908, -20199, -15755, -10150, -4044, 1898, 7079,
11030, 13459, 14268, 13555, 11585, 8745, 5487, 2268,
-511, -2559, -3716, -3975, -3468, -2440, -1206, -101,
578, 618, -78, -1470, -3382, -5524, -7531, -9018,
-9630, -9103, -7308, -4280, -226, 4483, 9357, 13829,
17329, 19352, 19524, 17659, 13788, 8177, 1302, -6184,
-13528, -19945, -24710, -27240, -27167, -24381, -19058, -11646,
-2830, 6539, 15528, 23219, 28806, 31685, 31520, 28282,
22254, 14010, 4355, -5759, -15331, -23411, -29203, -32144,
-31966, -28714, -22748, -14695, -5384, 4241, 13228, 20707,
25981, 28600, 28391, 25479, 20256, 13337, 5482, -2482,
-9761, -15668, -19694, -21556, -21215, -18865, -14902, -9864,
-4366, 975, 5614, 9130, 11270, 11967, 11332, 9628,
7223, 4536, 1976, -113, -1495, -2071, -1882, -1102,
0, 1102, 1882, 2071, 1495, 113, -1976, -4536,
-7223, -9628, -11332, -11967, -11270, -9130, -5614, -975,
4366, 9864, 14902, 18865, 21215, 21556, 19694, 15668,
9761, 2482, -5482, -13337, -20256, -25479, -28391, -28600,
-25981, -20707, -13228, -4241, 5384, 14695, 22748, 28714,
31966, 32144, 29203, 23411, 15331, 5759, -4355, -14010,
-22254, -28282, -31520, -31685, -28806, -23219, -15528, -6539,
2830, 11646, 19058, 24381, 27167, 27240, 24710, 19945,
13528, 6184, -1302, -8177, -13788, -17659, -19524, -19352,
-17329, -13829, -9357, -4483, 226, 4280, 7308, 9103,
9630, 9018, 7531, 5524, 3382, 1470, 78, -618,
-578, 101, 1206, 2440, 3468, 3975, 3716, 2559,
511, -2268, -5487, -8745, -11585, -13555, -14268, -13459,
-11030, -7079, -1898, 4044, 10150, 15755, 20199, 22908,
23463, 21660, 17540, 11401, 3777, -4614, -12940, -20339,
-26014, -29319, -29838, -27432, -22262, -14781, -5690, 4128,
13704, 22075, 28391, 32003, 32533, 29915, 24401, 16540,
7116, -2930, -12603, -20951, -27167, -30670, -31164, -28661,
-23475, -16185, -7570, 1480, 10061, 17341, 22653, 25558,
25879, 23711, 19403, 13506, 6705, -258, -6672, -11928,
-15582, -17393, -17339, -15605, -12544, -8631, -4390, -334,
3096, 5590, 6985, 7283, 6637, 5317, 3664, 2037,
757, 60, 62, 744, 1954, 3434, 4853, 5863,
6152, 5495, 3796, 1110, -2348, -6228, -10073, -13381,
-15661, -16505, -15642, -12985, -8655, -2980, 3526, 10218,
16384, 21318, 24413, 25223, 23531, 19378, 13071, 5164,
-3598, -12351, -20199, -26312, -30015, -30868, -28713, -23700,
-16278, -7150, 2796, 12576, 21215, 27845, 31800, 32682,
30406, 25208, 17616, 8401, -1511, -11134, -19524, -25876,
-29606, -30407, -28276, -23507, -16651, -8457, 218, 8498,
15582, 20823, 23794, 24320, 22491, 18632, 13263, 7031,
630, -5272, -10114, -13489, -15187, -15199, -13710, -11059,
-7689, -4081, -697, 2080, 3996, 4940, 4954, 4217,
3009, 1664, 515, -157, -169, 536, 1881, 3657,
5555, 7212, 8261, 8388, 7386, 5189, 1899, -2217,
-6753, -11197, -14998, -17628, -18653, -17794, -14969, -10318,
-4203, 2824, 10073, 16785, 22213, 25713, 26815, 25284,
21156, 14745, 6618, -2455, -11585, -19844, -26374, -30473,
-31675, -29805, -24997, -17694, -8594, 1411, 11332, 20185,
27088, 31360, 32588, 30667, 25813, 18538, 9589, -123,
-9630, -17998, -24429, -28342, -29422, -27654, -23309, -16913,
-9180, -934, 6985, 13807, 18914, 21895, 22583, 21060,
17635, 12797, 7152, 1349, -3996, -8370, -11408, -12933,
-12955, -11665, -9388, -6538, -3558, -855, 1247, 2548,
2993, 2669, 1784, 633, -454, -1168, -1263, -607,
801, 2822, 5190, 7547, 9491, 10634, 10657, 9365,
6721, 2866, -1881, -7061, -12107, -16420, -19434, -20687,
-19887, -16954, -12044, -5545, 1954, 9723, 16960, 22878,
26797, 28221, 26895, 22848, 16396, 8116, -1206, -10657,
-19286, -26206, -30690, -32251, -30692, -26133, -19004, -9997,
};
+142
View File
@@ -0,0 +1,142 @@
/*
* 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)
/*! H.263+ Video */
#define AST_FORMAT_H263p (1 << 20)
/*! H.264 Video*/
#define AST_FORMAT_H264 (1 << 21)
/*! MPEG4 Video*/
#define AST_FORMAT_MPEG4 (1 << 22)
/*! Theora Video */
#define AST_FORMAT_THEORA (1 << 24)
/*! 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
+259
View File
@@ -0,0 +1,259 @@
/*
* 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
#if defined(_MSC_VER)
/* disable zero-sized array in struct/union warning */
#pragma warning(disable:4200)
#endif
#ifdef WIN32
#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
#define IAX_EVENT_VIDEO 34 /* Send/receive video */
/* 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
/*
* Null event. We use it to notify back the caller that a frame has been
* received and is queued for delivery
* Applciations should simply ignore it
*/
#define IAX_EVENT_NULL 65535
#define IAX_SCHEDULE_FUZZ 0 /* ms of fuzz to drop */
#if defined(WIN32) || defined(_WIN32_WCE)
#if defined(_MSC_VER)
typedef int (__stdcall *iax_sendto_t)(SOCKET, const void *, size_t, int,
const struct sockaddr *, socklen_t);
typedef int (__stdcall *iax_recvfrom_t)(SOCKET, void *, size_t, int,
struct sockaddr *, socklen_t *);
#else
typedef int PASCAL (*iax_sendto_t)(SOCKET, const char *, int, int,
const struct sockaddr *, int);
typedef int PASCAL (*iax_recvfrom_t)(SOCKET, char *, int, int,
struct sockaddr *, int *);
#endif
#else
typedef int (*iax_sendto_t)(int, const void *, size_t, int,
const struct sockaddr *, socklen_t);
typedef int (*iax_recvfrom_t)(int, void *, size_t, int,
struct sockaddr *, socklen_t *);
#endif
struct iax_event {
int etype; /* Type of event */
int subclass; /* Subclass data (event specific) */
unsigned int 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[0]; /* 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(int preferredportno);
/* 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 int 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, const char *url, int link);
extern int iax_send_text(struct iax_session *session, const char *text);
extern int iax_send_ping(struct iax_session *session);
extern int iax_load_complete(struct iax_session *session);
extern int iax_reject(struct iax_session *session, char *reason);
extern int iax_busy(struct iax_session *session);
extern int iax_congestion(struct iax_session *session);
extern int iax_hangup(struct iax_session *session, char *byemsg);
extern int iax_call(struct iax_session *session, const char *cidnum, const char *cidname, const char *ich, const 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, const char *hostname, const char *peer, const char *secret, int refresh);
extern int iax_unregister(struct iax_session *session, const char *hostname, const char *peer, const char *secret, const char *reason);
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, const char *number);
extern int iax_quelch_moh(struct iax_session *session, int MOH);
extern int iax_send_video(struct iax_session *session, int format, unsigned char *data, int datalen, int fullframe);
extern int iax_send_video_trunk(struct iax_session *session, int format, char *data, int datalen, int fullframe, int ntrunk);
extern void iax_destroy(struct iax_session * session);
extern void iax_enable_debug(void);
extern void iax_disable_debug(void);
extern struct timeval iax_tvnow(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 {
int jitter;
int losspct;
int losscnt;
int packets;
int delay;
int dropped;
int ooo;
};
/* fills in rtt, and an iax_netstat structure for each of local/remote directions of call */
extern int iax_get_netstats(struct iax_session *s, int *rtt, struct iax_netstat *local, struct iax_netstat *remote);
extern void iax_set_private(struct iax_session *s, void *pvt);
extern void *iax_get_private(struct iax_session *s);
extern void iax_set_sendto(struct iax_session *s, iax_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(iax_sendto_t st, iax_recvfrom_t rf);
/* destroy an iax session */
extern void iax_session_destroy(struct iax_session **session);
/* To control use of jitter buffer for video event */
int iax_video_bypass_jitter(struct iax_session*, int );
/* 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 );
/* Portable 'decent' random number generation */
extern void iax_seed_random(void);
extern int iax_random(void);
#if defined(__cplusplus)
}
#endif
#endif /* _ASTERISK_IAX_CLIENT_H */
File diff suppressed because it is too large Load Diff
+86
View File
@@ -0,0 +1,86 @@
/*
* 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[0];
};
/* 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[0];
};
#endif
+822
View File
@@ -0,0 +1,822 @@
/*
* 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
*/
#if defined(WIN32) || defined(_WIN32_WCE)
#include "winpoop.h"
#define snprintf _snprintf
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
#ifndef _MSC_VER
#include <unistd.h>
#endif
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "frame.h"
#include "iax2.h"
#include "iax2-parser.h"
static int frames = 0;
static int iframes = 0;
static int oframes = 0;
#ifdef ALIGN32
static unsigned int get_uint32(unsigned char *p)
{
return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
}
static unsigned short get_uint16(unsigned char *p)
{
return (p[0] << 8) | p[1] ;
}
#else
#define get_uint32(p) (*((unsigned int *)(p)))
#define get_uint16(p) (*((unsigned short *)(p)))
#endif
static void internaloutput(const char *str)
{
//printf(str);
}
static void internalerror(const char *str)
{
fprintf(stderr, "WARNING: %s", str);
}
static void (*outputf)(const char *str) = internaloutput;
static void (*errorf)(const char *str) = internalerror;
static void dump_addr(char *output, int maxlen, void *value, int len)
{
struct sockaddr_in sin;
if (len == sizeof(sin)) {
memcpy(&sin, value, len);
snprintf(output, maxlen, "IPV4 %s:%d", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
} else {
snprintf(output, maxlen, "Invalid Address");
}
}
static void dump_string(char *output, int maxlen, void *value, int len)
{
maxlen--;
if (maxlen > len)
maxlen = len;
strncpy(output,(const char *)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");
}
static void dump_samprate(char *output, int maxlen, void *value, int len)
{
char tmp[256]="";
int sr;
if (len == (int)sizeof(unsigned short)) {
sr = ntohs(*((unsigned short *)value));
if (sr & IAX_RATE_8KHZ)
strcat(tmp, ",8khz");
if (sr & IAX_RATE_11KHZ)
strcat(tmp, ",11.025khz");
if (sr & IAX_RATE_16KHZ)
strcat(tmp, ",16khz");
if (sr & IAX_RATE_22KHZ)
strcat(tmp, ",22.05khz");
if (sr & IAX_RATE_44KHZ)
strcat(tmp, ",44.1khz");
if (sr & IAX_RATE_48KHZ)
strcat(tmp, ",48khz");
if (strlen(tmp))
strncpy(output, &tmp[1], maxlen - 1);
else
strncpy(output, "None specified!\n", maxlen - 1);
} else
snprintf(output, maxlen, "Invalid SHORT");
}
static void dump_prov_ies(char *output, int maxlen, unsigned char *iedata, int len);
static void dump_prov(char *output, int maxlen, void *value, int len)
{
dump_prov_ies(output, maxlen, (unsigned char *)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_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_CODEC_PREFS, "CODEC_PREFS", dump_string },
{ IAX_IE_RR_JITTER, "RR_JITTER", dump_int },
{ IAX_IE_RR_LOSS, "RR_LOSS", dump_int },
{ IAX_IE_RR_PKTS, "RR_PKTS", dump_int },
{ IAX_IE_RR_DELAY, "RR_DELAY", dump_short },
{ IAX_IE_RR_DROPPED, "RR_DROPPED", dump_int },
{ IAX_IE_RR_OOO, "RR_OOO", dump_int },
};
const char *iax_ie2str(int ie)
{
int x;
for (x=0;x<(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 ",
"CONGESTION ",
"FLASH ",
"WINK ",
"OPTION "
};
struct ast_iax2_full_hdr *fh;
char retries[20];
char class2[20];
char subclass2[20];
const char *clas;
const char *subclass;
char tmp[256];
if (f) {
fh = (struct ast_iax2_full_hdr *)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)/sizeof(char *))) {
snprintf(class2, (int)sizeof(class2), "(%d?)", fh->type);
clas = class2;
} else {
clas = 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)/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, clas, subclass);
outputf(tmp);
snprintf(tmp, (int)sizeof(tmp),
" Timestamp: %05lums SCall: %5.5d DCall: %5.5d [%s:%d]\n",
(unsigned long)ntohl(fh->ts),
ntohs(fh->scallno) & ~IAX_FLAG_FULL, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS,
inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
outputf(tmp);
if (fh->type == AST_FRAME_IAX)
dump_ies(fh->iedata, datalen);
}
int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, const void *data, int datalen)
{
char tmp[256];
if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
snprintf(tmp, (int)sizeof(tmp), "Out of space for ie '%s' (%d), need %d have %d\n", iax_ie2str(ie), ie, datalen, (int)sizeof(ied->buf) - ied->pos);
errorf(tmp);
return -1;
}
ied->buf[ied->pos++] = ie;
ied->buf[ied->pos++] = datalen;
memcpy(ied->buf + ied->pos, data, datalen);
ied->pos += datalen;
return 0;
}
int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, struct sockaddr_in *sin)
{
return iax_ie_append_raw(ied, ie, sin, (int)sizeof(struct sockaddr_in));
}
int iax_ie_append_int(struct iax_ie_data *ied, unsigned char ie, unsigned int value)
{
unsigned int newval;
newval = htonl(value);
return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
}
int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsigned short value)
{
unsigned short newval;
newval = htons(value);
return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
}
int iax_ie_append_str(struct iax_ie_data *ied, unsigned char ie, const char *str)
{
return iax_ie_append_raw(ied, ie, str, (int)strlen(str));
}
int iax_ie_append_byte(struct iax_ie_data *ied, unsigned char ie, unsigned char dat)
{
return iax_ie_append_raw(ied, ie, &dat, 1);
}
int iax_ie_append(struct iax_ie_data *ied, unsigned char ie)
{
return iax_ie_append_raw(ied, ie, NULL, 0);
}
void iax_set_output(void (*func)(const char *))
{
outputf = func;
}
void iax_set_error(void (*func)(const char *))
{
errorf = func;
}
int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
{
/* Parse data into information elements */
int len;
int ie;
char tmp[256];
memset(ies, 0, (int)sizeof(struct iax_ies));
ies->msgcount = -1;
ies->firmwarever = -1;
ies->calling_ton = -1;
ies->calling_tns = -1;
ies->calling_pres = -1;
ies->samprate = IAX_RATE_8KHZ;
while(datalen >= 2) {
ie = data[0];
len = data[1];
if (len > datalen - 2) {
errorf("Information element length exceeds message size\n");
return -1;
}
switch(ie) {
case IAX_IE_CALLED_NUMBER:
ies->called_number = (char *) data + 2;
break;
case IAX_IE_CALLING_NUMBER:
ies->calling_number = (char *) data + 2;
break;
case IAX_IE_CALLING_ANI:
ies->calling_ani = (char *) data + 2;
break;
case IAX_IE_CALLING_NAME:
ies->calling_name = (char *) data + 2;
break;
case IAX_IE_CALLED_CONTEXT:
ies->called_context = (char *) data + 2;
break;
case IAX_IE_USERNAME:
ies->username = (char *) data + 2;
break;
case IAX_IE_PASSWORD:
ies->password = (char *) data + 2;
break;
case IAX_IE_CAPABILITY:
if (len != (int)sizeof(unsigned int)) {
snprintf(tmp, (int)sizeof(tmp), "Expecting capability to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
errorf(tmp);
} else
ies->capability = ntohl(get_uint32(data + 2));
break;
case IAX_IE_FORMAT:
if (len != (int)sizeof(unsigned int)) {
snprintf(tmp, (int)sizeof(tmp), "Expecting format to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
errorf(tmp);
} else
ies->format = ntohl(get_uint32(data + 2));
break;
case IAX_IE_LANGUAGE:
ies->language = (char *) data + 2;
break;
case IAX_IE_CODEC_PREFS:
ies->codec_prefs = (char *) data + 2;
break;
case IAX_IE_VERSION:
if (len != (int)sizeof(unsigned short)) {
snprintf(tmp, (int)sizeof(tmp), "Expecting version to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
errorf(tmp);
} else
ies->version = ntohs(get_uint16(data + 2));
break;
case IAX_IE_ADSICPE:
if (len != (int)sizeof(unsigned short)) {
snprintf(tmp, (int)sizeof(tmp), "Expecting adsicpe to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
errorf(tmp);
} else
ies->adsicpe = ntohs(get_uint16(data + 2));
break;
case IAX_IE_SAMPLINGRATE:
if (len != (int)sizeof(unsigned short)) {
snprintf(tmp, (int)sizeof(tmp), "Expecting samplingrate to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
errorf(tmp);
} else
ies->samprate = ntohs(get_uint16(data + 2));
break;
case IAX_IE_DNID:
ies->dnid = (char *) data + 2;
break;
case IAX_IE_RDNIS:
ies->rdnis = (char *) data + 2;
break;
case IAX_IE_AUTHMETHODS:
if (len != (int)sizeof(unsigned short)) {
snprintf(tmp, (int)sizeof(tmp), "Expecting authmethods to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
errorf(tmp);
} else
ies->authmethods = ntohs(get_uint16(data + 2));
break;
case IAX_IE_CHALLENGE:
ies->challenge = (char *) data + 2;
break;
case IAX_IE_MD5_RESULT:
ies->md5_result = (char *) data + 2;
break;
case IAX_IE_RSA_RESULT:
ies->rsa_result = (char *) data + 2;
break;
case IAX_IE_APPARENT_ADDR:
ies->apparent_addr = ((struct sockaddr_in *)(data + 2));
break;
case IAX_IE_REFRESH:
if (len != (int)sizeof(unsigned short)) {
snprintf(tmp, (int)sizeof(tmp), "Expecting refresh to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
errorf(tmp);
} else
ies->refresh = ntohs(get_uint16(data + 2));
break;
case IAX_IE_DPSTATUS:
if (len != (int)sizeof(unsigned short)) {
snprintf(tmp, (int)sizeof(tmp), "Expecting dpstatus to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
errorf(tmp);
} else
ies->dpstatus = ntohs(get_uint16(data + 2));
break;
case IAX_IE_CALLNO:
if (len != (int)sizeof(unsigned short)) {
snprintf(tmp, (int)sizeof(tmp), "Expecting callno to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
errorf(tmp);
} else
ies->callno = ntohs(get_uint16(data + 2));
break;
case IAX_IE_CAUSE:
ies->cause = (char *) data + 2;
break;
case IAX_IE_CAUSECODE:
if (len != 1) {
snprintf(tmp, (int)sizeof(tmp), "Expecting causecode to be single byte but was %d\n", len);
errorf(tmp);
} else {
ies->causecode = data[2];
}
break;
case IAX_IE_IAX_UNKNOWN:
if (len == 1)
ies->iax_unknown = data[2];
else {
snprintf(tmp, (int)sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len);
errorf(tmp);
}
break;
case IAX_IE_MSGCOUNT:
if (len != (int)sizeof(unsigned short)) {
snprintf(tmp, (int)sizeof(tmp), "Expecting msgcount to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
errorf(tmp);
} else
ies->msgcount = ntohs(get_uint16(data + 2));
break;
case IAX_IE_AUTOANSWER:
ies->autoanswer = 1;
break;
case IAX_IE_MUSICONHOLD:
ies->musiconhold = 1;
break;
case IAX_IE_TRANSFERID:
if (len != (int)sizeof(unsigned int)) {
snprintf(tmp, (int)sizeof(tmp), "Expecting transferid to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
errorf(tmp);
} else
ies->transferid = ntohl(get_uint32(data + 2));
break;
case IAX_IE_DATETIME:
if (len != (int)sizeof(unsigned int)) {
snprintf(tmp, (int)sizeof(tmp), "Expecting date/time to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
errorf(tmp);
} else
ies->datetime = ntohl(get_uint32(data + 2));
break;
case IAX_IE_FIRMWAREVER:
if (len != (int)sizeof(unsigned short)) {
snprintf(tmp, (int)sizeof(tmp), "Expecting firmwarever to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
errorf(tmp);
} else
ies->firmwarever = ntohs(get_uint16(data + 2));
break;
case IAX_IE_DEVICETYPE:
ies->devicetype = (char *) data + 2;
break;
case IAX_IE_SERVICEIDENT:
ies->serviceident = (char *) data + 2;
break;
case IAX_IE_FWBLOCKDESC:
if (len != (int)sizeof(unsigned int)) {
snprintf(tmp, (int)sizeof(tmp), "Expected block desc to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
errorf(tmp);
} else
ies->fwdesc = ntohl(get_uint32(data + 2));
break;
case IAX_IE_FWBLOCKDATA:
ies->fwdata = data + 2;
ies->fwdatalen = len;
break;
case IAX_IE_PROVVER:
if (len != (int)sizeof(unsigned int)) {
snprintf(tmp, (int)sizeof(tmp), "Expected provisioning version to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
errorf(tmp);
} else {
ies->provverpres = 1;
ies->provver = ntohl(get_uint32(data + 2));
}
break;
case IAX_IE_CALLINGPRES:
if (len == 1)
ies->calling_pres = data[2];
else {
snprintf(tmp, (int)sizeof(tmp), "Expected single byte callingpres, but was %d long\n", len);
errorf(tmp);
}
break;
case IAX_IE_CALLINGTON:
if (len == 1)
ies->calling_ton = data[2];
else {
snprintf(tmp, (int)sizeof(tmp), "Expected single byte callington, but was %d long\n", len);
errorf(tmp);
}
break;
case IAX_IE_CALLINGTNS:
if (len != (int)sizeof(unsigned short)) {
snprintf(tmp, (int)sizeof(tmp), "Expecting callingtns to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
errorf(tmp);
} else
ies->calling_tns = ntohs(get_uint16(data + 2));
break;
case IAX_IE_RR_JITTER:
if (len != (int)sizeof(unsigned int)) {
snprintf(tmp, (int)sizeof(tmp), "Expected jitter rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
errorf(tmp);
} else {
ies->rr_jitter = ntohl(get_uint32(data + 2));
}
break;
case IAX_IE_RR_LOSS:
if (len != (int)sizeof(unsigned int)) {
snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
errorf(tmp);
} else {
ies->rr_loss = ntohl(get_uint32(data + 2));
}
break;
case IAX_IE_RR_PKTS:
if (len != (int)sizeof(unsigned int)) {
snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
errorf(tmp);
} else {
ies->rr_pkts = ntohl(get_uint32(data + 2));
}
break;
case IAX_IE_RR_DELAY:
if (len != (int)sizeof(unsigned short)) {
snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
errorf(tmp);
} else {
ies->rr_delay = ntohs(get_uint16(data + 2));
}
break;
case IAX_IE_RR_DROPPED:
if (len != (int)sizeof(unsigned int)) {
snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
errorf(tmp);
} else {
ies->rr_dropped = ntohl(get_uint32(data + 2));
}
break;
case IAX_IE_RR_OOO:
if (len != (int)sizeof(unsigned int)) {
snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
errorf(tmp);
} else {
ies->rr_ooo = ntohl(get_uint32(data + 2));
}
break;
default:
snprintf(tmp, (int)sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len);
outputf(tmp);
}
/* Overwrite information element with 0, to null terminate previous portion */
data[0] = 0;
datalen -= (len + 2);
data += (len + 2);
}
/* Null-terminate last field */
*data = '\0';
if (datalen) {
errorf("Invalid information element contents, strange boundary\n");
return -1;
}
return 0;
}
void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f)
{
fr->af.frametype = f->frametype;
fr->af.subclass = f->subclass;
fr->af.mallocd = 0; /* Our frame is static relative to the container */
fr->af.datalen = f->datalen;
fr->af.samples = f->samples;
fr->af.offset = AST_FRIENDLY_OFFSET;
fr->af.src = f->src;
fr->af.data = fr->afdata;
if (fr->af.datalen)
memcpy(fr->af.data, f->data, fr->af.datalen);
}
struct iax_frame *iax_frame_new(int direction, int datalen)
{
struct iax_frame *fr;
fr = (struct iax_frame *)malloc((int)sizeof(struct iax_frame) + datalen);
if (fr) {
fr->direction = direction;
fr->retrans = -1;
frames++;
if (fr->direction == DIRECTION_INGRESS)
iframes++;
else
oframes++;
}
return fr;
}
void iax_frame_free(struct iax_frame *fr)
{
/* Note: does not remove from scheduler! */
if (fr->direction == DIRECTION_INGRESS)
iframes--;
else if (fr->direction == DIRECTION_OUTGRESS)
oframes--;
else {
errorf("Attempt to double free frame detected\n");
return;
}
fr->direction = 0;
free(fr);
frames--;
}
int iax_get_frames(void) { return frames; }
int iax_get_iframes(void) { return iframes; }
int iax_get_oframes(void) { return oframes; }
+146
View File
@@ -0,0 +1,146 @@
/*
* 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) */
unsigned int ts;
/* How long to wait before retrying */
int 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[0]; /* 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 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
+223
View File
@@ -0,0 +1,223 @@
/*
* 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
/* 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_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(_MSC_VER)
#pragma pack(push,1)
#define __PACKED
#else
#define __PACKED __attribute__ ((__packed__))
#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[0];
} __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[0];
} __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[0];
} __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[0];
} __PACKED;
struct ast_iax2_meta_trunk_hdr {
unsigned int ts; /* 32-bit timestamp for all messages */
unsigned char data[0];
} __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[0];
} __PACKED;
#if defined(_MSC_VER)
#pragma pack(pop)
#endif
#undef __PACKED
#endif
+833
View File
@@ -0,0 +1,833 @@
/*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include "jitterbuf.h"
/* define these here, just for ancient compiler systems */
#define JB_LONGMAX 2147483647L
#define JB_LONGMIN (-JB_LONGMAX - 1L)
/* MS VC can't do __VA_ARGS__ */
#if (defined(WIN32) || defined(_WIN32_WCE)) && defined(_MSC_VER)
#define jb_warn if (warnf) warnf
#define jb_err if (errf) errf
#define jb_dbg if (dbgf) dbgf
#ifdef DEEP_DEBUG
#define jb_dbg2 if (dbgf) dbgf
#else
#define jb_dbg2 if (0) dbgf
#endif
#else
#define jb_warn(...) (warnf ? warnf(__VA_ARGS__) : (void)0)
#define jb_err(...) (errf ? errf(__VA_ARGS__) : (void)0)
#define jb_dbg(...) (dbgf ? dbgf(__VA_ARGS__) : (void)0)
#ifdef DEEP_DEBUG
#define jb_dbg2(...) (dbgf ? dbgf(__VA_ARGS__) : (void)0)
#else
#define jb_dbg2(...) ((void)0)
#endif
#endif
static jb_output_function_t warnf, errf, dbgf;
void jb_setoutput(jb_output_function_t err, jb_output_function_t warn, jb_output_function_t dbg)
{
errf = err;
warnf = warn;
dbgf = dbg;
}
static void increment_losspct(jitterbuf *jb)
{
jb->info.losspct = (100000 + 499 * jb->info.losspct)/500;
}
static void decrement_losspct(jitterbuf *jb)
{
jb->info.losspct = (499 * jb->info.losspct)/500;
}
void jb_reset(jitterbuf *jb)
{
/* only save settings */
jb_conf s = jb->info.conf;
memset(jb, 0, sizeof(*jb));
jb->info.conf = s;
/* initialize length, using the configured value */
jb->info.current = jb->info.target = jb->info.conf.target_extra;
jb->info.silence_begin_ts = -1;
}
jitterbuf * jb_new()
{
jitterbuf *jb;
if (!(jb = (jitterbuf *)malloc(sizeof(*jb))))
return NULL;
jb->info.conf.target_extra = JB_TARGET_EXTRA;
jb_reset(jb);
jb_dbg2("jb_new() = %x\n", jb);
return jb;
}
void jb_destroy(jitterbuf *jb)
{
jb_frame *frame;
jb_dbg2("jb_destroy(%x)\n", jb);
/* free all the frames on the "free list" */
frame = jb->free;
while (frame != NULL) {
jb_frame *next = frame->next;
free(frame);
frame = next;
}
/* free ourselves! */
free(jb);
}
#if 0
static int longcmp(const void *a, const void *b)
{
return *(long *)a - *(long *)b;
}
#endif
/* simple history manipulation */
/* maybe later we can make the history buckets variable size, or something? */
/* drop parameter determines whether we will drop outliers to minimize
* delay */
static int history_put(jitterbuf *jb, long ts, long now, long ms)
{
long delay = now - (ts - jb->info.resync_offset);
long threshold = 2 * jb->info.jitter + jb->info.conf.resync_threshold;
long kicked;
/* don't add special/negative times to history */
if (ts <= 0)
return 0;
/* check for drastic change in delay */
if (jb->info.conf.resync_threshold != -1) {
if (labs(delay - jb->info.last_delay) > threshold) {
jb->info.cnt_delay_discont++;
if (jb->info.cnt_delay_discont > 3) {
/* resync the jitterbuffer */
jb->info.cnt_delay_discont = 0;
jb->hist_ptr = 0;
jb->hist_maxbuf_valid = 0;
jb_warn("Resyncing the jb. last_delay %ld, this delay %ld, threshold %ld, new offset %ld\n", jb->info.last_delay, delay, threshold, ts - now);
jb->info.resync_offset = ts - now;
jb->info.last_delay = delay = 0; /* after resync, frame is right on time */
} else {
return -1;
}
} else {
jb->info.last_delay = delay;
jb->info.cnt_delay_discont = 0;
}
}
kicked = jb->history[jb->hist_ptr % JB_HISTORY_SZ];
jb->history[(jb->hist_ptr++) % JB_HISTORY_SZ] = delay;
/* optimization; the max/min buffers don't need to be recalculated,
* if this packet's entry doesn't change them. This happens if this
* packet is not involved, _and_ any packet that got kicked out of
* the history is also not involved. We do a number of comparisons,
* but it's probably still worthwhile, because it will usually
* succeed, and should be a lot faster than going through all 500
* packets in history */
if (!jb->hist_maxbuf_valid)
return 0;
/* don't do this until we've filled history
* (reduces some edge cases below) */
if (jb->hist_ptr < JB_HISTORY_SZ)
goto invalidate;
/* if the new delay would go into min */
if (delay < jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1])
goto invalidate;
/* or max.. */
if (delay > jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1])
goto invalidate;
/* or the kicked delay would be in min */
if (kicked <= jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1])
goto invalidate;
if (kicked >= jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1])
goto invalidate;
/* if we got here, we don't need to invalidate, 'cause this delay didn't
* affect things */
return 0;
/* end optimization */
invalidate:
jb->hist_maxbuf_valid = 0;
return 0;
}
static void history_calc_maxbuf(jitterbuf *jb)
{
int i,j;
if (jb->hist_ptr == 0)
return;
/* initialize maxbuf/minbuf to the latest value */
for (i=0;i<JB_HISTORY_MAXBUF_SZ;i++) {
/*
* jb->hist_maxbuf[i] = jb->history[(jb->hist_ptr-1) % JB_HISTORY_SZ];
* jb->hist_minbuf[i] = jb->history[(jb->hist_ptr-1) % JB_HISTORY_SZ];
*/
jb->hist_maxbuf[i] = JB_LONGMIN;
jb->hist_minbuf[i] = JB_LONGMAX;
}
/* use insertion sort to populate maxbuf */
/* we want it to be the top "n" values, in order */
/* start at the beginning, or JB_HISTORY_SZ frames ago */
i = (jb->hist_ptr > JB_HISTORY_SZ) ? (jb->hist_ptr - JB_HISTORY_SZ) : 0;
for (;i<jb->hist_ptr;i++) {
long toins = jb->history[i % JB_HISTORY_SZ];
/* if the maxbuf should get this */
if (toins > jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1]) {
/* insertion-sort it into the maxbuf */
for (j=0;j<JB_HISTORY_MAXBUF_SZ;j++) {
/* found where it fits */
if (toins > jb->hist_maxbuf[j]) {
/* move over */
memmove(jb->hist_maxbuf + j + 1, jb->hist_maxbuf + j, (JB_HISTORY_MAXBUF_SZ - (j + 1)) * sizeof(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");
}
}
jb->hist_maxbuf_valid = 1;
}
static void history_get(jitterbuf *jb)
{
long max, min, jitter;
int index;
int count;
if (!jb->hist_maxbuf_valid)
history_calc_maxbuf(jb);
/* count is how many items in history we're examining */
count = (jb->hist_ptr < JB_HISTORY_SZ) ? jb->hist_ptr : JB_HISTORY_SZ;
/* index is the "n"ths highest/lowest that we'll look for */
index = count * JB_HISTORY_DROPPCT / 100;
/* sanity checks for index */
if (index > (JB_HISTORY_MAXBUF_SZ - 1))
index = JB_HISTORY_MAXBUF_SZ - 1;
if (index < 0) {
jb->info.min = 0;
jb->info.jitter = 0;
return;
}
max = jb->hist_maxbuf[index];
min = jb->hist_minbuf[index];
jitter = max - min;
/* these debug stmts compare the difference between looking at the absolute jitter, and the
* values we get by throwing away the outliers */
/*
fprintf(stderr, "[%d] min=%d, max=%d, jitter=%d\n", index, min, max, jitter);
fprintf(stderr, "[%d] min=%d, max=%d, jitter=%d\n", 0, jb->hist_minbuf[0], jb->hist_maxbuf[0], jb->hist_maxbuf[0]-jb->hist_minbuf[0]);
*/
jb->info.min = min;
jb->info.jitter = jitter;
}
/* returns 1 if frame was inserted into head of queue, 0 otherwise */
static int queue_put(jitterbuf *jb, void *data, const enum jb_frame_type type, long ms, long ts)
{
jb_frame *frame;
jb_frame *p;
int head = 0;
long resync_ts = ts - jb->info.resync_offset;
if ((frame = jb->free)) {
jb->free = frame->next;
} else if (!(frame = (jb_frame *)malloc(sizeof(*frame)))) {
jb_err("cannot allocate frame\n");
return 0;
}
jb->info.frames_cur++;
frame->data = data;
frame->ts = resync_ts;
frame->ms = ms;
frame->type = type;
/*
* frames are a circular list, jb-frames points to to the lowest ts,
* jb->frames->prev points to the highest ts
*/
if (!jb->frames) { /* queue is empty */
jb->frames = frame;
frame->next = frame;
frame->prev = frame;
head = 1;
} else if (resync_ts < jb->frames->ts) {
frame->next = jb->frames;
frame->prev = jb->frames->prev;
frame->next->prev = frame;
frame->prev->next = frame;
/* frame is out of order */
jb->info.frames_ooo++;
jb->frames = frame;
head = 1;
} else {
p = jb->frames;
/* frame is out of order */
if (resync_ts < p->prev->ts) jb->info.frames_ooo++;
while (resync_ts < p->prev->ts && p->prev != jb->frames)
p = p->prev;
frame->next = p;
frame->prev = p->prev;
frame->next->prev = frame;
frame->prev->next = frame;
}
return head;
}
static long queue_next(jitterbuf *jb)
{
if (jb->frames)
return jb->frames->ts;
else
return -1;
}
static long queue_last(jitterbuf *jb)
{
if (jb->frames)
return jb->frames->prev->ts;
else
return -1;
}
static jb_frame *_queue_get(jitterbuf *jb, long ts, int all)
{
jb_frame *frame;
frame = jb->frames;
if (!frame)
return NULL;
/*jb_warn("queue_get: ASK %ld FIRST %ld\n", ts, frame->ts); */
if (all || ts >= frame->ts) {
/* remove this frame */
frame->prev->next = frame->next;
frame->next->prev = frame->prev;
if (frame->next == frame)
jb->frames = NULL;
else
jb->frames = frame->next;
/* insert onto "free" single-linked list */
frame->next = jb->free;
jb->free = frame;
jb->info.frames_cur--;
/* we return the frame pointer, even though it's on free list,
* but caller must copy data */
return frame;
}
return NULL;
}
static jb_frame *queue_get(jitterbuf *jb, long ts)
{
return _queue_get(jb,ts,0);
}
static jb_frame *queue_getall(jitterbuf *jb)
{
return _queue_get(jb,0,1);
}
#if 0
/* some diagnostics */
static void jb_dbginfo(jitterbuf *jb)
{
if (dbgf == NULL)
return;
jb_dbg("\njb info: fin=%ld fout=%ld flate=%ld flost=%ld fdrop=%ld fcur=%ld\n",
jb->info.frames_in, jb->info.frames_out, jb->info.frames_late, jb->info.frames_lost, jb->info.frames_dropped, jb->info.frames_cur);
jb_dbg("jitter=%ld current=%ld target=%ld min=%ld sil=%d len=%d len/fcur=%ld\n",
jb->info.jitter, jb->info.current, jb->info.target, jb->info.min, jb->info.silence_begin_ts, jb->info.current - jb->info.min,
jb->info.frames_cur ? (jb->info.current - jb->info.min)/jb->info.frames_cur : -8);
if (jb->info.frames_in > 0)
jb_dbg("jb info: Loss PCT = %ld%%, Late PCT = %ld%%\n",
jb->info.frames_lost * 100/(jb->info.frames_in + jb->info.frames_lost),
jb->info.frames_late * 100/jb->info.frames_in);
jb_dbg("jb info: queue %d -> %d. last_ts %d (queue len: %d) last_ms %d\n",
queue_next(jb),
queue_last(jb),
jb->info.next_voice_ts,
queue_last(jb) - queue_next(jb),
jb->info.last_voice_ms);
}
#endif
#ifdef DEEP_DEBUG
static void jb_chkqueue(jitterbuf *jb)
{
int i=0;
jb_frame *p = jb->frames;
if (!p) {
return;
}
do {
if (p->next == NULL) {
jb_err("Queue is BROKEN at item [%d]", i);
}
i++;
p=p->next;
} while (p->next != jb->frames);
}
static void jb_dbgqueue(jitterbuf *jb)
{
int i=0;
jb_frame *p = jb->frames;
jb_dbg("queue: ");
if (!p) {
jb_dbg("EMPTY\n");
return;
}
do {
jb_dbg("[%d]=%ld ", i++, p->ts);
p=p->next;
} while (p->next != jb->frames);
jb_dbg("\n");
}
#endif
enum jb_return_code jb_put(jitterbuf *jb, void *data, const enum jb_frame_type type, long ms, long ts, long now)
{
jb_dbg2("jb_put(%x,%x,%ld,%ld,%ld)\n", jb, data, ms, ts, now);
jb->info.frames_in++;
if (type == JB_TYPE_VOICE) {
/* presently, I'm only adding VOICE frames to history and drift
* calculations; mostly because with the IAX integrations, I'm
* sending retransmitted control frames with their awkward
* timestamps through
*/
if (history_put(jb,ts,now,ms))
return JB_DROP;
}
/* if put into head of queue, caller needs to reschedule */
if (queue_put(jb,data,type,ms,ts)) {
return JB_SCHED;
}
return JB_OK;
}
static enum jb_return_code _jb_get(jitterbuf *jb, jb_frame *frameout, long now, long interpl)
{
jb_frame *frame;
long diff;
/*if ((now - jb_next(jb)) > 2 * jb->info.last_voice_ms) jb_warn("SCHED: %ld", (now - jb_next(jb))); */
/* get jitter info */
history_get(jb);
/* target */
jb->info.target = jb->info.jitter + jb->info.min + jb->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;
}
}
}
long jb_next(jitterbuf *jb)
{
if (jb->info.silence_begin_ts) {
if (jb->frames) {
long 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, long 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;
}
+162
View File
@@ -0,0 +1,162 @@
/*
* 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.*/
long jitter; /* jitter measured within current history interval*/
long min; /* minimum lateness within current history interval */
long current; /* the present jitterbuffer adjustment */
long target; /* the target jitterbuffer adjustment */
long losspct; /* recent lost frame percentage (* 1000) */
long next_voice_ts; /* the ts of the next frame to be read from the jb - in receiver's time */
long last_voice_ms; /* the duration of the last voice frame */
long silence_begin_ts; /* the time of the last CNG frame, when in silence */
long last_adjustment; /* the time of the last adjustment */
long last_delay; /* the last now added to history */
long cnt_delay_discont; /* the count of discontinuous delays */
long resync_offset; /* the amount to offset ts to support resyncs */
long cnt_contig_interp; /* the number of contiguous interp frames returned */
} jb_info;
typedef struct jb_frame {
void *data; /* the frame data */
long ts; /* the relative delivery time expected */
long ms; /* the time covered by this frame, in sec/8000 */
enum jb_frame_type type; /* the type of frame */
struct jb_frame *next, *prev;
} jb_frame;
typedef struct jitterbuf {
jb_info info;
/* history */
long history[JB_HISTORY_SZ]; /* history */
int hist_ptr; /* points to index in history for next entry */
long hist_maxbuf[JB_HISTORY_MAXBUF_SZ]; /* a sorted buffer of the max delays (highest first) */
long hist_minbuf[JB_HISTORY_MAXBUF_SZ]; /* a sorted buffer of the min delays (lowest first) */
int hist_maxbuf_valid; /* are the "maxbuf"/minbuf valid? */
jb_frame *frames; /* queued frames */
jb_frame *free; /* free frames (avoid malloc?) */
} jitterbuf;
/* new jitterbuf */
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, long ts, long now);
/* get a frame for time now (receiver's time) return value is one of
* JB_OK: You've got frame!
* JB_DROP: Here's an audio frame you should just drop. Ask me again for this time..
* JB_NOFRAME: There's no frame scheduled for this time.
* JB_INTERP: Please interpolate an interpl-length frame for this time (either we need to grow, or there was a lost frame)
* JB_EMPTY: The jb is empty.
*/
enum jb_return_code jb_get(jitterbuf *jb, jb_frame *frame, long 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) */
long 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
+285
View File
@@ -0,0 +1,285 @@
/* 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
#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(uint8_t *buf, unsigned int longs);
#ifndef ASM_MD5
/*
* Note: this code is harmless on little-endian machines.
*/
void byteReverse(uint8_t *buf, unsigned int longs)
{
uint32_t t;
do {
t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
((unsigned) buf[1] << 8 | buf[0]);
*(uint32_t *) 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, uint8_t const *buf, unsigned int len)
{
uint32_t t;
/* Update bitcount */
t = ctx->bits[0];
if ((ctx->bits[0] = t + ((uint32_t) 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) {
uint8_t *p = (uint8_t *) 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_t *) 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_t *) 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(uint8_t digest[16], struct MD5Context *ctx)
{
unsigned int count;
uint8_t *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_t *) 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_t *) ctx->in)[14] = ctx->bits[0];
((uint32_t *) ctx->in)[15] = ctx->bits[1];
MD5Transform(ctx->buf, (uint32_t *) ctx->in);
byteReverse((uint8_t *) 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_t buf[4], uint32_t const in[16])
{
uint32_t 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
+27
View File
@@ -0,0 +1,27 @@
#ifndef MD5_H
#define MD5_H
#ifndef _MSC_VER
#include <inttypes.h>
#else
typedef unsigned int uint32_t;
typedef unsigned char uint8_t;
#endif
struct MD5Context {
uint32_t buf[4];
uint32_t bits[2];
uint8_t in[64];
};
void MD5Init(struct MD5Context *context);
void MD5Update(struct MD5Context *context, uint8_t const *buf, unsigned int len);
void MD5Final(uint8_t digest[16], struct MD5Context *context);
void MD5Transform(uint32_t buf[4], uint32_t const in[16]);
/*
* This is needed to make RSAREF happy on some MS-DOS compilers.
*/
typedef struct MD5Context MD5_CTX;
#endif /* !MD5_H */
+776
View File
@@ -0,0 +1,776 @@
/*
* Miniphone: A simple, command line telephone
*
* IAX Support for talking to Asterisk and other Gnophone clients
*
* Copyright (C) 1999, Linux Support Services, Inc.
*
* Mark Spencer <markster@linux-support.net>
*
* This program is free software, distributed under the terms of
* the GNU General Public License
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <iax-client.h>
#include <linux/soundcard.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <gsm.h>
#include <miniphone.h>
#include <time.h>
#include "busy.h"
#include "dialtone.h"
#include "answer.h"
#include "ringtone.h"
#include "ring10.h"
#include "options.h"
#define FRAME_SIZE 160
static char callerid[80];
struct peer {
int time;
gsm gsmin;
gsm gsmout;
struct iax_session *session;
struct peer *next;
};
static char *audiodev = "/dev/dsp";
static int audiofd = -1;
static struct peer *peers;
static int answered_call = 0;
static struct peer *find_peer(struct iax_session *);
static int audio_setup(char *);
static void sighandler(int);
static void parse_args(FILE *, unsigned char *);
void do_iax_event(FILE *);
void call(FILE *, char *);
void answer_call(void);
void reject_call(void);
static void handle_event(FILE *, struct iax_event *e, struct peer *p);
void parse_cmd(FILE *, int, char **);
void issue_prompt(FILE *);
void dump_array(FILE *, char **);
struct sound {
short *data;
int datalen;
int samplen;
int silencelen;
int repeat;
};
static int cursound = -1;
static int sampsent = 0;
static int offset = 0;
static int silencelen = 0;
static int nosound = 0;
static int offhook = 0;
static int ringing = 0;
static int writeonly = 0;
static struct iax_session *registry = NULL;
static struct timeval regtime;
#define TONE_NONE -1
#define TONE_RINGTONE 0
#define TONE_BUSY 1
#define TONE_CONGEST 2
#define TONE_RINGER 3
#define TONE_ANSWER 4
#define TONE_DIALTONE 5
#define OUTPUT_NONE 0
#define OUTPUT_SPEAKER 1
#define OUTPUT_HANDSET 2
#define OUTPUT_BOTH 3
static struct sound sounds[] = {
{ ringtone, sizeof(ringtone)/2, 16000, 32000, 1 },
{ busy, sizeof(busy)/2, 4000, 4000, 1 },
{ busy, sizeof(busy)/2, 2000, 2000, 1 },
{ ring10, sizeof(ring10)/2, 16000, 32000, 1 },
{ answer, sizeof(answer)/2, 2200, 0, 0 },
{ dialtone, sizeof(dialtone)/2, 8000, 0, 1 },
};
static char *help[] = {
"Welcome to the miniphone telephony client, the commands are as follows:\n",
"Help\t\t-\tDisplays this screen.",
"Help <Command>\t-\tInqueries specific information on a command.",
"Dial <Number>\t-\tDials the number supplied in the first arguement",
"Status\t\t-\tLists the current sessions and their current status.",
"Quit\t\t-\tShuts down the client.",
"",
0
};
static short silence[FRAME_SIZE];
static struct peer *most_recent_answer;
static struct iax_session *newcall = 0;
static struct peer *find_peer(struct iax_session *session)
{
struct peer *cur = peers;
while(cur) {
if (cur->session == session)
return cur;
cur = cur->next;
}
return NULL;
}
static int audio_setup(char *dev)
{
int fd;
int fmt = AFMT_S16_LE;
int channels = 1;
int speed = 8000;
int fragsize = (40 << 16) | 6;
if ( (fd = open(dev, O_RDWR | O_NONBLOCK)) < 0) {
fprintf(stderr, "Unable to open audio device %s: %s\n", dev, strerror(errno));
return -1;
}
if (ioctl(fd, SNDCTL_DSP_SETFMT, &fmt) || (fmt != AFMT_S16_LE)) {
fprintf(stderr, "Unable to set in signed linear format.\n");
return -1;
}
if (ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0)) {
fprintf(stderr, "Unable to set full duplex operation.\n");
writeonly = 1;
/* return -1; */
}
if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) || (channels != 1)) {
fprintf(stderr, "Unable to set to mono\n");
return -1;
}
if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) || (speed != 8000)) {
fprintf(stderr, "Unable to set speed to 8000 hz\n");
return -1;
}
if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &fragsize)) {
fprintf(stderr, "Unable to set fragment size...\n");
return -1;
}
return fd;
}
static int send_sound(int soundfd)
{
/* Send FRAME_SIZE samples of whatever */
short myframe[FRAME_SIZE];
short *frame = NULL;
int total = FRAME_SIZE;
int amt=0;
int res;
int myoff;
audio_buf_info abi;
if (cursound > -1) {
res = ioctl(soundfd, SNDCTL_DSP_GETOSPACE ,&abi);
if (res) {
fprintf(stderr,"Unable to read output space\n");
return -1;
}
/* Calculate how many samples we can send, max */
if (total > (abi.fragments * abi.fragsize / 2))
total = abi.fragments * abi.fragsize / 2;
res = total;
if (sampsent < sounds[cursound].samplen) {
myoff=0;
while(total) {
amt = total;
if (amt > (sounds[cursound].datalen - offset))
amt = sounds[cursound].datalen - offset;
memcpy(myframe + myoff, sounds[cursound].data + offset, amt * 2);
total -= amt;
offset += amt;
sampsent += amt;
myoff += amt;
if (offset >= sounds[cursound].datalen)
offset = 0;
}
/* Set it up for silence */
if (sampsent >= sounds[cursound].samplen)
silencelen = sounds[cursound].silencelen;
frame = myframe;
} else {
if (silencelen > 0) {
frame = silence;
silencelen -= res;
} else {
if (sounds[cursound].repeat) {
/* Start over */
sampsent = 0;
offset = 0;
} else {
cursound = -1;
nosound = 0;
}
}
}
#if 0
if (frame)
printf("res is %d, frame[0] is %d\n", res, frame[0]);
#endif
res = write(soundfd, frame, res * 2);
if (res > 0)
return 0;
return res;
}
return 0;
}
static int iax_regtimeout(int timeout)
{
if (timeout) {
gettimeofday(&regtime, NULL);
regtime.tv_sec += timeout;
} else {
regtime.tv_usec = 0;
regtime.tv_sec = 0;
}
return 0;
}
static int check_iax_register(void)
{
int res;
if (strlen(regpeer) && strlen(server)) {
registry = iax_session_new();
res = iax_register(registry, server,regpeer,regsecret, refresh);
if (res) {
fprintf(stderr, "Failed registration: %s\n", iax_errstr);
return -1;
}
iax_regtimeout(5 * refresh / 6);
} else {
iax_regtimeout(0);
refresh = 60;
}
return 0;
}
static int check_iax_timeout(void)
{
struct timeval tv;
int ms;
if (!regtime.tv_usec || !regtime.tv_sec)
return -1;
gettimeofday(&tv, NULL);
if ((tv.tv_usec >= regtime.tv_usec) && (tv.tv_sec >= regtime.tv_sec)) {
check_iax_register();
/* Have it check again soon */
return 100;
}
ms = (regtime.tv_sec - tv.tv_sec) * 1000 + (regtime.tv_usec - tv.tv_usec) / 1000;
return ms;
}
static int gentone(int sound, int uninterruptible)
{
cursound = sound;
sampsent = 0;
offset = 0;
silencelen = 0;
nosound = uninterruptible;
printf("Sending tone %d\n", sound);
return 0;
}
void
sighandler(int sig)
{
if(sig == SIGHUP) {
puts("rehashing!");
} else if(sig == SIGINT) {
static int prev = 0;
int cur;
if ( (cur = time(0))-prev <= 5) {
printf("Terminating!\n");
exit(0);
} else {
prev = cur;
printf("Press interrupt key again in the next %d seconds to really terminate\n", 5-(cur-prev));
}
}
}
void
parse_args(FILE *f, unsigned char *cmd)
{
static char *argv[MAXARGS];
unsigned char *parse = cmd;
int argc = 0, t = 0;
// Don't mess with anything that doesn't exist...
if(!*parse)
return;
bzero(argv, sizeof(argv));
while(*parse) {
if(*parse < 33 || *parse > 128) {
*parse = 0, t++;
if(t > MAXARG) {
fprintf(f, "Warning: Argument exceeds maximum argument size, command ignored!\n");
return;
}
} else if(t || !argc) {
if(argc == MAXARGS) {
fprintf(f, "Warning: Command ignored, too many arguments\n");
return;
}
argv[argc++] = parse;
t = 0;
}
parse++;
}
if(argc)
parse_cmd(f, argc, argv);
}
int
main(int argc, char *argv[])
{
int port;
int netfd;
int c, h=0, m, regm;
FILE *f;
int fd = STDIN_FILENO;
char rcmd[RBUFSIZE];
fd_set readfd;
fd_set writefd;
struct timeval timer;
struct timeval *timerptr = NULL;
gsm_frame fo;
load_options();
if (!strlen(callerid))
gethostname(callerid, sizeof(callerid));
signal(SIGHUP, sighandler);
signal(SIGINT, sighandler);
if ( !(f = fdopen(fd, "w+"))) {
fprintf(stderr, "Unable to create file on fd %d\n", fd);
return -1;
}
if ( (audiofd = audio_setup(audiodev)) == -1) {
fprintf(stderr, "Fatal error: failed to open sound device");
return -1;
}
if ( (port = iax_init(0) < 0)) {
fprintf(stderr, "Fatal error: failed to initialize iax with port %d\n", port);
return -1;
}
iax_set_formats(AST_FORMAT_GSM);
netfd = iax_get_fd();
check_iax_register();
fprintf(f, "Text Based Telephony Client.\n\n");
issue_prompt(f);
timer.tv_sec = 0;
timer.tv_usec = 0;
while(1) {
FD_ZERO(&readfd);
FD_ZERO(&writefd);
FD_SET(fd, &readfd);
if(fd > h)
h = fd;
if(answered_call && !writeonly) {
FD_SET(audiofd, &readfd);
if(audiofd > h)
h = audiofd;
}
if (cursound > -1) {
FD_SET(audiofd, &writefd);
if (audiofd > h)
h = audiofd;
}
FD_SET(netfd, &readfd);
if(netfd > h)
h = netfd;
if ( (c = select(h+1, &readfd, &writefd, 0, timerptr)) >= 0) {
if(FD_ISSET(fd, &readfd)) {
if ( ( fgets(&*rcmd, 256, f))) {
rcmd[strlen(rcmd)-1] = 0;
parse_args(f, &*rcmd);
} else fprintf(f, "Fatal error: failed to read data!\n");
issue_prompt(f);
}
if(answered_call) {
if(FD_ISSET(audiofd, &readfd)) {
static int ret, rlen = 0;
static short rbuf[FRAME_SIZE];
if ( (ret = read(audiofd, rbuf + rlen, 2 * (FRAME_SIZE-rlen))) == -1) {
puts("Failed to read audio.");
return -1;
}
rlen += ret/2;
if(rlen == FRAME_SIZE) {
rlen = 0;
if(!most_recent_answer->gsmout)
most_recent_answer->gsmout = gsm_create();
gsm_encode(most_recent_answer->gsmout, rbuf, fo);
if(iax_send_voice(most_recent_answer->session,
AST_FORMAT_GSM, (char *)fo, sizeof(fo)) == -1)
puts("Failed to send voice!");
}
}
}
do_iax_event(f);
m = iax_time_to_next_event();
if(m > -1) {
timerptr = &timer;
timer.tv_sec = m /1000;
timer.tv_usec = (m % 1000) * 1000;
} else
timerptr = 0;
regm = check_iax_timeout();
if (!timerptr || (m > regm)) {
timerptr = &timer;
timer.tv_sec = regm /1000;
timer.tv_usec = (regm % 1000) * 1000;
}
if (FD_ISSET(audiofd, &writefd)) {
send_sound(audiofd);
}
} else {
if(errno == EINTR)
continue;
fprintf(stderr, "Fatal error in select(): %s\n", strerror(errno));
return -1;
}
}
return 0;
}
void
do_iax_event(FILE *f) {
int sessions = 0;
struct iax_event *e = 0;
struct peer *peer;
while ( (e = iax_get_event(0))) {
peer = find_peer(e->session);
if(peer) {
handle_event(f, e, peer);
} else if (e->session == registry) {
fprintf(stderr, "Registration complete: %s (%d)\n",
(e->event.regreply.status == IAX_REG_SUCCESS) ? "Success" : "Failed",
e->event.regreply.status);
registry = NULL;
} else {
if(e->etype != IAX_EVENT_CONNECT) {
fprintf(stderr, "Huh? This is an event for a non-existant session?\n");
continue;
}
sessions++;
if(sessions >= MAX_SESSIONS) {
fprintf(f, "Missed a call... too many sessions open.\n");
}
if(e->event.connect.callerid && e->event.connect.dnid)
fprintf(f, "Call from '%s' for '%s'", e->event.connect.callerid,
e->event.connect.dnid);
else if(e->event.connect.dnid) {
fprintf(f, "Call from '%s'", e->event.connect.dnid);
} else if(e->event.connect.callerid) {
fprintf(f, "Call from '%s'", e->event.connect.callerid);
} else printf("Call from");
fprintf(f, " (%s)\n", inet_ntoa(iax_get_peer_addr(e->session).sin_addr));
if(most_recent_answer) {
fprintf(f, "Incoming call ignored, there's already a call waiting for answer... \
please accept or reject first\n");
iax_reject(e->session, "Too many calls, we're busy!");
} else {
if ( !(peer = malloc(sizeof(struct peer)))) {
fprintf(f, "Warning: Unable to allocate memory!\n");
return;
}
peer->time = time(0);
peer->session = e->session;
if (peer->gsmin)
free(peer->gsmin);
peer->gsmin = 0;
if (peer->gsmout)
free(peer->gsmout);
peer->gsmout = 0;
peer->next = peers;
peers = peer;
iax_accept(peer->session);
iax_ring_announce(peer->session);
most_recent_answer = peer;
ringing = 1;
gentone(TONE_RINGER, 0);
fprintf(f, "Incoming call!\n");
}
issue_prompt(f);
}
iax_event_free(e);
}
}
void
call(FILE *f, char *num)
{
struct peer *peer;
if(!newcall)
newcall = iax_session_new();
else {
fprintf(f, "Already attempting to call somewhere, please cancel first!\n");
return;
}
if ( !(peer = malloc(sizeof(struct peer)))) {
fprintf(f, "Warning: Unable to allocate memory!\n");
return;
}
peer->time = time(0);
peer->session = newcall;
peer->gsmin = 0;
peer->gsmout = 0;
peer->next = peers;
peers = peer;
most_recent_answer = peer;
offhook = 1;
iax_call(peer->session, callerid, num, NULL, 10);
}
void
answer_call(void)
{
if(most_recent_answer)
iax_answer(most_recent_answer->session);
printf("Answering call!\n");
answered_call = 1;
offhook = 1;
ringing = 0;
gentone(TONE_ANSWER, 1);
}
void
reject_call(void)
{
iax_reject(most_recent_answer->session, "Call rejected manually.");
most_recent_answer = 0;
ringing = 0;
gentone(TONE_NONE, 1);
}
void
handle_event(FILE *f, struct iax_event *e, struct peer *p)
{
short fr[FRAME_SIZE];
int len;
switch(e->etype) {
case IAX_EVENT_HANGUP:
iax_hangup(most_recent_answer->session, "Byeee!");
fprintf(f, "Call disconnected by peer\n");
free(most_recent_answer);
most_recent_answer = 0;
answered_call = 0;
peers = 0;
newcall = 0;
if (offhook)
gentone(TONE_CONGEST, 0);
break;
case IAX_EVENT_REJECT:
fprintf(f, "Authentication was rejected\n");
break;
case IAX_EVENT_ACCEPT:
fprintf(f, "Accepted...\n");
issue_prompt(f);
break;
case IAX_EVENT_RINGA:
fprintf(f, "Ringing...\n");
issue_prompt(f);
gentone(TONE_RINGTONE, 0);
break;
case IAX_EVENT_ANSWER:
answer_call();
gentone(TONE_ANSWER, 1);
break;
case IAX_EVENT_VOICE:
switch(e->event.voice.format) {
case AST_FORMAT_GSM:
if(e->event.voice.datalen % 33) {
fprintf(stderr, "Weird gsm frame, not a multiple of 33.\n");
break;
}
if (!p->gsmin)
p->gsmin = gsm_create();
len = 0;
while(len < e->event.voice.datalen) {
if(gsm_decode(p->gsmin, e->event.voice.data + len, fr)) {
fprintf(stderr, "Bad GSM data\n");
break;
} else {
int res;
res = write(audiofd, fr, sizeof(fr));
if (res < 0)
fprintf(f, "Write failed: %s\n", strerror(errno));
}
len += 33;
}
break;
default :
fprintf(f, "Don't know how to handle that format %d\n", e->event.voice.format);
}
break;
default:
fprintf(f, "Unknown event: %d\n", e->etype);
}
}
void
dump_call(void)
{
if(most_recent_answer)
{
printf("Dumping call!\n");
iax_hangup(most_recent_answer->session,"");
free(most_recent_answer);
}
answered_call = 0;
most_recent_answer = 0;
answered_call = 0;
peers = 0;
newcall = 0;
offhook = 0;
ringing = 0;
gentone(TONE_NONE, 0);
}
void
parse_cmd(FILE *f, int argc, char **argv)
{
if(!strcasecmp(argv[0], "HELP")) {
if(argc == 1)
dump_array(f, help);
else if(argc == 2) {
if(!strcasecmp(argv[1], "HELP"))
fprintf(f, "Help <Command>\t-\tDisplays general help or specific help on command if supplied an arguement\n");
else if(!strcasecmp(argv[1], "QUIT"))
fprintf(f, "Quit\t\t-\tShuts down the miniphone\n");
else fprintf(f, "No help available on %s\n", argv[1]);
} else {
fprintf(f, "Too many arguements for command help.\n");
}
} else if(!strcasecmp(argv[0], "STATUS")) {
if(argc == 1) {
int c = 0;
struct peer *peerptr = peers;
if(!peerptr)
fprintf(f, "No session matches found.\n");
else while(peerptr) {
fprintf(f, "Listing sessions:\n\n");
fprintf(f, "Session %d\n", ++c);
fprintf(f, "Session existed for %d seconds\n", (int)time(0)-peerptr->time);
if(answered_call)
fprintf(f, "Call answered.\n");
else fprintf(f, "Call ringing.\n");
peerptr = peerptr->next;
}
} else fprintf(f, "Too many arguments for command status.\n");
} else if(!strcasecmp(argv[0], "ANSWER")) {
if(argc > 1)
fprintf(f, "Too many arguements for command answer\n");
else answer_call();
} else if(!strcasecmp(argv[0], "REJECT")) {
if(argc > 1)
fprintf(f, "Too many arguements for command reject\n");
else {
fprintf(f, "Rejecting current phone call.\n");
reject_call();
}
} else if (!strcasecmp(argv[0], "DUMP")) {
dump_call();
} else if (!strcasecmp(argv[0], "HANGUP")) {
dump_call();
} else if(!strcasecmp(argv[0], "CALL")) {
if(argc > 2)
fprintf(f, "Too many arguements for command call\n");
else {
call(f, argv[1]);
}
} else if(!strcasecmp(argv[0], "QUIT")) {
if(argc > 1)
fprintf(f, "Too many arguements for command quit\n");
else {
fprintf(f, "Good bye!\n");
exit(1);
}
} else fprintf(f, "Unknown command of %s\n", argv[0]);
}
void
issue_prompt(FILE *f)
{
fprintf(f, "TeleClient> ");
fflush(f);
}
void
dump_array(FILE *f, char **array) {
while(*array)
fprintf(f, "%s\n", *array++);
}
+6
View File
@@ -0,0 +1,6 @@
#define RBUFSIZE 256
#define MAXARGS 10
#define MAXARG 256
#define MAX_SESSIONS 4
extern void parse_cmd(FILE *, int, char **);
+137
View File
@@ -0,0 +1,137 @@
/*
* Snomphone: IAX software for SNOM 100 Phone
*
* IAX Support for talking to Asterisk and other Gnophone clients
*
* Copyright (C) 1999, Linux Support Services, Inc.
*
* Mark Spencer <markster@linux-support.net>
*
* This program is free software, distributed under the terms of
* the GNU General Public License
*/
#define CONFIG_FILE "/etc/miniphone.conf"
#define USER_FILE "%s/.miniphone-conf"
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
char regpeer[256];
char regsecret[256];
char server[256];
int refresh = 60;
char context[256];
char language[256];
#define TYPE_STRING 0
#define TYPE_INT 1
struct opt {
char *name;
void *where;
int len;
int type;
};
static struct opt opts[] = {
{ "regpeer", regpeer, sizeof(regpeer), TYPE_STRING },
{ "regsecret", regsecret, sizeof(regsecret), TYPE_STRING },
{ "server", server, sizeof(server), TYPE_STRING },
{ "context", context, sizeof(context), TYPE_STRING },
{ "language", language, sizeof(language), TYPE_STRING },
{ "refresh", &refresh, sizeof(refresh), TYPE_INT },
};
static int __load_options(char *filename)
{
FILE *f;
int lineno = 0;
char buf[256];
char *var, *value;
int x;
char *c;
f = fopen(filename, "r");
if (!f) {
fprintf(stderr, "Failed to open '%s': %s\n", filename, strerror(errno));
return -1;
}
while(!feof(f)) {
fgets(buf, sizeof(buf), f);
if (!feof(f)) {
/* Ditch comments */
if ((c = strchr(buf, '#')))
*c = 0;
lineno++;
/* Strip CR */
buf[strlen(buf)-1] = '\0';
if (strlen(buf)) {
var = strtok(buf, "=");
value = strtok(NULL, "=");
if (!var || !value) {
fprintf(stderr, "Syntax error line %d\n", lineno);
continue;
}
for (x=0;x<sizeof(opts) / sizeof(opts[0]); x++) {
if (!strcasecmp(var, opts[x].name)) {
switch(opts[x].type) {
case TYPE_STRING:
strncpy((char *)opts[x].where, value, opts[x].len);
break;
case TYPE_INT:
if (sscanf(value, "%i", (int *)opts[x].where) != 1) {
fprintf(stderr, "Not a number at line %d\n", lineno);
}
break;
default:
fprintf(stderr, "Don't know what to do about type %d\n", opts[x].type);
}
break;
}
}
if (!(x < sizeof(opts) / sizeof(opts[0]))) {
fprintf(stderr, "Dunno keyword '%s'\n", var);
continue;
}
}
}
}
fclose(f);
return 0;
}
int load_options(void)
{
char fn[256];
__load_options(CONFIG_FILE);
if (getenv("HOME")) {
snprintf(fn, sizeof(fn), USER_FILE, getenv("HOME"));
__load_options(fn);
}
return 0;
}
static int __save_options(char *filename)
{
FILE *f;
f = fopen(filename, "w");
if (!f) {
fprintf(stderr, "Failed to open '%s': %s\n", filename, strerror(errno));
return -1;
}
fclose(f);
return 0;
}
int save_options(void)
{
char fn[256];
if (getenv("HOME")) {
snprintf(fn, sizeof(fn), USER_FILE, getenv("HOME"));
return __save_options(fn);
} else
return __save_options(CONFIG_FILE);
}
+23
View File
@@ -0,0 +1,23 @@
/*
* Snomphone: IAX software for SNOM 100 Phone
*
* IAX Support for talking to Asterisk and other Gnophone clients
*
* Copyright (C) 1999, Linux Support Services, Inc.
*
* Mark Spencer <markster@linux-support.net>
*
* This program is free software, distributed under the terms of
* the GNU General Public License
*/
extern char regpeer[256];
extern char regsecret[256];
extern char regpeer[256];
extern char server[256];
extern int refresh;
extern char context[256];
extern char language[256];
int save_options(void);
int load_options(void);
File diff suppressed because it is too large Load Diff
+30
View File
@@ -0,0 +1,30 @@
/* ringtone.h: Generated from frequencies 440 and 480
by gensound. 200 samples */
static short ringtone[200] = {
0, 11581, 21659, 28927, 32445, 31764, 26981, 18727,
8084, -3559, -14693, -23875, -29927, -32083, -30088, -24228,
-15290, -4453, 6864, 17195, 25212, 29902, 30693, 27526,
20856, 11585, 944, -9673, -18899, -25560, -28837, -28357,
-24244, -17089, -7868, 2192, 11780, 19667, 24872, 26779,
25212, 20450, 13179, 4396, -4731, -13019, -19421, -23164,
-23839, -21446, -16384, -9384, -1408, 6484, 13281, 18145,
20517, 20182, 17286, 12301, 5951, -887, -7314, -12519,
-15886, -17068, -16017, -12983, -8458, -3109, 2327, 7142,
10750, 12757, 13007, 11585, 8793, 5095, 1044, -2800,
-5951, -8053, -8921, -8560, -7141, -4967, -2421, 104,
2260, 3791, 4567, 4589, 3977, 2941, 1733, 600,
-257, -722, -772, -481, 0, 481, 772, 722,
257, -600, -1733, -2941, -3977, -4589, -4567, -3791,
-2260, -104, 2421, 4967, 7141, 8560, 8921, 8053,
5951, 2800, -1044, -5095, -8793, -11585, -13007, -12757,
-10750, -7142, -2327, 3109, 8458, 12983, 16017, 17068,
15886, 12519, 7314, 887, -5951, -12301, -17286, -20182,
-20517, -18145, -13281, -6484, 1408, 9384, 16384, 21446,
23839, 23164, 19421, 13019, 4731, -4396, -13179, -20450,
-25212, -26779, -24872, -19667, -11780, -2192, 7868, 17089,
24244, 28357, 28837, 25560, 18899, 9673, -944, -11585,
-20856, -27526, -30693, -29902, -25212, -17195, -6864, 4453,
15290, 24228, 30088, 32083, 29927, 23875, 14693, 3559,
-8084, -18727, -26981, -31764, -32445, -28927, -21659, -11581,
};
+761
View File
@@ -0,0 +1,761 @@
/*
* Miniphone: A simple, command line telephone
*
* IAX Support for talking to Asterisk and other Gnophone clients
*
* Copyright (C) 1999, Linux Support Services, Inc.
*
* Mark Spencer <markster@linux-support.net>
*
* This program is free software, distributed under the terms of
* the GNU General Public License
*/
/* #define PRINTCHUCK /* enable this to indicate chucked incomming packets */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <io.h>
#include <conio.h>
#include <stdio.h>
#include <errno.h>
#include <time.h>
#include <process.h>
#include <windows.h>
#include <winsock.h>
#include <mmsystem.h>
#include <malloc.h>
#include "gsm.h"
#include "iax-client.h"
#include "frame.h"
#include "miniphone.h"
struct peer {
int time;
gsm gsmin;
gsm gsmout;
struct iax_session *session;
struct peer *next;
};
static struct peer *peers;
static int answered_call = 0;
/* stuff for wave audio device */
HWAVEOUT wout;
HWAVEIN win;
typedef struct whout {
WAVEHDR w;
short data[160];
struct whout *next;
} WHOUT;
WHOUT *outqueue = NULL;
/* parameters for audio in */
#define NWHIN 8 /* number of input buffer entries */
/* NOTE the OUT_INTERVAL parameter *SHOULD* be more around 18 to 20 or so, since the packets should
be spaced by 20 milliseconds. However, in practice, especially in Windoze-95, setting it that high
caused underruns. 10 is just ever so slightly agressive, and the receiver has to chuck a packet
every now and then. Thats about the way it should be to be happy. */
#define OUT_INTERVAL 10 /* number of ms to wait before sending more data to peer */
/* parameters for audio out */
#define OUT_DEPTH 12 /* number of outbut buffer entries */
#define OUT_PAUSE_THRESHOLD 2 /* number of active entries needed to start output (for smoothing) */
/* audio input buffer headers */
WAVEHDR whin[NWHIN];
/* audio input buffers */
char bufin[NWHIN][320];
/* initialize the sequence variables for the audio in stuff */
unsigned int whinserial = 1,nextwhin = 1;
static struct peer *find_peer(struct iax_session *);
static void parse_args(FILE *, unsigned char *);
void do_iax_event(FILE *);
void call(FILE *, char *);
void answer_call(void);
void reject_call(void);
static void handle_event(FILE *, struct iax_event *e, struct peer *p);
void parse_cmd(FILE *, int, char **);
void issue_prompt(FILE *);
void dump_array(FILE *, char **);
static char *help[] = {
"Welcome to the miniphone telephony client, the commands are as follows:\n",
"Help\t\t-\tDisplays this screen.",
"Call <Number>\t-\tDials the number supplied.",
"Answer\t\t-\tAnswers an Inbound call.",
"Reject\t\t-\tRejects an Inbound call.",
"Dump\t\t-\tDumps (disconnects) the current call.",
"Dtmf <Digit>\t-\tSends specified DTMF digit.",
"Status\t\t-\tLists the current sessions and their current status.",
"Quit\t\t-\tShuts down the client.",
"",
0
};
static struct peer *most_recent_answer;
static struct iax_session *newcall = 0;
/* holder of the time, relative to startup in system ticks. See our
gettimeofday() implementation */
time_t startuptime;
/* routine called at exit to shutdown audio I/O and close nicely.
NOTE: If all this isnt done, the system doesnt not handle this
cleanly and has to be rebooted. What a pile of doo doo!! */
void killem(void)
{
waveInStop(win);
waveInReset(win);
waveInClose(win);
waveOutReset(wout);
waveOutClose(wout);
WSACleanup(); /* dont forget socket stuff too */
return;
}
/* Win-doze doenst have gettimeofday(). This sux. So, what we did is
provide some gettimeofday-like functionality that works for our purposes.
In the main(), we take a sample of the system tick counter (into startuptime).
This function returns the relative time since program startup, more or less,
which is certainly good enough for our purposes. */
void gettimeofday(struct timeval *tv, struct timezone *tz)
{
long l = startuptime + GetTickCount();
tv->tv_sec = l / 1000;
tv->tv_usec = (l % 1000) * 1000;
return;
}
static struct peer *find_peer(struct iax_session *session)
{
struct peer *cur = peers;
while(cur) {
if (cur->session == session)
return cur;
cur = cur->next;
}
return NULL;
}
void
parse_args(FILE *f, unsigned char *cmd)
{
static char *argv[MAXARGS];
unsigned char *parse = cmd;
int argc = 0, t = 0;
// Don't mess with anything that doesn't exist...
if(!*parse)
return;
memset(argv, 0, sizeof(argv));
while(*parse) {
if(*parse < 33 || *parse > 128) {
*parse = 0, t++;
if(t > MAXARG) {
fprintf(f, "Warning: Argument exceeds maximum argument size, command ignored!\n");
return;
}
} else if(t || !argc) {
if(argc == MAXARGS) {
fprintf(f, "Warning: Command ignored, too many arguments\n");
return;
}
argv[argc++] = parse;
t = 0;
}
parse++;
}
if(argc)
parse_cmd(f, argc, argv);
}
/* handle all network requests, and a pending scheduled event, if any */
void service_network(int netfd, FILE *f)
{
fd_set readfd;
struct timeval dumbtimer;
/* set up a timer that falls-through */
dumbtimer.tv_sec = 0;
dumbtimer.tv_usec = 0;
for(;;) /* suck everything outa network stuff */
{
FD_ZERO(&readfd);
FD_SET(netfd, &readfd);
if (select(netfd + 1, &readfd, 0, 0, &dumbtimer) > 0)
{
if (FD_ISSET(netfd,&readfd))
{
do_iax_event(f);
(void) iax_time_to_next_event();
} else break;
} else break;
}
do_iax_event(f); /* do pending event if any */
}
int
main(int argc, char *argv[])
{
int port;
int netfd;
int c, i;
FILE *f;
char rcmd[RBUFSIZE];
gsm_frame fo;
WSADATA foop;
time_t t;
WAVEFORMATEX wf;
WHOUT *wh,*wh1,*wh2;
unsigned long lastouttick = 0;
/* get time of day in milliseconds, offset by tick count (see our
gettimeofday() implementation) */
time(&t);
startuptime = ((t % 86400) * 1000) - GetTickCount();
f = stdout;
_dup2(fileno(stdout),fileno(stderr));
/* start up the windoze-socket layer stuff */
if (WSAStartup(0x0101,&foop)) {
fprintf(stderr,"Fatal error: Falied to startup windows sockets\n");
return -1;
}
/* setup the format for opening audio channels */
wf.wFormatTag = WAVE_FORMAT_PCM;
wf.nChannels = 1;
wf.nSamplesPerSec = 8000;
wf.nAvgBytesPerSec = 16000;
wf.nBlockAlign = 2;
wf.wBitsPerSample = 16;
wf.cbSize = 0;
/* open the audio out channel */
if (waveOutOpen(&wout,0,&wf,0,0,CALLBACK_NULL) != MMSYSERR_NOERROR)
{
fprintf(stderr,"Fatal Error: Failed to open wave output device\n");
return -1;
}
/* open the audio in channel */
if (waveInOpen(&win,0,&wf,0,0,CALLBACK_NULL) != MMSYSERR_NOERROR)
{
fprintf(stderr,"Fatal Error: Failed to open wave input device\n");
waveOutReset(wout);
waveOutClose(wout);
return -1;
}
/* activate the exit handler */
atexit(killem);
/* initialize the audio in buffer structures */
memset(&whin,0,sizeof(whin));
if ( (port = iax_init(0) < 0)) {
fprintf(stderr, "Fatal error: failed to initialize iax with port %d\n", port);
return -1;
}
iax_set_formats(AST_FORMAT_GSM);
netfd = iax_get_fd();
fprintf(f, "Text Based Telephony Client.\n\n");
issue_prompt(f);
/* main tight loop */
while(1) {
/* service the network stuff */
service_network(netfd,f);
if (outqueue) /* if stuff in audio output queue, free it up if its available */
{
/* go through audio output queue */
for(wh = outqueue,wh1 = wh2 = NULL,i = 0; wh != NULL; wh = wh->next)
{
service_network(netfd,f); /* service network here for better performance */
/* if last one was removed from queue, zot it here */
if (i && wh1)
{
free(wh1);
wh1 = wh2;
}
i = 0; /* reset "last one removed" flag */
if (wh->w.dwFlags & WHDR_DONE) /* if this one is done */
{
/* prepare audio header */
if ((c = waveOutUnprepareHeader(wout,&wh->w,sizeof(WAVEHDR))) != MMSYSERR_NOERROR)
{
fprintf(stderr,"Cannot unprepare audio out header, error %d\n",c);
exit(255);
}
if (wh1 != NULL) /* if there was a last one */
{
wh1->next = wh->next;
}
if (outqueue == wh) /* is first one, so set outqueue to next one */
{
outqueue = wh->next;
}
i = 1; /* set 'to free' flag */
}
wh2 = wh1; /* save old,old wh pointer */
wh1 = wh; /* save the old wh pointer */
}
}
/* go through all audio in buffers, and prepare and queue ones that are currently idle */
for(i = 0; i < NWHIN; i++)
{
service_network(netfd,f); /* service network stuff here for better performance */
if (!(whin[i].dwFlags & WHDR_PREPARED)) /* if not prepared, do so */
{
/* setup this input buffer header */
memset(&whin[i],0,sizeof(WAVEHDR));
whin[i].lpData = bufin[i];
whin[i].dwBufferLength = 320;
whin[i].dwUser = whinserial++; /* set 'user data' to current serial number */
/* prepare the buffer */
if (waveInPrepareHeader(win,&whin[i],sizeof(WAVEHDR)))
{
fprintf(stderr,"Unable to prepare header for input\n");
return -1;
}
/* add it to device (queue) */
if (waveInAddBuffer(win,&whin[i],sizeof(WAVEHDR)))
{
fprintf(stderr,"Unable to prepare header for input\n");
return -1;
}
}
waveInStart(win); /* start it (if not already started) */
}
/* if key pressed, do command stuff */
if(_kbhit())
{
if ( ( fgets(&*rcmd, 256, stdin))) {
rcmd[strlen(rcmd)-1] = 0;
parse_args(f, &*rcmd);
} else fprintf(f, "Fatal error: failed to read data!\n");
issue_prompt(f);
}
/* do audio input stuff for buffers that have received data from audio in device already. Must
do them in serial number order (the order in which they were originally queued). */
if(answered_call) /* send audio only if call answered */
{
for(;;) /* loop until all are found */
{
for(i = 0; i < NWHIN; i++) /* find an available one that's the one we are looking for */
{
service_network(netfd,f); /* service network here for better performance */
/* if not time to send any more, dont */
if (GetTickCount() < (lastouttick + OUT_INTERVAL))
{
i = NWHIN; /* set to value that WILL exit loop */
break;
}
if ((whin[i].dwUser == nextwhin) && (whin[i].dwFlags & WHDR_DONE)) { /* if audio is ready */
/* must have read exactly 320 bytes */
if (whin[i].dwBytesRecorded != whin[i].dwBufferLength)
{
fprintf(stderr,"Short audio read, got %d bytes, expected %d bytes\n", whin[i].dwBytesRecorded,
whin[i].dwBufferLength);
return -1;
}
if(!most_recent_answer->gsmout)
most_recent_answer->gsmout = gsm_create();
service_network(netfd,f); /* service network here for better performance */
/* encode the audio from the buffer into GSM format */
gsm_encode(most_recent_answer->gsmout, (short *) ((char *) whin[i].lpData), fo);
if(iax_send_voice(most_recent_answer->session,
AST_FORMAT_GSM, (char *)fo, sizeof(gsm_frame)) == -1)
puts("Failed to send voice!");
lastouttick = GetTickCount(); /* save time of last output */
/* unprepare (free) the header */
waveInUnprepareHeader(win,&whin[i],sizeof(WAVEHDR));
/* initialize the buffer */
memset(&whin[i],0,sizeof(WAVEHDR));
/* bump the serial number to look for the next time */
nextwhin++;
/* exit the loop so that we can start at lowest buffer again */
break;
}
}
if (i >= NWHIN) break; /* if all found, get out of loop */
}
}
}
return 0;
}
void
do_iax_event(FILE *f) {
int sessions = 0;
struct iax_event *e = 0;
struct peer *peer;
while ( (e = iax_get_event(0))) {
peer = find_peer(e->session);
if(peer) {
handle_event(f, e, peer);
} else {
if(e->etype != IAX_EVENT_CONNECT) {
fprintf(stderr, "Huh? This is an event for a non-existant session?\n");
}
sessions++;
if(sessions >= MAX_SESSIONS) {
fprintf(f, "Missed a call... too many sessions open.\n");
}
if(e->event.connect.callerid && e->event.connect.dnid)
fprintf(f, "Call from '%s' for '%s'", e->event.connect.callerid,
e->event.connect.dnid);
else if(e->event.connect.dnid) {
fprintf(f, "Call from '%s'", e->event.connect.dnid);
} else if(e->event.connect.callerid) {
fprintf(f, "Call from '%s'", e->event.connect.callerid);
} else printf("Call from");
fprintf(f, " (%s)\n", inet_ntoa(iax_get_peer_addr(e->session).sin_addr));
if(most_recent_answer) {
fprintf(f, "Incoming call ignored, there's already a call waiting for answer... \
please accept or reject first\n");
iax_reject(e->session, "Too many calls, we're busy!");
} else {
if ( !(peer = malloc(sizeof(struct peer)))) {
fprintf(f, "Warning: Unable to allocate memory!\n");
return;
}
peer->time = time(0);
peer->session = e->session;
peer->gsmin = 0;
peer->gsmout = 0;
peer->next = peers;
peers = peer;
iax_accept(peer->session);
iax_ring_announce(peer->session);
most_recent_answer = peer;
fprintf(f, "Incoming call!\n");
}
iax_event_free(e);
issue_prompt(f);
}
}
}
void
call(FILE *f, char *num)
{
struct peer *peer;
if(!newcall)
newcall = iax_session_new();
else {
fprintf(f, "Already attempting to call somewhere, please cancel first!\n");
return;
}
if ( !(peer = malloc(sizeof(struct peer)))) {
fprintf(f, "Warning: Unable to allocate memory!\n");
return;
}
peer->time = time(0);
peer->session = newcall;
peer->gsmin = 0;
peer->gsmout = 0;
peer->next = peers;
peers = peer;
most_recent_answer = peer;
iax_call(peer->session, num, 10);
}
void
answer_call(void)
{
if(most_recent_answer)
iax_answer(most_recent_answer->session);
printf("Answering call!\n");
answered_call = 1;
}
void
dump_call(void)
{
if(most_recent_answer)
{
iax_hangup(most_recent_answer->session,"");
free(most_recent_answer);
}
printf("Dumping call!\n");
answered_call = 0;
most_recent_answer = 0;
answered_call = 0;
peers = 0;
newcall = 0;
}
void
reject_call(void)
{
iax_reject(most_recent_answer->session, "Call rejected manually.");
most_recent_answer = 0;
}
void
handle_event(FILE *f, struct iax_event *e, struct peer *p)
{
int len,n;
WHOUT *wh,*wh1;
short fr[160];
static paused_xmit = 0;
switch(e->etype) {
case IAX_EVENT_HANGUP:
iax_hangup(most_recent_answer->session, "Byeee!");
fprintf(f, "Call disconnected by peer\n");
free(most_recent_answer);
most_recent_answer = 0;
answered_call = 0;
peers = 0;
newcall = 0;
break;
case IAX_EVENT_REJECT:
fprintf(f, "Authentication was rejected\n");
break;
case IAX_EVENT_ACCEPT:
fprintf(f, "Waiting for answer... RING RING\n");
issue_prompt(f);
break;
case IAX_EVENT_ANSWER:
answer_call();
break;
case IAX_EVENT_VOICE:
switch(e->event.voice.format) {
case AST_FORMAT_GSM:
if(e->event.voice.datalen % 33) {
fprintf(stderr, "Weird gsm frame, not a multiple of 33.\n");
break;
}
if (!p->gsmin)
p->gsmin = gsm_create();
len = 0;
while(len < e->event.voice.datalen) {
if(gsm_decode(p->gsmin, (char *) e->event.voice.data + len, fr)) {
fprintf(stderr, "Bad GSM data\n");
break;
} else { /* its an audio packet to be output to user */
/* get count of pending items in audio output queue */
n = 0;
if (outqueue)
{ /* determine number of pending out queue items */
for(wh = outqueue; wh != NULL; wh = wh->next)
{
if (!(wh->w.dwFlags & WHDR_DONE)) n++;
}
}
/* if not too many, send to user, otherwise chuck packet */
if (n <= OUT_DEPTH) /* if not to chuck packet */
{
/* malloc the memory for the queue item */
wh = (WHOUT *) malloc(sizeof(WHOUT));
if (wh == (WHOUT *) NULL) /* if error, bail */
{
fprintf(stderr,"Outa memory!!!!\n");
exit(255);
}
/* initialize the queue entry */
memset(wh,0,sizeof(WHOUT));
/* copy the PCM data from the gsm conversion buffer */
memcpy((char *)wh->data,(char *)fr,sizeof(fr));
/* set parameters for data */
wh->w.lpData = (char *) wh->data;
wh->w.dwBufferLength = 320;
/* prepare buffer for output */
if (waveOutPrepareHeader(wout,&wh->w,sizeof(WAVEHDR)))
{
fprintf(stderr,"Cannot prepare header for audio out\n");
exit(255);
}
/* if not currently transmitting, hold off a couple of packets for
smooth sounding output */
if ((!n) && (!paused_xmit))
{
/* pause output (before starting) */
waveOutPause(wout);
/* indicate as such */
paused_xmit = 1;
}
/* queue packet for output on audio device */
if (waveOutWrite(wout,&wh->w,sizeof(WAVEHDR)))
{
fprintf(stderr,"Cannot output to wave output device\n");
exit(255);
}
/* if we are paused, and we have enough packets, start audio */
if ((n > OUT_PAUSE_THRESHOLD) && paused_xmit)
{
/* start the output */
waveOutRestart(wout);
/* indicate as such */
paused_xmit = 0;
}
/* insert it onto tail of outqueue */
if (outqueue == NULL) /* if empty queue */
outqueue = wh; /* point queue to new entry */
else /* otherwise is non-empty queue */
{
wh1 = outqueue;
while(wh1->next) wh1 = wh1->next; /* find last entry in queue */
wh1->next = wh; /* point it to new entry */
}
}
#ifdef PRINTCHUCK
else printf("Chucking packet!!\n");
#endif
}
len += 33;
}
break;
default :
fprintf(f, "Don't know how to handle that format %d\n", e->event.voice.format);
}
break;
case IAX_EVENT_RINGA:
break;
default:
fprintf(f, "Unknown event: %d\n", e->etype);
break;
}
}
void
parse_cmd(FILE *f, int argc, char **argv)
{
_strupr(argv[0]);
if(!strcmp(argv[0], "HELP")) {
if(argc == 1)
dump_array(f, help);
else if(argc == 2) {
if(!strcmp(argv[1], "HELP"))
fprintf(f, "Help <Command>\t-\tDisplays general help or specific help on command if supplied an arguement\n");
else if(!strcmp(argv[1], "QUIT"))
fprintf(f, "Quit\t\t-\tShuts down the miniphone\n");
else fprintf(f, "No help available on %s\n", argv[1]);
} else {
fprintf(f, "Too many arguements for command help.\n");
}
} else if(!strcmp(argv[0], "STATUS")) {
if(argc == 1) {
int c = 0;
struct peer *peerptr = peers;
if(!peerptr)
fprintf(f, "No session matches found.\n");
else while(peerptr) {
fprintf(f, "Listing sessions:\n\n");
fprintf(f, "Session %d\n", ++c);
fprintf(f, "Session existed for %d seconds\n", (int)time(0)-peerptr->time);
if(answered_call)
fprintf(f, "Call answered.\n");
else fprintf(f, "Call ringing.\n");
peerptr = peerptr->next;
}
} else fprintf(f, "Too many arguments for command status.\n");
} else if(!strcmp(argv[0], "ANSWER")) {
if(argc > 1)
fprintf(f, "Too many arguements for command answer\n");
else answer_call();
} else if(!strcmp(argv[0], "REJECT")) {
if(argc > 1)
fprintf(f, "Too many arguements for command reject\n");
else {
fprintf(f, "Rejecting current phone call.\n");
reject_call();
}
} else if(!strcmp(argv[0], "CALL")) {
if(argc > 2)
fprintf(f, "Too many arguements for command call\n");
else {
call(f, argv[1]);
}
} else if(!strcmp(argv[0], "DUMP")) {
if(argc > 1)
fprintf(f, "Too many arguements for command dump\n");
else {
dump_call();
}
} else if(!strcmp(argv[0], "DTMF")) {
if(argc > 2)
{
fprintf(f, "Too many arguements for command dtmf\n");
return;
}
if (argc < 1)
{
fprintf(f, "Too many arguements for command dtmf\n");
return;
}
if(most_recent_answer)
iax_send_dtmf(most_recent_answer->session,*argv[1]);
} else if(!strcmp(argv[0], "QUIT")) {
if(argc > 1)
fprintf(f, "Too many arguements for command quit\n");
else {
fprintf(f, "Good bye!\n");
exit(1);
}
} else fprintf(f, "Unknown command of %s\n", argv[0]);
}
void
issue_prompt(FILE *f)
{
fprintf(f, "TeleClient> ");
fflush(f);
}
void
dump_array(FILE *f, char **array) {
while(*array)
fprintf(f, "%s\n", *array++);
}
+56
View File
@@ -0,0 +1,56 @@
/*
* 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
#define inline __inline
#if _MSC_VER < 1900
#define snprintf _snprintf
#endif
// should try without these
#pragma warning(disable: 4996 4244 4305 4018 4804)
#if defined(_WIN64)
typedef __int64 ssize_t;
#elif defined(_WIN32)
typedef __int32 ssize_t;
#endif
#else
#define INLINE inline
#endif
#include <winsock2.h> // this include <windows.h>
#include <io.h> // for open, close, write, read
#include <stdio.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