00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include <stdio.h>
00017 #include <stdlib.h>
00018 #include <string.h>
00019 #include <fcntl.h>
00020 #include <stdio.h>
00021 #include <time.h>
00022
00023 #include "iaxclient.h"
00024
00025 #define NETSTATS
00026 #define JITTERMAKER
00027
00028 #ifdef JITTERMAKER
00029 #include <netdb.h>
00030 #include <sys/socket.h>
00031 #include <netinet/in.h>
00032 #include <sys/time.h>
00033 #include <stdlib.h>
00034 #include <string.h>
00035 #include <stdarg.h>
00036 #include <stdio.h>
00037 #include <unistd.h>
00038 #include <fcntl.h>
00039 #include <errno.h>
00040 #include <sys/select.h>
00041 #include <netinet/in.h>
00042 #include <arpa/inet.h>
00043 #include <time.h>
00044
00045
00046 int netfd = -1;
00047 int preferredportno = 0;
00048
00049 #define JM_BUCKETS 500
00050
00051 static int jm_buckets_full= 0;
00052
00053 static int jm_dropped = 0;
00054 static int jm_delayed = 0;
00055
00056 static int jm_droppct = 0;
00057 static int jm_buckpct = 0;
00058 static double jm_jitter = 0;
00059
00060 static int jm_starttime = 0;
00061
00062
00063 struct jm_frame {
00064 char buf[2048];
00065 size_t len;
00066 struct sockaddr from;
00067 int occupied;
00068 unsigned deltime;
00069 };
00070
00071 struct jm_frame jm_buckets[JM_BUCKETS];
00072
00073
00074 long jm_time() {
00075 struct timeval tv;
00076 gettimeofday(&tv, NULL);
00077 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
00078 }
00079
00080 int jm_init() {
00081 int portno = preferredportno;
00082 struct sockaddr_in sin;
00083 unsigned int sinlen;
00084 int flags;
00085
00086 if (netfd > -1) {
00087
00088 fprintf(stderr, "Already initialized.");
00089 return 0;
00090 }
00091 netfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
00092 if (netfd < 0) {
00093 fprintf(stderr, "Unable to allocate UDP socket\n");
00094 fprintf(stderr, "Unable to allocate UDP socket\n");
00095 return -1;
00096 }
00097
00098 if (preferredportno == 0)
00099 preferredportno = 4569;
00100
00101 if (preferredportno > 0) {
00102 sin.sin_family = AF_INET;
00103 sin.sin_addr.s_addr = 0;
00104 sin.sin_port = htons((short)preferredportno);
00105 if (bind(netfd, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
00106 fprintf(stderr, "Unable to bind to preferred port. Using random one instead.");
00107 }
00108 }
00109 sinlen = sizeof(sin);
00110 if (getsockname(netfd, (struct sockaddr *) &sin, &sinlen) < 0) {
00111 close(netfd);
00112 netfd = -1;
00113 fprintf(stderr, "Unable to figure out what I'm bound to.");
00114 fprintf(stderr, "Unable to determine bound port number.");
00115 }
00116 #ifdef WIN32
00117 flags = 1;
00118 if (ioctlsocket(netfd,FIONBIO,(unsigned long *) &flags)) {
00119 _close(netfd);
00120 netfd = -1;
00121 fprintf(stderr, "Unable to set non-blocking mode.");
00122 fprintf(stderr, "Unable to set non-blocking mode.");
00123 }
00124
00125 #else
00126 if ((flags = fcntl(netfd, F_GETFL)) < 0) {
00127 close(netfd);
00128 netfd = -1;
00129 fprintf(stderr, "Unable to retrieve socket flags.");
00130 fprintf(stderr, "Unable to retrieve socket flags.");
00131 }
00132 if (fcntl(netfd, F_SETFL, flags | O_NONBLOCK) < 0) {
00133 close(netfd);
00134 netfd = -1;
00135 fprintf(stderr, "Unable to set non-blocking mode.");
00136 fprintf(stderr, "Unable to set non-blocking mode.");
00137 }
00138 #endif
00139 }
00140
00141 int jm_sendto(int fd, const void *buf, size_t sz, int i, const struct sockaddr * addr, socklen_t asz) {
00142 (void)fd;
00143
00144
00145
00146
00147 return sendto(netfd, buf, sz, i, addr, asz);
00148 }
00149
00150
00151
00152
00153 int jm_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen) {
00154 int ret;
00155 static int report;
00156
00157 (void)s;
00158
00159 ret = recvfrom(netfd,buf,len,flags,from,fromlen);
00160
00161
00162 if(ret <= 0) return ret;
00163
00164 if((report++ % 200) == 0)
00165 fprintf(stderr, "JM: %d dropped, %d delayed\n", jm_dropped, jm_delayed);
00166
00167
00168 if( (100.0*rand()/(RAND_MAX+1.0)) < jm_droppct) {
00169
00170 jm_dropped++;
00171 errno = EAGAIN;
00172 return -1;
00173 }
00174
00175
00176 if( 1 && (100.0*rand()/(RAND_MAX+1.0)) < jm_buckpct ) {
00177 int i,j;
00178 unsigned earlytm;
00179
00180
00181 for(i=0;i<JM_BUCKETS;i++) {
00182
00183 if(!jm_buckets[i].occupied) {
00184 memcpy(jm_buckets[i].buf, buf, ret);
00185 jm_buckets[i].len = ret;
00186 jm_buckets[i].from = *from;
00187 jm_buckets[i].occupied = 1;
00188 jm_buckets[i].deltime = jm_time() + (int)(jm_jitter*rand()/(RAND_MAX+1.0)) ;
00189
00190 jm_buckets_full++;
00191 break;
00192 }
00193 }
00194 if(i == JM_BUCKETS) jm_dropped++;
00195
00196 j = -1;
00197 earlytm = -1;
00198
00199 for(i = 0; i < JM_BUCKETS; i++) {
00200 if(jm_buckets[i].occupied && jm_buckets[i].deltime < earlytm) {
00201 j = i;
00202 earlytm = jm_buckets[i].deltime;
00203 }
00204 }
00205
00206 i=j;
00207 if(earlytm < jm_time() && i < JM_BUCKETS) {
00208 ret = jm_buckets[i].len;
00209 memcpy(buf,jm_buckets[i].buf, ret);
00210 *from = jm_buckets[i].from;
00211 jm_buckets[i].occupied = 0;
00212 jm_buckets_full --;
00213 jm_delayed++;
00214
00215 return ret;
00216 }
00217
00218
00219
00220
00221 #if 0
00222
00223 for(j=0;j<JM_BUCKETS/2;j++) {
00224 i = (int) ((double)JM_BUCKETS*rand()/(RAND_MAX+1.0));
00225 if(jm_buckets[i].occupied) {
00226 ret = jm_buckets[i].len;
00227 memcpy(buf,jm_buckets[i].buf, ret);
00228 *from = jm_buckets[i].from;
00229 jm_buckets[i].occupied = 0;
00230 jm_buckets_full --;
00231 jm_delayed++;
00232 return ret;
00233 }
00234 }
00235 #endif
00236
00237
00238 jm_dropped++;
00239 errno = EAGAIN;
00240 return -1;
00241 }
00242
00243
00244 return ret;
00245 }
00246
00247
00248
00249 #endif
00250
00251
00252 static int answered_call;
00253 static char *output_filename = NULL;
00254 int do_levels = 0;
00255
00256
00257
00258
00259 void killem(void)
00260 {
00261 iaxc_shutdown();
00262 return;
00263 }
00264
00265 void fatal_error(char *err) {
00266 killem();
00267 fprintf(stderr, "FATAL ERROR: %s\n", err);
00268 exit(1);
00269 }
00270
00271 void mysleep(void)
00272 {
00273 iaxc_millisleep(10);
00274 }
00275
00276 int levels_callback(float input, float output) {
00277 static int i;
00278 #ifdef notdefNETSTATS
00279 if(i%25 == 0)
00280 fprintf(stderr, "RTT\tRJIT\tRLOSP\tRLOSC\tRPKTS\tRDEL\tLJIT\tLLOSP\tLLOSC\tLPKTS\tLDEL\n");
00281 if(i++ % 5 == 0) {
00282 unsigned int info[10];
00283 iaxc_get_netstats(iaxc_selected_call(),info,10);
00284 fprintf(stderr, "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t\n",
00285 info[0], info[1], info[2]>>24, info[2] & 0xffffff, info[3], info[4],
00286 info[5], info[6]>>24, info[6] & 0xffffff, info[7], info[8]);
00287 }
00288
00289 #endif
00290 if(do_levels) fprintf(stderr, "IN: %f OUT: %f\n", input, output);
00291 return 0;
00292 }
00293
00294 int netstat_callback(struct iaxc_ev_netstats n) {
00295 static int i;
00296 if(i++%25 == 0)
00297 fprintf(stderr, "RTT\t"
00298 "Rjit\tRlos%\tRlosC\tRpkts\tRdel\tRdrop\tRooo\t"
00299 "Ljit\tLlos%\tLlosC\tLpkts\tLdel\tLdrop\tLooo\n"
00300 );
00301
00302 fprintf(stderr, "%d\t"
00303 "%d\t%d\t%d\t%d\t%d\t%d\t%d\t"
00304 "%d\t%d\t%d\t%d\t%d\t%d\t%d\n",
00305
00306 n.rtt,
00307
00308 n.remote.jitter,
00309 n.remote.losspct,
00310 n.remote.losscnt,
00311 n.remote.packets,
00312 n.remote.delay,
00313 n.remote.dropped,
00314 n.remote.ooo,
00315
00316 n.local.jitter,
00317 n.local.losspct,
00318 n.local.losscnt,
00319 n.local.packets,
00320 n.local.delay,
00321 n.local.dropped,
00322 n.local.ooo
00323 );
00324
00325 return 0;
00326 }
00327
00328 int iaxc_callback(iaxc_event e)
00329 {
00330 switch(e.type) {
00331 case IAXC_EVENT_LEVELS:
00332 return levels_callback(e.ev.levels.input, e.ev.levels.output);
00333 case IAXC_EVENT_NETSTAT:
00334 return netstat_callback(e.ev.netstats);
00335 case IAXC_EVENT_TEXT:
00336 return 0;
00337 case IAXC_EVENT_STATE:
00338 return 0;
00339 default:
00340 return 0;
00341 }
00342 }
00343
00344 void list_devices()
00345 {
00346 struct iaxc_audio_device *devs;
00347 int nDevs, input, output, ring;
00348 int i;
00349
00350 iaxc_audio_devices_get(&devs,&nDevs, &input, &output, &ring);
00351 for(i=0;i<nDevs;i++) {
00352 fprintf(stderr, "DEVICE ID=%d NAME=%s CAPS=%x\n", devs[i].devID, devs[i].name, devs[i].capabilities);
00353 }
00354 }
00355
00356 void usage()
00357 {
00358 fprintf(stderr, "Usage is XXX\n");
00359 exit(1);
00360 }
00361
00362 int main(int argc, char **argv)
00363 {
00364 FILE *f;
00365 char c;
00366 int i;
00367 char *dest = "guest@10.23.1.31/9999";
00368 double silence_threshold = -99;
00369
00370
00371 f = stdout;
00372
00373 for(i=1;i<argc;i++)
00374 {
00375 if(argv[i][0] == '-')
00376 {
00377 switch(tolower(argv[i][1]))
00378 {
00379 case 'v':
00380 do_levels = 1;
00381 break;
00382 case 's':
00383 if(i+1 >= argc) usage();
00384 silence_threshold = atof(argv[++i]);
00385 break;
00386 case 'f':
00387 if(i+1 >= argc) usage();
00388 output_filename = argv[++i];
00389 break;
00390
00391 default:
00392 usage();
00393 }
00394 } else {
00395 dest=argv[i];
00396 }
00397 }
00398
00399
00400 printf("settings: \n");
00401 printf("\tsilence threshold: %f\n", silence_threshold);
00402 printf("\tlevel output: %s\n", do_levels ? "on" : "off");
00403
00404
00405 atexit(killem);
00406
00407 #ifdef JITTERMAKER
00408 jm_init();
00409 iaxc_set_networking(jm_sendto, jm_recvfrom);
00410 #endif
00411
00412 if(output_filename) {
00413 FILE *outfile;
00414 if(iaxc_initialize(AUDIO_INTERNAL_FILE,1))
00415 fatal_error("cannot initialize iaxclient!");
00416 outfile = fopen(output_filename,"w");
00417 iaxc_set_files(NULL, outfile);
00418 } else {
00419 if(iaxc_initialize(AUDIO_INTERNAL_PA,1))
00420 fatal_error("cannot initialize iaxclient!");
00421 }
00422
00423
00424 iaxc_set_formats(IAXC_FORMAT_SPEEX,IAXC_FORMAT_ILBC|IAXC_FORMAT_ALAW|IAXC_FORMAT_ULAW|IAXC_FORMAT_GSM|IAXC_FORMAT_SPEEX);
00425
00426
00427
00428 iaxc_set_silence_threshold(silence_threshold);
00429
00430 list_devices();
00431
00432 iaxc_set_event_callback(iaxc_callback);
00433
00434
00435 fprintf(f, "\n\
00436 TestCall accept some keyboard input while it's running.\n\
00437 You must hit 'enter' for your keypresses to be recognized,\n\
00438 although you can type more than one key on a line\n\
00439 \n\
00440 q: drop the call and hangup.\n\
00441 0-9 * or #: dial those DTMF digits.\n");
00442 fprintf(f, "Calling %s\n", dest);
00443
00444 iaxc_call(dest);
00445
00446 iaxc_start_processing_thread();
00447 printf("ready for keyboard input\n");
00448
00449 if(output_filename) {
00450 for(;;)
00451 sleep(10);
00452 }
00453 while(c = getc(stdin)) {
00454 switch (tolower(c)) {
00455 case 'q':
00456 printf("Hanging up and exiting\n");
00457 iaxc_dump_call();
00458 iaxc_millisleep(1000);
00459 iaxc_stop_processing_thread();
00460 exit(0);
00461 break;
00462
00463 case '1': case '2': case '3': case '4': case '5':
00464 jm_droppct = 10 * (c - '1');
00465 fprintf(stderr, "setting jm_droppct to %d\n", jm_droppct);
00466 break;
00467 case '6': case '7': case '8': case '9': case '0':
00468 jm_buckpct = 15 * (c - '6');
00469 fprintf(stderr, "setting jm_buckpct to %d\n", jm_buckpct);
00470 break;
00471 case '#': case '*':
00472 printf ("sending %c\n", c);
00473 iaxc_send_dtmf(c);
00474 break;
00475 }
00476 }
00477
00478 return 0;
00479 }