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 #include <signal.h>
00023
00024 #include "iaxclient.h"
00025
00026 #include <SDL.h>
00027
00028 #ifdef WIN32
00029
00030 #undef main
00031 #endif
00032
00033 #define MAX_CALLS 6
00034
00035 static int video = 0;
00036
00037
00038 int format = IAXC_FORMAT_H263 | IAXC_FORMAT_H263_PLUS | IAXC_FORMAT_H264 | IAXC_FORMAT_MPEG4 | IAXC_FORMAT_THEORA;
00039 int formatp = IAXC_FORMAT_H264;
00040 int framerate = 15;
00041 int bitrate = 400000;
00042 int width = 320;
00043 int height = 240;
00044 int fragsize = 4000;
00045
00046 int preview = 1;
00047
00048
00049 int display_video(struct iaxc_ev_video v, int remote);
00050 void process_text_message(char *message);
00051
00052 char caption[80] = "";
00053
00054 SDL_mutex *mut;
00055
00056
00057 struct iaxc_sound sound_ringOUT, sound_ringIN;
00058
00059
00060
00061
00062 void killem(void)
00063 {
00064 fprintf(stderr,"Calling iaxc_shutdown...");
00065 iaxc_shutdown();
00066 fprintf(stderr,"Done.\nCallig SDL_Quit...\n");
00067 SDL_DestroyMutex(mut);
00068 SDL_Quit();
00069 fprintf(stderr,"Done\nProgram terminated correctly.\n");
00070 exit(0);
00071 }
00072
00073 void signal_handler(int signum)
00074 {
00075 if ( signum == SIGTERM || signum == SIGINT )
00076 {
00077 killem();
00078 exit(0);
00079 }
00080 }
00081
00082 void fatal_error(char *err) {
00083 killem();
00084 fprintf(stderr, "FATAL ERROR: %s\n", err);
00085 exit(1);
00086 }
00087
00088 void mysleep(void)
00089 {
00090 iaxc_millisleep(10);
00091 }
00092
00093 int levels_callback(float input, float output) {
00094
00095 return 1;
00096 }
00097
00098 int netstat_callback(struct iaxc_ev_netstats n) {
00099 static int i;
00100 if(i++%25 == 0)
00101 fprintf(stderr, "RTT\t"
00102 "Rjit\tRlos%%\tRlosC\tRpkts\tRdel\tRdrop\tRooo\t"
00103 "Ljit\tLlos%%\tLlosC\tLpkts\tLdel\tLdrop\tLooo\n");
00104
00105 fprintf(stderr, "%d\t"
00106 "%d\t%d\t%d\t%d\t%d\t%d\t%d\t"
00107 "%d\t%d\t%d\t%d\t%d\t%d\t%d\n",
00108
00109 n.rtt,
00110
00111 n.remote.jitter,
00112 n.remote.losspct,
00113 n.remote.losscnt,
00114 n.remote.packets,
00115 n.remote.delay,
00116 n.remote.dropped,
00117 n.remote.ooo,
00118
00119 n.local.jitter,
00120 n.local.losspct,
00121 n.local.losscnt,
00122 n.local.packets,
00123 n.local.delay,
00124 n.local.dropped,
00125 n.local.ooo
00126 );
00127
00128 return 0;
00129 }
00130
00131 void hangup_and_exit(void)
00132 {
00133 iaxc_dump_call();
00134 fprintf(stderr,"Dumped call\n");
00135 iaxc_millisleep(1000);
00136 fprintf(stderr,"Sleeped for 1000 msec\n");
00137 iaxc_stop_processing_thread();
00138 fprintf(stderr,"Stopped processing thread\n");
00139 killem();
00140 }
00141
00142
00143 void my_safe_caption(char* c)
00144 {
00145 if(SDL_mutexP(mut)==-1)
00146 {
00147 fprintf(stderr, "Couldn't lock mutex");
00148 exit(-1);
00149 }
00150
00151 SDL_WM_SetCaption(c, NULL);
00152
00153 if(SDL_mutexV(mut)==-1)
00154 {
00155 fprintf(stderr, "Couldn't unlock mutex");
00156 exit(-1);
00157 }
00158
00159 }
00160
00161 int state_callback(struct iaxc_ev_call_state s)
00162 {
00163 printf("------------------------------------------------------------\n");
00164 printf("Call #%d state report\n",s.callNo);
00165 printf("State\t\t: \t %d\n",s.state);
00166 printf("Format\t\t: \t %d\n",s.format);
00167 printf("Video format\t: \t %d\n",s.vformat);
00168 printf("Remote\t\t: \t %s\n",s.remote);
00169 printf("Remote name\t: \t %s\n",s.remote_name);
00170 printf("Local\t\t: \t %s\n",s.local);
00171 printf("Local context\t: \t %s\n",s.local_context);
00172 printf("------------------------------------------------------------\n");
00173
00174
00175 if (s.state == (IAXC_CALL_STATE_ACTIVE | IAXC_CALL_STATE_COMPLETE))
00176 {
00177 iaxc_stop_sound(sound_ringIN.id);
00178 }
00179 if (!(s.state & (IAXC_CALL_STATE_BUSY|IAXC_CALL_STATE_TRANSFER)))
00180 {
00181 iaxc_stop_sound(sound_ringOUT.id);
00182 }
00183 if (s.state == (IAXC_CALL_STATE_ACTIVE|IAXC_CALL_STATE_RINGING))
00184 {
00185
00186
00187 fprintf(stderr,"Auto-Answering to caller %s on line %d...\n",s.remote,s.callNo);
00188 sprintf(caption,"Auto-Answering to caller %s on line %d...\n",s.remote,s.callNo);
00189 my_safe_caption(caption);
00190 fprintf(stderr, "Mihai: answer call vformat=0x%x\n", s.vformat);
00191
00192 iaxc_millisleep(1000);
00193 iaxc_answer_call(s.callNo);
00194 iaxc_select_call(s.callNo);
00195
00196 return 0;
00197 }
00198 if (s.state == IAXC_CALL_STATE_FREE)
00199 {
00200 fprintf(stderr,"Disconnect from other end\n");
00201 hangup_and_exit();
00202 }
00203
00204 return 0;
00205 }
00206
00207 int iaxc_callback(iaxc_event e)
00208 {
00209
00210 switch ( e.type )
00211 {
00212 case IAXC_EVENT_LEVELS:
00213 return levels_callback(e.ev.levels.input, e.ev.levels.output);
00214 case IAXC_EVENT_NETSTAT:
00215 return netstat_callback(e.ev.netstats);
00216 case IAXC_EVENT_TEXT:
00217 process_text_message(e.ev.text.message);
00218 break;
00219 case IAXC_EVENT_STATE:
00220 return state_callback(e.ev.call);
00221 case IAXC_EVENT_VIDEO:
00222 if ( !video )
00223 return 0;
00224
00225 if ( !e.ev.video.encoded )
00226 return display_video(e.ev.video,
00227 e.ev.video.source == IAXC_SOURCE_REMOTE);
00228 else
00229 fprintf(stderr, "We cannot handle encoded video in callbacks yet\n");
00230 break;
00231
00232 case IAXC_EVENT_AUDIO:
00233 fprintf(stderr, "Got %s %s audio\n",
00234 e.ev.audio.source == IAXC_SOURCE_REMOTE ? "remote" : "local",
00235 e.ev.audio.encoded ? "encoded" : "raw");
00236 break;
00237 default:
00238 break;
00239 }
00240
00241 return 0;
00242 }
00243
00244 void process_text_message(char *message)
00245 {
00246 unsigned int prefs;
00247
00248 if ( strncmp(message, "CONTROL:", strlen("CONTROL:")) == 0 )
00249 {
00250 message += strlen("CONTROL:");
00251 if ( strcmp(message, "STOPVIDEO") == 0 )
00252 {
00253
00254 prefs = iaxc_get_video_prefs();
00255 prefs = prefs | IAXC_VIDEO_PREF_SEND_DISABLE ;
00256 iaxc_set_video_prefs(prefs);
00257 } else if ( strcmp(message, "STARTVIDEO") == 0 )
00258 {
00259
00260 prefs = iaxc_get_video_prefs();
00261 prefs = prefs & ~IAXC_VIDEO_PREF_SEND_DISABLE ;
00262 iaxc_set_video_prefs(prefs);
00263 }
00264 } else
00265 fprintf(stderr, "Text message received: %s\n", message);
00266 }
00267
00268 void list_devices()
00269 {
00270 struct iaxc_audio_device *devs;
00271 int nDevs, input, output,ring;
00272 int i;
00273
00274 iaxc_audio_devices_get(&devs,&nDevs, &input, &output, &ring);
00275 for(i=0;i<nDevs;i++)
00276 {
00277 fprintf(stderr, "DEVICE ID=%d NAME=%s CAPS=%lx\n", devs[i].devID, devs[i].name, devs[i].capabilities);
00278 iaxc_audio_devices_set(input,output,ring);
00279 }
00280 }
00281
00282 void usage()
00283 {
00284 printf(
00285 "\n"
00286 "Usage is: tescall <options>\n\n"
00287 "available options:\n"
00288 "-F [codec,framerate,bitrate,width,height,fragsize]\t \n"
00289 "-V force video mode\n"
00290 "-s set silence threshold\n"
00291 "-v [input_video_filename]\n"
00292 "-f [output_video_filename]\n"
00293 "-i [input_audio_filename]\n"
00294 "-a [output_audio_filename]\n"
00295 "\n"
00296 );
00297
00298 exit(1);
00299 }
00300
00301 static SDL_Surface *window;
00302 SDL_Overlay *rolay;
00303 SDL_Overlay *lolay;
00304 unsigned char *remote_data = NULL;
00305 unsigned char *local_data = NULL;
00306
00307 int init_sdl()
00308 {
00309 int InitCode;
00310
00311 #ifdef LINUX
00312 InitCode=SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE|SDL_INIT_EVENTTHREAD;;
00313 #else
00314 InitCode=SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE;
00315 #endif
00316
00317 if( SDL_Init(InitCode) < 0 )
00318 {
00319 fprintf(stderr, "could not init SDL: %s\n", SDL_GetError());
00320 return -1;
00321 }
00322 atexit(SDL_Quit);
00323
00324
00325 window = SDL_SetVideoMode(width,height, 24, SDL_HWSURFACE|SDL_DOUBLEBUF|SDL_ASYNCBLIT|SDL_HWACCEL|SDL_RESIZABLE);
00326 if( !window )
00327 {
00328 fprintf(stderr, "could not open one of the output windows\n");
00329 return -1;
00330 }
00331
00332 rolay = SDL_CreateYUVOverlay(width, height, SDL_IYUV_OVERLAY, window);
00333 if ( !rolay )
00334 {
00335 fprintf(stderr, "could not create Remote video overlay");
00336 return -1;
00337 }
00338 lolay = SDL_CreateYUVOverlay(width, height, SDL_IYUV_OVERLAY, window);
00339 if( !lolay )
00340 {
00341 fprintf(stderr, "could not create Local video overlay\n");
00342 return -1;
00343 }
00344
00345
00346 SDL_EventState(SDL_ACTIVEEVENT, SDL_IGNORE);
00347 SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
00348 SDL_EventState(SDL_SYSWMEVENT, SDL_IGNORE);
00349 SDL_EventState(SDL_USEREVENT, SDL_IGNORE);
00350 mut=SDL_CreateMutex();
00351
00352 return 0;
00353 }
00354
00355 int display_video(struct iaxc_ev_video v, int remote)
00356 {
00357 SDL_Rect Rrect = {v.width/2, v.height/2, v.width/2, v.height/2};
00358 SDL_Rect rect = {0, 0, v.width, v.height};
00359
00360 if( SDL_mutexP(mut) == -1 )
00361 {
00362 fprintf(stderr, "Couldn't lock mutex");
00363 exit(-1);
00364 }
00365
00366 if ( v.size <= 0 ) fprintf(stderr, "WARNING: size %d in callback\n", v.size);
00367
00368 if ( !remote )
00369 {
00370
00371
00372 if ( local_data != NULL )
00373 {
00374 free(local_data);
00375 local_data = NULL;
00376 }
00377 local_data = (unsigned char *)malloc(v.size);
00378 memcpy(local_data, v.data, v.size);
00379
00380 SDL_LockYUVOverlay(lolay);
00381 lolay->pixels[0] = local_data;
00382 lolay->pixels[1] = local_data + (v.width * v.height);
00383 lolay->pixels[2] = local_data + (v.width * v.height * 5 / 4 );
00384 SDL_UnlockYUVOverlay(lolay);
00385
00386 if (remote_data != NULL)
00387 {
00388 SDL_DisplayYUVOverlay(rolay, &rect);
00389 if (preview)
00390 SDL_DisplayYUVOverlay(lolay, &Rrect);
00391 }
00392 else
00393 SDL_DisplayYUVOverlay(lolay, &Rrect);
00394
00395 } else
00396 {
00397
00398
00399 if ( remote_data != NULL )
00400 {
00401 free(remote_data);
00402 remote_data = NULL;
00403 }
00404 remote_data = (unsigned char *)malloc(v.size);
00405 memcpy(remote_data, v.data, v.size);
00406
00407 if ( v.callNo < 0 || v.callNo > MAX_CALLS ) return -1;
00408 SDL_LockYUVOverlay(rolay);
00409 rolay->pixels[0] = remote_data;
00410 rolay->pixels[1] = remote_data + (v.width * v.height);
00411 rolay->pixels[2] = remote_data + (v.width * v.height * 5/4);
00412 SDL_UnlockYUVOverlay(rolay);
00413 SDL_DisplayYUVOverlay(rolay, &rect);
00414
00415
00416 if (preview)
00417 SDL_DisplayYUVOverlay(lolay, &Rrect);
00418 }
00419
00420 if( SDL_mutexV(mut) == -1 )
00421 {
00422 fprintf(stderr, "Couldn't unlock mutex");
00423 exit(-1);
00424 }
00425 return 0;
00426 }
00427
00428 int main(int argc, char **argv)
00429 {
00430 FILE *f = stdout;
00431 char c;
00432 int i;
00433 char mydest[80], *dest = NULL;
00434 double silence_threshold = -99;
00435 char *WF_file = NULL;
00436 int jbypass = 0;
00437
00438
00439 signal(SIGINT, signal_handler);
00440 signal(SIGTERM, signal_handler);
00441
00442
00443 for(i=1;i<argc;i++)
00444 {
00445 if(argv[i][0] == '-')
00446 {
00447 switch(argv[i][1])
00448 {
00449 case 'V':
00450 video = 1;
00451 break;
00452 case 'F':
00453 {
00454 formatp = 1<<atoi(argv[++i]);
00455 framerate = atoi(argv[++i]);
00456 bitrate = atoi(argv[++i]);
00457 width = atoi(argv[++i]);
00458 height = atoi(argv[++i]);
00459 fragsize = atoi(argv[++i]);
00460 }
00461 break;
00462 case 'P':
00463 preview = 0;
00464 break;
00465 case 's':
00466 if(i+1 >= argc) usage();
00467 silence_threshold = atof(argv[++i]);
00468 break;
00469 case 'r':
00470 if(i+3 >= argc) usage();
00471 iaxc_register(argv[i+1],argv[i+2],argv[i+3]);
00472 i+=3;
00473 break;
00474 case 'h':
00475 if(i+1 >= argc) usage();
00476 WF_file=argv[++i];
00477 break;
00478
00479 default:
00480 usage();
00481 }
00482 } else
00483 {
00484 dest=argv[i];
00485
00486 }
00487 }
00488
00489 if ( width<128 || height<96 )
00490 {
00491 fprintf(stderr,"Frame is too small\n");
00492 usage();
00493 }
00494
00495 if ( width%2 || height%2 )
00496 {
00497 fprintf(stderr,"Frame width and height must be multiple of 2\n");
00498 usage();
00499 }
00500
00501
00502 iaxc_video_format_set(formatp, format, framerate, bitrate, width, height, fragsize);
00503
00504 fprintf(stderr,">>> Forcing video mode!\n");
00505 video=1;
00506
00507 if ( video )
00508 {
00509 if( init_sdl() )
00510 {
00511 fprintf(stderr, "could not init SDL\n");
00512 return -1;
00513 }
00514 }
00515
00516 if (iaxc_initialize(MAX_CALLS)) fatal_error("cannot initialize iaxclient!");
00517
00518
00519 iaxc_set_formats(IAXC_FORMAT_SPEEX, IAXC_FORMAT_SPEEX);
00520
00521 iaxc_set_silence_threshold(1.0);
00522 iaxc_set_audio_output(0);
00523 iaxc_set_filters(IAXC_FILTER_DENOISE|IAXC_FILTER_CN);
00524
00525 list_devices();
00526
00527 iaxc_set_event_callback(iaxc_callback);
00528
00529
00530 iaxc_video_bypass_jitter(0);
00531
00532
00533
00534 iaxc_set_video_prefs(IAXC_VIDEO_PREF_RECV_LOCAL_RAW |
00535 IAXC_VIDEO_PREF_RECV_REMOTE_RAW);
00536
00537
00538
00539
00540
00541 fprintf(f, "\n\
00542 TestCall accept some keyboard input while it's running.\n\
00543 You must hit 'enter' for your keypresses to be recognized,\n\
00544 although you can type more than one key on a line\n\
00545 \n\
00546 q: drop the call and hangup.\n\
00547 0-9 * or #: dial those DTMF digits.\n");
00548
00549 printf("Starting processing thread...\n");
00550 iaxc_start_processing_thread();
00551
00552 if ( dest != NULL )
00553 {
00554 sprintf(caption, "Calling to %s", dest);
00555 fprintf(stderr, "Calling to %s\n", dest);
00556 my_safe_caption(caption);
00557 int callNo = iaxc_call(dest);
00558 if (callNo <= 0)
00559 iaxc_select_call(callNo);
00560 else
00561 fprintf(stderr, "Failed to make call to '%s'", dest);
00562 }
00563
00564
00565 printf("ready for keyboard input\n");
00566 for(;;) {
00567 SDL_Event event;
00568 while (1) {
00569 SDL_WaitEvent(&event);
00570 if(event.type == SDL_QUIT) {
00571 break;
00572 } else if(event.type == SDL_KEYDOWN) {
00573 switch(event.key.keysym.sym) {
00574 case SDLK_a:
00575 printf("Answering to incoming call...\n");
00576 break;
00577 case SDLK_b:
00578 jbypass=(jbypass+1) % 2;
00579 printf("New bypass video jitter buffer mode=%d\n",jbypass);
00580 iaxc_video_bypass_jitter(jbypass);
00581 break;
00582 case SDLK_q:
00583 printf("Hanging up and exiting\n");
00584 hangup_and_exit();
00585 break;
00586 case SDLK_r:
00587 printf("Rejecting incoming call...\n");
00588 iaxc_reject_call();
00589 iaxc_dump_call();
00590 break;
00591 case SDLK_h:
00592 printf("Hanging up selected call...\n");
00593 iaxc_dump_call();
00594 break;
00595 case SDLK_d:
00596 printf("Select type of call (Audio only or audio/Video): ");
00597 fflush(stdin);
00598
00599 fscanf(stdin,"%s",mydest);
00600
00601 fprintf(stderr,"format_set a %d,%d,%d,%d,%d,%d,%d\n",formatp, format, framerate, bitrate, width, height, fragsize);
00602 iaxc_video_format_set(formatp, format, framerate, bitrate, width, height, fragsize);
00603
00604
00605
00606
00607
00608 printf("Insert address to dial to in `%s' type call: ",mydest[0]=='A'?"A only":"A/V");
00609 fscanf(stdin,"%s",mydest);
00610 fprintf(stderr,"\n --> Calling to %s\n",mydest);
00611 sprintf(caption,"Calling to %s",mydest);
00612 my_safe_caption(caption);
00613
00614
00615 iaxc_call_ex(mydest, NULL, NULL, (mydest[0]!='A'));
00616 break;
00617 case SDLK_c:
00618 {
00619 char myCIDname[80];
00620 char myCIDnumber[80];
00621
00622 printf("Insert caller name: ");
00623 fscanf(stdin,"%s",myCIDname);
00624 printf("Insert caller ID number: ");
00625 fscanf(stdin,"%s",myCIDnumber);
00626 iaxc_set_callerid(myCIDname,myCIDnumber);
00627 }
00628 break;
00629 case SDLK_t:
00630 printf("transmit mode active\n");
00631 break;
00632 case SDLK_w:
00633 {
00634 unsigned int prefs;
00635
00636 prefs = iaxc_get_video_prefs();
00637
00638 if ( prefs & IAXC_VIDEO_PREF_CAPTURE_DISABLE )
00639 {
00640 prefs &= ~IAXC_VIDEO_PREF_CAPTURE_DISABLE;
00641 printf("video switched on\n");
00642 }
00643 else
00644 {
00645 prefs |= IAXC_VIDEO_PREF_CAPTURE_DISABLE;
00646 printf("video switched off\n");
00647 }
00648 iaxc_set_video_prefs(prefs);
00649 }
00650 break;
00651 #if 1
00652 case '1': case '2': case '3': case '4': case '5':
00653 case '6': case '7': case '8': case '9': case '0':
00654 case '#': case '*':
00655 c=event.key.keysym.sym;
00656 printf (">>>>>>>>>> sending %c\n", c);
00657 iaxc_send_dtmf(c);
00658 break;
00659 #endif
00660 default:
00661 fprintf(stderr,"Keystroke %c not handled!\n",event.key.keysym.sym);
00662 break;
00663 }
00664 }
00665 }
00666 }
00667
00668 return 0;
00669 }