Add support for ICE/STUN/TURN in res_rtp_asterisk and chan_sip.
[asterisk/asterisk.git] / res / pjproject / pjsip-apps / src / samples / siprtp.c
1 /* $Id$ */
2 /* 
3  * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4  * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
19  */
20
21
22
23
24
25 /* Usage */
26 static const char *USAGE = 
27 " PURPOSE:                                                                  \n"
28 "   This program establishes SIP INVITE session and media, and calculate    \n"
29 "   the media quality (packet lost, jitter, rtt, etc.). Unlike normal       \n"
30 "   pjmedia applications, this program bypasses all pjmedia stream          \n"
31 "   framework and transmit encoded RTP packets manually using own thread.   \n"
32 "\n"
33 " USAGE:\n"
34 "   siprtp [options]        => to start in server mode\n"
35 "   siprtp [options] URL    => to start in client mode\n"
36 "\n"
37 " Program options:\n"
38 "   --count=N,        -c    Set number of calls to create (default:1) \n"
39 "   --gap=N           -g    Set call gapping to N msec (default:0)\n"
40 "   --duration=SEC,   -d    Set maximum call duration (default:unlimited) \n"
41 "   --auto-quit,      -q    Quit when calls have been completed (default:no)\n"
42 "   --call-report     -R    Display report on call termination (default:yes)\n"
43 "\n"
44 " Address and ports options:\n"
45 "   --local-port=PORT,-p    Set local SIP port (default: 5060)\n"
46 "   --rtp-port=PORT,  -r    Set start of RTP port (default: 4000)\n"
47 "   --ip-addr=IP,     -i    Set local IP address to use (otherwise it will\n"
48 "                           try to determine local IP address from hostname)\n"
49 "\n"
50 " Logging Options:\n"
51 "   --log-level=N,    -l    Set log verbosity level (default=5)\n"
52 "   --app-log-level=N       Set app screen log verbosity (default=3)\n"
53 "   --log-file=FILE         Write log to file FILE\n"
54 "   --report-file=FILE      Write report to file FILE\n"
55 "\n"
56 /* Don't support this anymore, because codec is properly examined in
57    pjmedia_session_info_from_sdp() function.
58
59 " Codec Options:\n"
60 "   --a-pt=PT               Set audio payload type to PT (default=0)\n"
61 "   --a-name=NAME           Set audio codec name to NAME (default=pcmu)\n"
62 "   --a-clock=RATE          Set audio codec rate to RATE Hz (default=8000Hz)\n"
63 "   --a-bitrate=BPS         Set audio codec bitrate to BPS (default=64000bps)\n"
64 "   --a-ptime=MS            Set audio frame time to MS msec (default=20ms)\n"
65 */
66 ;
67
68
69 /* Include all headers. */
70 #include <pjsip.h>
71 #include <pjmedia.h>
72 #include <pjmedia-codec.h>
73 #include <pjsip_ua.h>
74 #include <pjsip_simple.h>
75 #include <pjlib-util.h>
76 #include <pjlib.h>
77
78 #include <stdlib.h>
79
80 /* Uncomment these to disable threads.
81  * NOTE:
82  *   when threading is disabled, siprtp won't transmit any
83  *   RTP packets.
84  */
85 /*
86 #undef PJ_HAS_THREADS
87 #define PJ_HAS_THREADS 0
88 */
89
90
91 #if PJ_HAS_HIGH_RES_TIMER==0
92 #   error "High resolution timer is needed for this sample"
93 #endif
94
95 #define THIS_FILE       "siprtp.c"
96 #define MAX_CALLS       1024
97 #define RTP_START_PORT  4000
98
99
100 /* Codec descriptor: */
101 struct codec
102 {
103     unsigned    pt;
104     char*       name;
105     unsigned    clock_rate;
106     unsigned    bit_rate;
107     unsigned    ptime;
108     char*       description;
109 };
110
111
112 /* A bidirectional media stream created when the call is active. */
113 struct media_stream
114 {
115     /* Static: */
116     unsigned             call_index;        /* Call owner.              */
117     unsigned             media_index;       /* Media index in call.     */
118     pjmedia_transport   *transport;         /* To send/recv RTP/RTCP    */
119
120     /* Active? */
121     pj_bool_t            active;            /* Non-zero if is in call.  */
122
123     /* Current stream info: */
124     pjmedia_stream_info  si;                /* Current stream info.     */
125
126     /* More info: */
127     unsigned             clock_rate;        /* clock rate               */
128     unsigned             samples_per_frame; /* samples per frame        */
129     unsigned             bytes_per_frame;   /* frame size.              */
130
131     /* RTP session: */
132     pjmedia_rtp_session  out_sess;          /* outgoing RTP session     */
133     pjmedia_rtp_session  in_sess;           /* incoming RTP session     */
134
135     /* RTCP stats: */
136     pjmedia_rtcp_session rtcp;              /* incoming RTCP session.   */
137
138     /* Thread: */
139     pj_bool_t            thread_quit_flag;  /* Stop media thread.       */
140     pj_thread_t         *thread;            /* Media thread.            */
141 };
142
143
144 /* This is a call structure that is created when the application starts
145  * and only destroyed when the application quits.
146  */
147 struct call
148 {
149     unsigned             index;
150     pjsip_inv_session   *inv;
151     unsigned             media_count;
152     struct media_stream  media[1];
153     pj_time_val          start_time;
154     pj_time_val          response_time;
155     pj_time_val          connect_time;
156
157     pj_timer_entry       d_timer;           /**< Disconnect timer.      */
158 };
159
160
161 /* Application's global variables */
162 static struct app
163 {
164     unsigned             max_calls;
165     unsigned             call_gap;
166     pj_bool_t            call_report;
167     unsigned             uac_calls;
168     unsigned             duration;
169     pj_bool_t            auto_quit;
170     unsigned             thread_count;
171     int                  sip_port;
172     int                  rtp_start_port;
173     pj_str_t             local_addr;
174     pj_str_t             local_uri;
175     pj_str_t             local_contact;
176     
177     int                  app_log_level;
178     int                  log_level;
179     char                *log_filename;
180     char                *report_filename;
181
182     struct codec         audio_codec;
183
184     pj_str_t             uri_to_call;
185
186     pj_caching_pool      cp;
187     pj_pool_t           *pool;
188
189     pjsip_endpoint      *sip_endpt;
190     pj_bool_t            thread_quit;
191     pj_thread_t         *sip_thread[1];
192
193     pjmedia_endpt       *med_endpt;
194     struct call          call[MAX_CALLS];
195 } app;
196
197
198
199 /*
200  * Prototypes:
201  */
202
203 /* Callback to be called when SDP negotiation is done in the call: */
204 static void call_on_media_update( pjsip_inv_session *inv,
205                                   pj_status_t status);
206
207 /* Callback to be called when invite session's state has changed: */
208 static void call_on_state_changed( pjsip_inv_session *inv, 
209                                    pjsip_event *e);
210
211 /* Callback to be called when dialog has forked: */
212 static void call_on_forked(pjsip_inv_session *inv, pjsip_event *e);
213
214 /* Callback to be called to handle incoming requests outside dialogs: */
215 static pj_bool_t on_rx_request( pjsip_rx_data *rdata );
216
217 /* Worker thread prototype */
218 static int sip_worker_thread(void *arg);
219
220 /* Create SDP for call */
221 static pj_status_t create_sdp( pj_pool_t *pool,
222                                struct call *call,
223                                pjmedia_sdp_session **p_sdp);
224
225 /* Hangup call */
226 static void hangup_call(unsigned index);
227
228 /* Destroy the call's media */
229 static void destroy_call_media(unsigned call_index);
230
231 /* Destroy media. */
232 static void destroy_media();
233
234 /* This callback is called by media transport on receipt of RTP packet. */
235 static void on_rx_rtp(void *user_data, void *pkt, pj_ssize_t size);
236
237 /* This callback is called by media transport on receipt of RTCP packet. */
238 static void on_rx_rtcp(void *user_data, void *pkt, pj_ssize_t size);
239
240 /* Display error */
241 static void app_perror(const char *sender, const char *title, 
242                        pj_status_t status);
243
244 /* Print call */
245 static void print_call(int call_index);
246
247
248 /* This is a PJSIP module to be registered by application to handle
249  * incoming requests outside any dialogs/transactions. The main purpose
250  * here is to handle incoming INVITE request message, where we will
251  * create a dialog and INVITE session for it.
252  */
253 static pjsip_module mod_siprtp =
254 {
255     NULL, NULL,                     /* prev, next.              */
256     { "mod-siprtpapp", 13 },        /* Name.                    */
257     -1,                             /* Id                       */
258     PJSIP_MOD_PRIORITY_APPLICATION, /* Priority                 */
259     NULL,                           /* load()                   */
260     NULL,                           /* start()                  */
261     NULL,                           /* stop()                   */
262     NULL,                           /* unload()                 */
263     &on_rx_request,                 /* on_rx_request()          */
264     NULL,                           /* on_rx_response()         */
265     NULL,                           /* on_tx_request.           */
266     NULL,                           /* on_tx_response()         */
267     NULL,                           /* on_tsx_state()           */
268 };
269
270
271 /* Codec constants */
272 struct codec audio_codecs[] = 
273 {
274     { 0,  "PCMU", 8000, 64000, 20, "G.711 ULaw" },
275     { 3,  "GSM",  8000, 13200, 20, "GSM" },
276     { 4,  "G723", 8000, 6400,  30, "G.723.1" },
277     { 8,  "PCMA", 8000, 64000, 20, "G.711 ALaw" },
278     { 18, "G729", 8000, 8000,  20, "G.729" },
279 };
280
281
282 /*
283  * Init SIP stack
284  */
285 static pj_status_t init_sip()
286 {
287     unsigned i;
288     pj_status_t status;
289
290     /* init PJLIB-UTIL: */
291     status = pjlib_util_init();
292     PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
293
294     /* Must create a pool factory before we can allocate any memory. */
295     pj_caching_pool_init(&app.cp, &pj_pool_factory_default_policy, 0);
296
297     /* Create application pool for misc. */
298     app.pool = pj_pool_create(&app.cp.factory, "app", 1000, 1000, NULL);
299
300     /* Create the endpoint: */
301     status = pjsip_endpt_create(&app.cp.factory, pj_gethostname()->ptr, 
302                                 &app.sip_endpt);
303     PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
304
305
306     /* Add UDP transport. */
307     {
308         pj_sockaddr_in addr;
309         pjsip_host_port addrname;
310         pjsip_transport *tp;
311
312         pj_bzero(&addr, sizeof(addr));
313         addr.sin_family = pj_AF_INET();
314         addr.sin_addr.s_addr = 0;
315         addr.sin_port = pj_htons((pj_uint16_t)app.sip_port);
316
317         if (app.local_addr.slen) {
318
319             addrname.host = app.local_addr;
320             addrname.port = app.sip_port;
321
322             status = pj_sockaddr_in_init(&addr, &app.local_addr, 
323                                          (pj_uint16_t)app.sip_port);
324             if (status != PJ_SUCCESS) {
325                 app_perror(THIS_FILE, "Unable to resolve IP interface", status);
326                 return status;
327             }
328         }
329
330         status = pjsip_udp_transport_start( app.sip_endpt, &addr, 
331                                             (app.local_addr.slen ? &addrname:NULL),
332                                             1, &tp);
333         if (status != PJ_SUCCESS) {
334             app_perror(THIS_FILE, "Unable to start UDP transport", status);
335             return status;
336         }
337
338         PJ_LOG(3,(THIS_FILE, "SIP UDP listening on %.*s:%d",
339                   (int)tp->local_name.host.slen, tp->local_name.host.ptr,
340                   tp->local_name.port));
341     }
342
343     /* 
344      * Init transaction layer.
345      * This will create/initialize transaction hash tables etc.
346      */
347     status = pjsip_tsx_layer_init_module(app.sip_endpt);
348     PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
349
350     /*  Initialize UA layer. */
351     status = pjsip_ua_init_module( app.sip_endpt, NULL );
352     PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
353
354     /* Initialize 100rel support */
355     status = pjsip_100rel_init_module(app.sip_endpt);
356     PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
357
358     /*  Init invite session module. */
359     {
360         pjsip_inv_callback inv_cb;
361
362         /* Init the callback for INVITE session: */
363         pj_bzero(&inv_cb, sizeof(inv_cb));
364         inv_cb.on_state_changed = &call_on_state_changed;
365         inv_cb.on_new_session = &call_on_forked;
366         inv_cb.on_media_update = &call_on_media_update;
367
368         /* Initialize invite session module:  */
369         status = pjsip_inv_usage_init(app.sip_endpt, &inv_cb);
370         PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
371     }
372
373     /* Register our module to receive incoming requests. */
374     status = pjsip_endpt_register_module( app.sip_endpt, &mod_siprtp);
375     PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
376
377     /* Init calls */
378     for (i=0; i<app.max_calls; ++i)
379         app.call[i].index = i;
380
381     /* Done */
382     return PJ_SUCCESS;
383 }
384
385
386 /*
387  * Destroy SIP
388  */
389 static void destroy_sip()
390 {
391     unsigned i;
392
393     app.thread_quit = 1;
394     for (i=0; i<app.thread_count; ++i) {
395         if (app.sip_thread[i]) {
396             pj_thread_join(app.sip_thread[i]);
397             pj_thread_destroy(app.sip_thread[i]);
398             app.sip_thread[i] = NULL;
399         }
400     }
401
402     if (app.sip_endpt) {
403         pjsip_endpt_destroy(app.sip_endpt);
404         app.sip_endpt = NULL;
405     }
406
407 }
408
409
410 /*
411  * Init media stack.
412  */
413 static pj_status_t init_media()
414 {
415     unsigned    i, count;
416     pj_uint16_t rtp_port;
417     pj_status_t status;
418
419
420     /* Initialize media endpoint so that at least error subsystem is properly
421      * initialized.
422      */
423 #if PJ_HAS_THREADS
424     status = pjmedia_endpt_create(&app.cp.factory, NULL, 1, &app.med_endpt);
425 #else
426     status = pjmedia_endpt_create(&app.cp.factory, 
427                                   pjsip_endpt_get_ioqueue(app.sip_endpt),
428                                   0, &app.med_endpt);
429 #endif
430     PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
431
432
433     /* Must register codecs to be supported */
434 #if defined(PJMEDIA_HAS_G711_CODEC) && PJMEDIA_HAS_G711_CODEC!=0
435     pjmedia_codec_g711_init(app.med_endpt);
436 #endif
437
438     /* RTP port counter */
439     rtp_port = (pj_uint16_t)(app.rtp_start_port & 0xFFFE);
440
441     /* Init media transport for all calls. */
442     for (i=0, count=0; i<app.max_calls; ++i, ++count) {
443
444         unsigned j;
445
446         /* Create transport for each media in the call */
447         for (j=0; j<PJ_ARRAY_SIZE(app.call[0].media); ++j) {
448             /* Repeat binding media socket to next port when fails to bind
449              * to current port number.
450              */
451             int retry;
452
453             app.call[i].media[j].call_index = i;
454             app.call[i].media[j].media_index = j;
455
456             status = -1;
457             for (retry=0; retry<100; ++retry,rtp_port+=2)  {
458                 struct media_stream *m = &app.call[i].media[j];
459                 
460                 status = pjmedia_transport_udp_create2(app.med_endpt, 
461                                                        "siprtp",
462                                                        &app.local_addr,
463                                                        rtp_port, 0, 
464                                                        &m->transport);
465                 if (status == PJ_SUCCESS) {
466                     rtp_port += 2;
467                     break;
468                 }
469             }
470         }
471
472         if (status != PJ_SUCCESS)
473             goto on_error;
474     }
475
476     /* Done */
477     return PJ_SUCCESS;
478
479 on_error:
480     destroy_media();
481     return status;
482 }
483
484
485 /*
486  * Destroy media.
487  */
488 static void destroy_media()
489 {
490     unsigned i;
491
492     for (i=0; i<app.max_calls; ++i) {
493         unsigned j;
494         for (j=0; j<PJ_ARRAY_SIZE(app.call[0].media); ++j) {
495             struct media_stream *m = &app.call[i].media[j];
496
497             if (m->transport) {
498                 pjmedia_transport_close(m->transport);
499                 m->transport = NULL;
500             }
501         }
502     }
503
504     if (app.med_endpt) {
505         pjmedia_endpt_destroy(app.med_endpt);
506         app.med_endpt = NULL;
507     }
508 }
509
510
511 /*
512  * Make outgoing call.
513  */
514 static pj_status_t make_call(const pj_str_t *dst_uri)
515 {
516     unsigned i;
517     struct call *call;
518     pjsip_dialog *dlg;
519     pjmedia_sdp_session *sdp;
520     pjsip_tx_data *tdata;
521     pj_status_t status;
522
523
524     /* Find unused call slot */
525     for (i=0; i<app.max_calls; ++i) {
526         if (app.call[i].inv == NULL)
527             break;
528     }
529
530     if (i == app.max_calls)
531         return PJ_ETOOMANY;
532
533     call = &app.call[i];
534
535     /* Create UAC dialog */
536     status = pjsip_dlg_create_uac( pjsip_ua_instance(), 
537                                    &app.local_uri,      /* local URI        */
538                                    &app.local_contact,  /* local Contact    */
539                                    dst_uri,             /* remote URI       */
540                                    dst_uri,             /* remote target    */
541                                    &dlg);               /* dialog           */
542     if (status != PJ_SUCCESS) {
543         ++app.uac_calls;
544         return status;
545     }
546
547     /* Create SDP */
548     create_sdp( dlg->pool, call, &sdp);
549
550     /* Create the INVITE session. */
551     status = pjsip_inv_create_uac( dlg, sdp, 0, &call->inv);
552     if (status != PJ_SUCCESS) {
553         pjsip_dlg_terminate(dlg);
554         ++app.uac_calls;
555         return status;
556     }
557
558
559     /* Attach call data to invite session */
560     call->inv->mod_data[mod_siprtp.id] = call;
561
562     /* Mark start of call */
563     pj_gettimeofday(&call->start_time);
564
565
566     /* Create initial INVITE request.
567      * This INVITE request will contain a perfectly good request and 
568      * an SDP body as well.
569      */
570     status = pjsip_inv_invite(call->inv, &tdata);
571     PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
572
573
574     /* Send initial INVITE request. 
575      * From now on, the invite session's state will be reported to us
576      * via the invite session callbacks.
577      */
578     status = pjsip_inv_send_msg(call->inv, tdata);
579     PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
580
581
582     return PJ_SUCCESS;
583 }
584
585
586 /*
587  * Receive incoming call
588  */
589 static void process_incoming_call(pjsip_rx_data *rdata)
590 {
591     unsigned i, options;
592     struct call *call;
593     pjsip_dialog *dlg;
594     pjmedia_sdp_session *sdp;
595     pjsip_tx_data *tdata;
596     pj_status_t status;
597
598     /* Find free call slot */
599     for (i=0; i<app.max_calls; ++i) {
600         if (app.call[i].inv == NULL)
601             break;
602     }
603
604     if (i == app.max_calls) {
605         const pj_str_t reason = pj_str("Too many calls");
606         pjsip_endpt_respond_stateless( app.sip_endpt, rdata, 
607                                        500, &reason,
608                                        NULL, NULL);
609         return;
610     }
611
612     call = &app.call[i];
613
614     /* Verify that we can handle the request. */
615     options = 0;
616     status = pjsip_inv_verify_request(rdata, &options, NULL, NULL,
617                                    app.sip_endpt, &tdata);
618     if (status != PJ_SUCCESS) {
619         /*
620          * No we can't handle the incoming INVITE request.
621          */
622         if (tdata) {
623             pjsip_response_addr res_addr;
624             
625             pjsip_get_response_addr(tdata->pool, rdata, &res_addr);
626             pjsip_endpt_send_response(app.sip_endpt, &res_addr, tdata,
627                 NULL, NULL);
628             
629         } else {
630             
631             /* Respond with 500 (Internal Server Error) */
632             pjsip_endpt_respond_stateless(app.sip_endpt, rdata, 500, NULL,
633                 NULL, NULL);
634         }
635         
636         return;
637     }
638
639     /* Create UAS dialog */
640     status = pjsip_dlg_create_uas( pjsip_ua_instance(), rdata,
641                                    &app.local_contact, &dlg);
642     if (status != PJ_SUCCESS) {
643         const pj_str_t reason = pj_str("Unable to create dialog");
644         pjsip_endpt_respond_stateless( app.sip_endpt, rdata, 
645                                        500, &reason,
646                                        NULL, NULL);
647         return;
648     }
649
650     /* Create SDP */
651     create_sdp( dlg->pool, call, &sdp);
652
653     /* Create UAS invite session */
654     status = pjsip_inv_create_uas( dlg, rdata, sdp, 0, &call->inv);
655     if (status != PJ_SUCCESS) {
656         pjsip_dlg_create_response(dlg, rdata, 500, NULL, &tdata);
657         pjsip_dlg_send_response(dlg, pjsip_rdata_get_tsx(rdata), tdata);
658         return;
659     }
660     
661
662     /* Attach call data to invite session */
663     call->inv->mod_data[mod_siprtp.id] = call;
664
665     /* Mark start of call */
666     pj_gettimeofday(&call->start_time);
667
668
669
670     /* Create 200 response .*/
671     status = pjsip_inv_initial_answer(call->inv, rdata, 200, 
672                                       NULL, NULL, &tdata);
673     if (status != PJ_SUCCESS) {
674         status = pjsip_inv_initial_answer(call->inv, rdata, 
675                                           PJSIP_SC_NOT_ACCEPTABLE,
676                                           NULL, NULL, &tdata);
677         if (status == PJ_SUCCESS)
678             pjsip_inv_send_msg(call->inv, tdata); 
679         else
680             pjsip_inv_terminate(call->inv, 500, PJ_FALSE);
681         return;
682     }
683
684
685     /* Send the 200 response. */  
686     status = pjsip_inv_send_msg(call->inv, tdata); 
687     PJ_ASSERT_ON_FAIL(status == PJ_SUCCESS, return);
688
689
690     /* Done */
691 }
692
693
694 /* Callback to be called when dialog has forked: */
695 static void call_on_forked(pjsip_inv_session *inv, pjsip_event *e)
696 {
697     PJ_UNUSED_ARG(inv);
698     PJ_UNUSED_ARG(e);
699
700     PJ_TODO( HANDLE_FORKING );
701 }
702
703
704 /* Callback to be called to handle incoming requests outside dialogs: */
705 static pj_bool_t on_rx_request( pjsip_rx_data *rdata )
706 {
707     /* Ignore strandled ACKs (must not send respone */
708     if (rdata->msg_info.msg->line.req.method.id == PJSIP_ACK_METHOD)
709         return PJ_FALSE;
710
711     /* Respond (statelessly) any non-INVITE requests with 500  */
712     if (rdata->msg_info.msg->line.req.method.id != PJSIP_INVITE_METHOD) {
713         pj_str_t reason = pj_str("Unsupported Operation");
714         pjsip_endpt_respond_stateless( app.sip_endpt, rdata, 
715                                        500, &reason,
716                                        NULL, NULL);
717         return PJ_TRUE;
718     }
719
720     /* Handle incoming INVITE */
721     process_incoming_call(rdata);
722
723     /* Done */
724     return PJ_TRUE;
725 }
726
727
728 /* Callback timer to disconnect call (limiting call duration) */
729 static void timer_disconnect_call( pj_timer_heap_t *timer_heap,
730                                    struct pj_timer_entry *entry)
731 {
732     struct call *call = entry->user_data;
733
734     PJ_UNUSED_ARG(timer_heap);
735
736     entry->id = 0;
737     hangup_call(call->index);
738 }
739
740
741 /* Callback to be called when invite session's state has changed: */
742 static void call_on_state_changed( pjsip_inv_session *inv, 
743                                    pjsip_event *e)
744 {
745     struct call *call = inv->mod_data[mod_siprtp.id];
746
747     PJ_UNUSED_ARG(e);
748
749     if (!call)
750         return;
751
752     if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
753         
754         pj_time_val null_time = {0, 0};
755
756         if (call->d_timer.id != 0) {
757             pjsip_endpt_cancel_timer(app.sip_endpt, &call->d_timer);
758             call->d_timer.id = 0;
759         }
760
761         PJ_LOG(3,(THIS_FILE, "Call #%d disconnected. Reason=%d (%.*s)",
762                   call->index,
763                   inv->cause,
764                   (int)inv->cause_text.slen,
765                   inv->cause_text.ptr));
766
767         if (app.call_report) {
768             PJ_LOG(3,(THIS_FILE, "Call #%d statistics:", call->index));
769             print_call(call->index);
770         }
771
772
773         call->inv = NULL;
774         inv->mod_data[mod_siprtp.id] = NULL;
775
776         destroy_call_media(call->index);
777
778         call->start_time = null_time;
779         call->response_time = null_time;
780         call->connect_time = null_time;
781
782         ++app.uac_calls;
783
784     } else if (inv->state == PJSIP_INV_STATE_CONFIRMED) {
785
786         pj_time_val t;
787
788         pj_gettimeofday(&call->connect_time);
789         if (call->response_time.sec == 0)
790             call->response_time = call->connect_time;
791
792         t = call->connect_time;
793         PJ_TIME_VAL_SUB(t, call->start_time);
794
795         PJ_LOG(3,(THIS_FILE, "Call #%d connected in %d ms", call->index,
796                   PJ_TIME_VAL_MSEC(t)));
797
798         if (app.duration != 0) {
799             call->d_timer.id = 1;
800             call->d_timer.user_data = call;
801             call->d_timer.cb = &timer_disconnect_call;
802
803             t.sec = app.duration;
804             t.msec = 0;
805
806             pjsip_endpt_schedule_timer(app.sip_endpt, &call->d_timer, &t);
807         }
808
809     } else if ( inv->state == PJSIP_INV_STATE_EARLY ||
810                 inv->state == PJSIP_INV_STATE_CONNECTING) {
811
812         if (call->response_time.sec == 0)
813             pj_gettimeofday(&call->response_time);
814
815     }
816 }
817
818
819 /* Utility */
820 static void app_perror(const char *sender, const char *title, 
821                        pj_status_t status)
822 {
823     char errmsg[PJ_ERR_MSG_SIZE];
824
825     pj_strerror(status, errmsg, sizeof(errmsg));
826     PJ_LOG(3,(sender, "%s: %s [status=%d]", title, errmsg, status));
827 }
828
829
830 /* Worker thread for SIP */
831 static int sip_worker_thread(void *arg)
832 {
833     PJ_UNUSED_ARG(arg);
834
835     while (!app.thread_quit) {
836         pj_time_val timeout = {0, 10};
837         pjsip_endpt_handle_events(app.sip_endpt, &timeout);
838     }
839
840     return 0;
841 }
842
843
844 /* Init application options */
845 static pj_status_t init_options(int argc, char *argv[])
846 {
847     static char ip_addr[32];
848     static char local_uri[64];
849
850     enum { OPT_START,
851            OPT_APP_LOG_LEVEL, OPT_LOG_FILE, 
852            OPT_A_PT, OPT_A_NAME, OPT_A_CLOCK, OPT_A_BITRATE, OPT_A_PTIME,
853            OPT_REPORT_FILE };
854
855     struct pj_getopt_option long_options[] = {
856         { "count",          1, 0, 'c' },
857         { "gap",            1, 0, 'g' },
858         { "call-report",    0, 0, 'R' },
859         { "duration",       1, 0, 'd' },
860         { "auto-quit",      0, 0, 'q' },
861         { "local-port",     1, 0, 'p' },
862         { "rtp-port",       1, 0, 'r' },
863         { "ip-addr",        1, 0, 'i' },
864
865         { "log-level",      1, 0, 'l' },
866         { "app-log-level",  1, 0, OPT_APP_LOG_LEVEL },
867         { "log-file",       1, 0, OPT_LOG_FILE },
868
869         { "report-file",    1, 0, OPT_REPORT_FILE },
870
871         /* Don't support this anymore, see comments in USAGE above.
872         { "a-pt",           1, 0, OPT_A_PT },
873         { "a-name",         1, 0, OPT_A_NAME },
874         { "a-clock",        1, 0, OPT_A_CLOCK },
875         { "a-bitrate",      1, 0, OPT_A_BITRATE },
876         { "a-ptime",        1, 0, OPT_A_PTIME },
877         */
878
879         { NULL, 0, 0, 0 },
880     };
881     int c;
882     int option_index;
883
884     /* Get local IP address for the default IP address */
885     {
886         const pj_str_t *hostname;
887         pj_sockaddr_in tmp_addr;
888         char *addr;
889
890         hostname = pj_gethostname();
891         pj_sockaddr_in_init(&tmp_addr, hostname, 0);
892         addr = pj_inet_ntoa(tmp_addr.sin_addr);
893         pj_ansi_strcpy(ip_addr, addr);
894     }
895
896     /* Init defaults */
897     app.max_calls = 1;
898     app.thread_count = 1;
899     app.sip_port = 5060;
900     app.rtp_start_port = RTP_START_PORT;
901     app.local_addr = pj_str(ip_addr);
902     app.log_level = 5;
903     app.app_log_level = 3;
904     app.log_filename = NULL;
905
906     /* Default codecs: */
907     app.audio_codec = audio_codecs[0];
908
909     /* Parse options */
910     pj_optind = 0;
911     while((c=pj_getopt_long(argc,argv, "c:d:p:r:i:l:g:qR", 
912                             long_options, &option_index))!=-1) 
913     {
914         switch (c) {
915         case 'c':
916             app.max_calls = atoi(pj_optarg);
917             if (app.max_calls < 0 || app.max_calls > MAX_CALLS) {
918                 PJ_LOG(3,(THIS_FILE, "Invalid max calls value %s", pj_optarg));
919                 return 1;
920             }
921             break;
922         case 'g':
923             app.call_gap = atoi(pj_optarg);
924             break;
925         case 'R':
926             app.call_report = PJ_TRUE;
927             break;
928         case 'd':
929             app.duration = atoi(pj_optarg);
930             break;
931         case 'q':
932             app.auto_quit = 1;
933             break;
934
935         case 'p':
936             app.sip_port = atoi(pj_optarg);
937             break;
938         case 'r':
939             app.rtp_start_port = atoi(pj_optarg);
940             break;
941         case 'i':
942             app.local_addr = pj_str(pj_optarg);
943             break;
944
945         case 'l':
946             app.log_level = atoi(pj_optarg);
947             break;
948         case OPT_APP_LOG_LEVEL:
949             app.app_log_level = atoi(pj_optarg);
950             break;
951         case OPT_LOG_FILE:
952             app.log_filename = pj_optarg;
953             break;
954
955         case OPT_A_PT:
956             app.audio_codec.pt = atoi(pj_optarg);
957             break;
958         case OPT_A_NAME:
959             app.audio_codec.name = pj_optarg;
960             break;
961         case OPT_A_CLOCK:
962             app.audio_codec.clock_rate = atoi(pj_optarg);
963             break;
964         case OPT_A_BITRATE:
965             app.audio_codec.bit_rate = atoi(pj_optarg);
966             break;
967         case OPT_A_PTIME:
968             app.audio_codec.ptime = atoi(pj_optarg);
969             break;
970         case OPT_REPORT_FILE:
971             app.report_filename = pj_optarg;
972             break;
973
974         default:
975             puts(USAGE);
976             return 1;
977         }
978     }
979
980     /* Check if URL is specified */
981     if (pj_optind < argc)
982         app.uri_to_call = pj_str(argv[pj_optind]);
983
984     /* Build local URI and contact */
985     pj_ansi_sprintf( local_uri, "sip:%s:%d", app.local_addr.ptr, app.sip_port);
986     app.local_uri = pj_str(local_uri);
987     app.local_contact = app.local_uri;
988
989
990     return PJ_SUCCESS;
991 }
992
993
994 /*****************************************************************************
995  * MEDIA STUFFS
996  */
997
998 /*
999  * Create SDP session for a call.
1000  */
1001 static pj_status_t create_sdp( pj_pool_t *pool,
1002                                struct call *call,
1003                                pjmedia_sdp_session **p_sdp)
1004 {
1005     pj_time_val tv;
1006     pjmedia_sdp_session *sdp;
1007     pjmedia_sdp_media *m;
1008     pjmedia_sdp_attr *attr;
1009     pjmedia_transport_info tpinfo;
1010     struct media_stream *audio = &call->media[0];
1011
1012     PJ_ASSERT_RETURN(pool && p_sdp, PJ_EINVAL);
1013
1014
1015     /* Get transport info */
1016     pjmedia_transport_info_init(&tpinfo);
1017     pjmedia_transport_get_info(audio->transport, &tpinfo);
1018
1019     /* Create and initialize basic SDP session */
1020     sdp = pj_pool_zalloc (pool, sizeof(pjmedia_sdp_session));
1021
1022     pj_gettimeofday(&tv);
1023     sdp->origin.user = pj_str("pjsip-siprtp");
1024     sdp->origin.version = sdp->origin.id = tv.sec + 2208988800UL;
1025     sdp->origin.net_type = pj_str("IN");
1026     sdp->origin.addr_type = pj_str("IP4");
1027     sdp->origin.addr = *pj_gethostname();
1028     sdp->name = pj_str("pjsip");
1029
1030     /* Since we only support one media stream at present, put the
1031      * SDP connection line in the session level.
1032      */
1033     sdp->conn = pj_pool_zalloc (pool, sizeof(pjmedia_sdp_conn));
1034     sdp->conn->net_type = pj_str("IN");
1035     sdp->conn->addr_type = pj_str("IP4");
1036     sdp->conn->addr = app.local_addr;
1037
1038
1039     /* SDP time and attributes. */
1040     sdp->time.start = sdp->time.stop = 0;
1041     sdp->attr_count = 0;
1042
1043     /* Create media stream 0: */
1044
1045     sdp->media_count = 1;
1046     m = pj_pool_zalloc (pool, sizeof(pjmedia_sdp_media));
1047     sdp->media[0] = m;
1048
1049     /* Standard media info: */
1050     m->desc.media = pj_str("audio");
1051     m->desc.port = pj_ntohs(tpinfo.sock_info.rtp_addr_name.ipv4.sin_port);
1052     m->desc.port_count = 1;
1053     m->desc.transport = pj_str("RTP/AVP");
1054
1055     /* Add format and rtpmap for each codec. */
1056     m->desc.fmt_count = 1;
1057     m->attr_count = 0;
1058
1059     {
1060         pjmedia_sdp_rtpmap rtpmap;
1061         pjmedia_sdp_attr *attr;
1062         char ptstr[10];
1063
1064         sprintf(ptstr, "%d", app.audio_codec.pt);
1065         pj_strdup2(pool, &m->desc.fmt[0], ptstr);
1066         rtpmap.pt = m->desc.fmt[0];
1067         rtpmap.clock_rate = app.audio_codec.clock_rate;
1068         rtpmap.enc_name = pj_str(app.audio_codec.name);
1069         rtpmap.param.slen = 0;
1070
1071         pjmedia_sdp_rtpmap_to_attr(pool, &rtpmap, &attr);
1072         m->attr[m->attr_count++] = attr;
1073     }
1074
1075     /* Add sendrecv attribute. */
1076     attr = pj_pool_zalloc(pool, sizeof(pjmedia_sdp_attr));
1077     attr->name = pj_str("sendrecv");
1078     m->attr[m->attr_count++] = attr;
1079
1080 #if 1
1081     /*
1082      * Add support telephony event
1083      */
1084     m->desc.fmt[m->desc.fmt_count++] = pj_str("121");
1085     /* Add rtpmap. */
1086     attr = pj_pool_zalloc(pool, sizeof(pjmedia_sdp_attr));
1087     attr->name = pj_str("rtpmap");
1088     attr->value = pj_str("121 telephone-event/8000");
1089     m->attr[m->attr_count++] = attr;
1090     /* Add fmtp */
1091     attr = pj_pool_zalloc(pool, sizeof(pjmedia_sdp_attr));
1092     attr->name = pj_str("fmtp");
1093     attr->value = pj_str("121 0-15");
1094     m->attr[m->attr_count++] = attr;
1095 #endif
1096
1097     /* Done */
1098     *p_sdp = sdp;
1099
1100     return PJ_SUCCESS;
1101 }
1102
1103
1104 #if defined(PJ_WIN32) && PJ_WIN32 != 0
1105 #include <windows.h>
1106 static void boost_priority(void)
1107 {
1108     SetPriorityClass( GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
1109     SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
1110 }
1111
1112 #elif defined(PJ_LINUX) && PJ_LINUX != 0
1113 #include <pthread.h>
1114 static void boost_priority(void)
1115 {
1116 #define POLICY  SCHED_FIFO
1117     struct sched_param tp;
1118     int max_prio;
1119     int policy;
1120     int rc;
1121
1122     if (sched_get_priority_min(POLICY) < sched_get_priority_max(POLICY))
1123         max_prio = sched_get_priority_max(POLICY)-1;
1124     else
1125         max_prio = sched_get_priority_max(POLICY)+1;
1126
1127     /*
1128      * Adjust process scheduling algorithm and priority
1129      */
1130     rc = sched_getparam(0, &tp);
1131     if (rc != 0) {
1132         app_perror( THIS_FILE, "sched_getparam error",
1133                     PJ_RETURN_OS_ERROR(rc));
1134         return;
1135     }
1136     tp.__sched_priority = max_prio;
1137
1138     rc = sched_setscheduler(0, POLICY, &tp);
1139     if (rc != 0) {
1140         app_perror( THIS_FILE, "sched_setscheduler error",
1141                     PJ_RETURN_OS_ERROR(rc));
1142     }
1143
1144     PJ_LOG(4, (THIS_FILE, "New process policy=%d, priority=%d",
1145               policy, tp.__sched_priority));
1146
1147     /*
1148      * Adjust thread scheduling algorithm and priority
1149      */
1150     rc = pthread_getschedparam(pthread_self(), &policy, &tp);
1151     if (rc != 0) {
1152         app_perror( THIS_FILE, "pthread_getschedparam error",
1153                     PJ_RETURN_OS_ERROR(rc));
1154         return;
1155     }
1156
1157     PJ_LOG(4, (THIS_FILE, "Old thread policy=%d, priority=%d",
1158               policy, tp.__sched_priority));
1159
1160     policy = POLICY;
1161     tp.__sched_priority = max_prio;
1162
1163     rc = pthread_setschedparam(pthread_self(), policy, &tp);
1164     if (rc != 0) {
1165         app_perror( THIS_FILE, "pthread_setschedparam error",
1166                     PJ_RETURN_OS_ERROR(rc));
1167         return;
1168     }
1169
1170     PJ_LOG(4, (THIS_FILE, "New thread policy=%d, priority=%d",
1171               policy, tp.__sched_priority));
1172 }
1173
1174 #else
1175 #  define boost_priority()
1176 #endif
1177
1178
1179 /*
1180  * This callback is called by media transport on receipt of RTP packet.
1181  */
1182 static void on_rx_rtp(void *user_data, void *pkt, pj_ssize_t size)
1183 {
1184     struct media_stream *strm;
1185     pj_status_t status;
1186     const pjmedia_rtp_hdr *hdr;
1187     const void *payload;
1188     unsigned payload_len;
1189
1190     strm = user_data;
1191
1192     /* Discard packet if media is inactive */
1193     if (!strm->active)
1194         return;
1195
1196     /* Check for errors */
1197     if (size < 0) {
1198         app_perror(THIS_FILE, "RTP recv() error", -size);
1199         return;
1200     }
1201
1202     /* Decode RTP packet. */
1203     status = pjmedia_rtp_decode_rtp(&strm->in_sess, 
1204                                     pkt, size, 
1205                                     &hdr, &payload, &payload_len);
1206     if (status != PJ_SUCCESS) {
1207         app_perror(THIS_FILE, "RTP decode error", status);
1208         return;
1209     }
1210
1211     //PJ_LOG(4,(THIS_FILE, "Rx seq=%d", pj_ntohs(hdr->seq)));
1212
1213     /* Update the RTCP session. */
1214     pjmedia_rtcp_rx_rtp(&strm->rtcp, pj_ntohs(hdr->seq),
1215                         pj_ntohl(hdr->ts), payload_len);
1216
1217     /* Update RTP session */
1218     pjmedia_rtp_session_update(&strm->in_sess, hdr, NULL);
1219
1220 }
1221
1222 /*
1223  * This callback is called by media transport on receipt of RTCP packet.
1224  */
1225 static void on_rx_rtcp(void *user_data, void *pkt, pj_ssize_t size)
1226 {
1227     struct media_stream *strm;
1228
1229     strm = user_data;
1230
1231     /* Discard packet if media is inactive */
1232     if (!strm->active)
1233         return;
1234
1235     /* Check for errors */
1236     if (size < 0) {
1237         app_perror(THIS_FILE, "Error receiving RTCP packet", -size);
1238         return;
1239     }
1240
1241     /* Update RTCP session */
1242     pjmedia_rtcp_rx_rtcp(&strm->rtcp, pkt, size);
1243 }
1244
1245
1246 /* 
1247  * Media thread 
1248  *
1249  * This is the thread to send and receive both RTP and RTCP packets.
1250  */
1251 static int media_thread(void *arg)
1252 {
1253     enum { RTCP_INTERVAL = 5000, RTCP_RAND = 2000 };
1254     struct media_stream *strm = arg;
1255     char packet[1500];
1256     unsigned msec_interval;
1257     pj_timestamp freq, next_rtp, next_rtcp;
1258
1259
1260     /* Boost thread priority if necessary */
1261     boost_priority();
1262
1263     /* Let things settle */
1264     pj_thread_sleep(100);
1265
1266     msec_interval = strm->samples_per_frame * 1000 / strm->clock_rate;
1267     pj_get_timestamp_freq(&freq);
1268
1269     pj_get_timestamp(&next_rtp);
1270     next_rtp.u64 += (freq.u64 * msec_interval / 1000);
1271
1272     next_rtcp = next_rtp;
1273     next_rtcp.u64 += (freq.u64 * (RTCP_INTERVAL+(pj_rand()%RTCP_RAND)) / 1000);
1274
1275
1276     while (!strm->thread_quit_flag) {
1277         pj_timestamp now, lesser;
1278         pj_time_val timeout;
1279         pj_bool_t send_rtp, send_rtcp;
1280
1281         send_rtp = send_rtcp = PJ_FALSE;
1282
1283         /* Determine how long to sleep */
1284         if (next_rtp.u64 < next_rtcp.u64) {
1285             lesser = next_rtp;
1286             send_rtp = PJ_TRUE;
1287         } else {
1288             lesser = next_rtcp;
1289             send_rtcp = PJ_TRUE;
1290         }
1291
1292         pj_get_timestamp(&now);
1293         if (lesser.u64 <= now.u64) {
1294             timeout.sec = timeout.msec = 0;
1295             //printf("immediate "); fflush(stdout);
1296         } else {
1297             pj_uint64_t tick_delay;
1298             tick_delay = lesser.u64 - now.u64;
1299             timeout.sec = 0;
1300             timeout.msec = (pj_uint32_t)(tick_delay * 1000 / freq.u64);
1301             pj_time_val_normalize(&timeout);
1302
1303             //printf("%d:%03d ", timeout.sec, timeout.msec); fflush(stdout);
1304         }
1305
1306         /* Wait for next interval */
1307         //if (timeout.sec!=0 && timeout.msec!=0) {
1308             pj_thread_sleep(PJ_TIME_VAL_MSEC(timeout));
1309             if (strm->thread_quit_flag)
1310                 break;
1311         //}
1312
1313         pj_get_timestamp(&now);
1314
1315         if (send_rtp || next_rtp.u64 <= now.u64) {
1316             /*
1317              * Time to send RTP packet.
1318              */
1319             pj_status_t status;
1320             const void *p_hdr;
1321             const pjmedia_rtp_hdr *hdr;
1322             pj_ssize_t size;
1323             int hdrlen;
1324
1325             /* Format RTP header */
1326             status = pjmedia_rtp_encode_rtp( &strm->out_sess, strm->si.tx_pt,
1327                                              0, /* marker bit */
1328                                              strm->bytes_per_frame, 
1329                                              strm->samples_per_frame,
1330                                              &p_hdr, &hdrlen);
1331             if (status == PJ_SUCCESS) {
1332
1333                 //PJ_LOG(4,(THIS_FILE, "\t\tTx seq=%d", pj_ntohs(hdr->seq)));
1334                 
1335                 hdr = (const pjmedia_rtp_hdr*) p_hdr;
1336
1337                 /* Copy RTP header to packet */
1338                 pj_memcpy(packet, hdr, hdrlen);
1339
1340                 /* Zero the payload */
1341                 pj_bzero(packet+hdrlen, strm->bytes_per_frame);
1342
1343                 /* Send RTP packet */
1344                 size = hdrlen + strm->bytes_per_frame;
1345                 status = pjmedia_transport_send_rtp(strm->transport, 
1346                                                     packet, size);
1347                 if (status != PJ_SUCCESS)
1348                     app_perror(THIS_FILE, "Error sending RTP packet", status);
1349
1350             } else {
1351                 pj_assert(!"RTP encode() error");
1352             }
1353
1354             /* Update RTCP SR */
1355             pjmedia_rtcp_tx_rtp( &strm->rtcp, (pj_uint16_t)strm->bytes_per_frame);
1356
1357             /* Schedule next send */
1358             next_rtp.u64 += (msec_interval * freq.u64 / 1000);
1359         }
1360
1361
1362         if (send_rtcp || next_rtcp.u64 <= now.u64) {
1363             /*
1364              * Time to send RTCP packet.
1365              */
1366             void *rtcp_pkt;
1367             int rtcp_len;
1368             pj_ssize_t size;
1369             pj_status_t status;
1370
1371             /* Build RTCP packet */
1372             pjmedia_rtcp_build_rtcp(&strm->rtcp, &rtcp_pkt, &rtcp_len);
1373
1374     
1375             /* Send packet */
1376             size = rtcp_len;
1377             status = pjmedia_transport_send_rtcp(strm->transport,
1378                                                  rtcp_pkt, size);
1379             if (status != PJ_SUCCESS) {
1380                 app_perror(THIS_FILE, "Error sending RTCP packet", status);
1381             }
1382             
1383             /* Schedule next send */
1384             next_rtcp.u64 += (freq.u64 * (RTCP_INTERVAL+(pj_rand()%RTCP_RAND)) /
1385                               1000);
1386         }
1387     }
1388
1389     return 0;
1390 }
1391
1392
1393 /* Callback to be called when SDP negotiation is done in the call: */
1394 static void call_on_media_update( pjsip_inv_session *inv,
1395                                   pj_status_t status)
1396 {
1397     struct call *call;
1398     pj_pool_t *pool;
1399     struct media_stream *audio;
1400     const pjmedia_sdp_session *local_sdp, *remote_sdp;
1401     struct codec *codec_desc = NULL;
1402     unsigned i;
1403
1404     call = inv->mod_data[mod_siprtp.id];
1405     pool = inv->dlg->pool;
1406     audio = &call->media[0];
1407
1408     /* If this is a mid-call media update, then destroy existing media */
1409     if (audio->thread != NULL)
1410         destroy_call_media(call->index);
1411
1412
1413     /* Do nothing if media negotiation has failed */
1414     if (status != PJ_SUCCESS) {
1415         app_perror(THIS_FILE, "SDP negotiation failed", status);
1416         return;
1417     }
1418
1419     
1420     /* Capture stream definition from the SDP */
1421     pjmedia_sdp_neg_get_active_local(inv->neg, &local_sdp);
1422     pjmedia_sdp_neg_get_active_remote(inv->neg, &remote_sdp);
1423
1424     status = pjmedia_stream_info_from_sdp(&audio->si, inv->pool, app.med_endpt,
1425                                           local_sdp, remote_sdp, 0);
1426     if (status != PJ_SUCCESS) {
1427         app_perror(THIS_FILE, "Error creating stream info from SDP", status);
1428         return;
1429     }
1430
1431     /* Get the remainder of codec information from codec descriptor */
1432     if (audio->si.fmt.pt == app.audio_codec.pt)
1433         codec_desc = &app.audio_codec;
1434     else {
1435         /* Find the codec description in codec array */
1436         for (i=0; i<PJ_ARRAY_SIZE(audio_codecs); ++i) {
1437             if (audio_codecs[i].pt == audio->si.fmt.pt) {
1438                 codec_desc = &audio_codecs[i];
1439                 break;
1440             }
1441         }
1442
1443         if (codec_desc == NULL) {
1444             PJ_LOG(3, (THIS_FILE, "Error: Invalid codec payload type"));
1445             return;
1446         }
1447     }
1448
1449     audio->clock_rate = audio->si.fmt.clock_rate;
1450     audio->samples_per_frame = audio->clock_rate * codec_desc->ptime / 1000;
1451     audio->bytes_per_frame = codec_desc->bit_rate * codec_desc->ptime / 1000 / 8;
1452
1453
1454     pjmedia_rtp_session_init(&audio->out_sess, audio->si.tx_pt, 
1455                              pj_rand());
1456     pjmedia_rtp_session_init(&audio->in_sess, audio->si.fmt.pt, 0);
1457     pjmedia_rtcp_init(&audio->rtcp, "rtcp", audio->clock_rate, 
1458                       audio->samples_per_frame, 0);
1459
1460
1461     /* Attach media to transport */
1462     status = pjmedia_transport_attach(audio->transport, audio, 
1463                                       &audio->si.rem_addr, 
1464                                       &audio->si.rem_rtcp, 
1465                                       sizeof(pj_sockaddr_in),
1466                                       &on_rx_rtp,
1467                                       &on_rx_rtcp);
1468     if (status != PJ_SUCCESS) {
1469         app_perror(THIS_FILE, "Error on pjmedia_transport_attach()", status);
1470         return;
1471     }
1472
1473     /* Start media thread. */
1474     audio->thread_quit_flag = 0;
1475 #if PJ_HAS_THREADS
1476     status = pj_thread_create( inv->pool, "media", &media_thread, audio,
1477                                0, 0, &audio->thread);
1478     if (status != PJ_SUCCESS) {
1479         app_perror(THIS_FILE, "Error creating media thread", status);
1480         return;
1481     }
1482 #endif
1483
1484     /* Set the media as active */
1485     audio->active = PJ_TRUE;
1486 }
1487
1488
1489
1490 /* Destroy call's media */
1491 static void destroy_call_media(unsigned call_index)
1492 {
1493     struct media_stream *audio = &app.call[call_index].media[0];
1494
1495     if (audio) {
1496         audio->active = PJ_FALSE;
1497
1498         if (audio->thread) {
1499             audio->thread_quit_flag = 1;
1500             pj_thread_join(audio->thread);
1501             pj_thread_destroy(audio->thread);
1502             audio->thread = NULL;
1503             audio->thread_quit_flag = 0;
1504         }
1505
1506         pjmedia_transport_detach(audio->transport, audio);
1507     }
1508 }
1509
1510  
1511 /*****************************************************************************
1512  * USER INTERFACE STUFFS
1513  */
1514
1515 static void call_get_duration(int call_index, pj_time_val *dur)
1516 {
1517     struct call *call = &app.call[call_index];
1518     pjsip_inv_session *inv;
1519
1520     dur->sec = dur->msec = 0;
1521
1522     if (!call)
1523         return;
1524
1525     inv = call->inv;
1526     if (!inv)
1527         return;
1528
1529     if (inv->state >= PJSIP_INV_STATE_CONFIRMED && call->connect_time.sec) {
1530
1531         pj_gettimeofday(dur);
1532         PJ_TIME_VAL_SUB((*dur), call->connect_time);
1533     }
1534 }
1535
1536
1537 static const char *good_number(char *buf, pj_int32_t val)
1538 {
1539     if (val < 1000) {
1540         pj_ansi_sprintf(buf, "%d", val);
1541     } else if (val < 1000000) {
1542         pj_ansi_sprintf(buf, "%d.%02dK", 
1543                         val / 1000,
1544                         (val % 1000) / 100);
1545     } else {
1546         pj_ansi_sprintf(buf, "%d.%02dM", 
1547                         val / 1000000,
1548                         (val % 1000000) / 10000);
1549     }
1550
1551     return buf;
1552 }
1553
1554
1555
1556 static void print_avg_stat(void)
1557 {
1558 #define MIN_(var,val)      if ((int)val < (int)var) var = val
1559 #define MAX_(var,val)      if ((int)val > (int)var) var = val
1560 #define AVG_(var,val)      var = ( ((var * count) + val) / (count+1) )
1561 #define BIGVAL              0x7FFFFFFFL
1562     struct stat_entry
1563     {
1564         int min, avg, max;
1565     };
1566
1567     struct stat_entry call_dur, call_pdd;
1568     pjmedia_rtcp_stat min_stat, avg_stat, max_stat;
1569
1570     char srx_min[16], srx_avg[16], srx_max[16];
1571     char brx_min[16], brx_avg[16], brx_max[16];
1572     char stx_min[16], stx_avg[16], stx_max[16];
1573     char btx_min[16], btx_avg[16], btx_max[16];
1574
1575
1576     unsigned i, count;
1577
1578     pj_bzero(&call_dur, sizeof(call_dur)); 
1579     call_dur.min = BIGVAL;
1580
1581     pj_bzero(&call_pdd, sizeof(call_pdd)); 
1582     call_pdd.min = BIGVAL;
1583
1584     pj_bzero(&min_stat, sizeof(min_stat));
1585     min_stat.rx.pkt = min_stat.tx.pkt = BIGVAL;
1586     min_stat.rx.bytes = min_stat.tx.bytes = BIGVAL;
1587     min_stat.rx.loss = min_stat.tx.loss = BIGVAL;
1588     min_stat.rx.dup = min_stat.tx.dup = BIGVAL;
1589     min_stat.rx.reorder = min_stat.tx.reorder = BIGVAL;
1590     min_stat.rx.jitter.min = min_stat.tx.jitter.min = BIGVAL;
1591     min_stat.rtt.min = BIGVAL;
1592
1593     pj_bzero(&avg_stat, sizeof(avg_stat));
1594     pj_bzero(&max_stat, sizeof(max_stat));
1595
1596
1597     for (i=0, count=0; i<app.max_calls; ++i) {
1598
1599         struct call *call = &app.call[i];
1600         struct media_stream *audio = &call->media[0];
1601         pj_time_val dur;
1602         unsigned msec_dur;
1603
1604         if (call->inv == NULL || 
1605             call->inv->state < PJSIP_INV_STATE_CONFIRMED ||
1606             call->connect_time.sec == 0) 
1607         {
1608             continue;
1609         }
1610
1611         /* Duration */
1612         call_get_duration(i, &dur);
1613         msec_dur = PJ_TIME_VAL_MSEC(dur);
1614
1615         MIN_(call_dur.min, msec_dur);
1616         MAX_(call_dur.max, msec_dur);
1617         AVG_(call_dur.avg, msec_dur);
1618
1619         /* Connect delay */
1620         if (call->connect_time.sec) {
1621             pj_time_val t = call->connect_time;
1622             PJ_TIME_VAL_SUB(t, call->start_time);
1623             msec_dur = PJ_TIME_VAL_MSEC(t);
1624         } else {
1625             msec_dur = 10;
1626         }
1627
1628         MIN_(call_pdd.min, msec_dur);
1629         MAX_(call_pdd.max, msec_dur);
1630         AVG_(call_pdd.avg, msec_dur);
1631
1632         /* RX Statistisc: */
1633
1634         /* Packets */
1635         MIN_(min_stat.rx.pkt, audio->rtcp.stat.rx.pkt);
1636         MAX_(max_stat.rx.pkt, audio->rtcp.stat.rx.pkt);
1637         AVG_(avg_stat.rx.pkt, audio->rtcp.stat.rx.pkt);
1638
1639         /* Bytes */
1640         MIN_(min_stat.rx.bytes, audio->rtcp.stat.rx.bytes);
1641         MAX_(max_stat.rx.bytes, audio->rtcp.stat.rx.bytes);
1642         AVG_(avg_stat.rx.bytes, audio->rtcp.stat.rx.bytes);
1643
1644
1645         /* Packet loss */
1646         MIN_(min_stat.rx.loss, audio->rtcp.stat.rx.loss);
1647         MAX_(max_stat.rx.loss, audio->rtcp.stat.rx.loss);
1648         AVG_(avg_stat.rx.loss, audio->rtcp.stat.rx.loss);
1649
1650         /* Packet dup */
1651         MIN_(min_stat.rx.dup, audio->rtcp.stat.rx.dup);
1652         MAX_(max_stat.rx.dup, audio->rtcp.stat.rx.dup);
1653         AVG_(avg_stat.rx.dup, audio->rtcp.stat.rx.dup);
1654
1655         /* Packet reorder */
1656         MIN_(min_stat.rx.reorder, audio->rtcp.stat.rx.reorder);
1657         MAX_(max_stat.rx.reorder, audio->rtcp.stat.rx.reorder);
1658         AVG_(avg_stat.rx.reorder, audio->rtcp.stat.rx.reorder);
1659
1660         /* Jitter  */
1661         MIN_(min_stat.rx.jitter.min, audio->rtcp.stat.rx.jitter.min);
1662         MAX_(max_stat.rx.jitter.max, audio->rtcp.stat.rx.jitter.max);
1663         AVG_(avg_stat.rx.jitter.mean, audio->rtcp.stat.rx.jitter.mean);
1664
1665
1666         /* TX Statistisc: */
1667
1668         /* Packets */
1669         MIN_(min_stat.tx.pkt, audio->rtcp.stat.tx.pkt);
1670         MAX_(max_stat.tx.pkt, audio->rtcp.stat.tx.pkt);
1671         AVG_(avg_stat.tx.pkt, audio->rtcp.stat.tx.pkt);
1672
1673         /* Bytes */
1674         MIN_(min_stat.tx.bytes, audio->rtcp.stat.tx.bytes);
1675         MAX_(max_stat.tx.bytes, audio->rtcp.stat.tx.bytes);
1676         AVG_(avg_stat.tx.bytes, audio->rtcp.stat.tx.bytes);
1677
1678         /* Packet loss */
1679         MIN_(min_stat.tx.loss, audio->rtcp.stat.tx.loss);
1680         MAX_(max_stat.tx.loss, audio->rtcp.stat.tx.loss);
1681         AVG_(avg_stat.tx.loss, audio->rtcp.stat.tx.loss);
1682
1683         /* Packet dup */
1684         MIN_(min_stat.tx.dup, audio->rtcp.stat.tx.dup);
1685         MAX_(max_stat.tx.dup, audio->rtcp.stat.tx.dup);
1686         AVG_(avg_stat.tx.dup, audio->rtcp.stat.tx.dup);
1687
1688         /* Packet reorder */
1689         MIN_(min_stat.tx.reorder, audio->rtcp.stat.tx.reorder);
1690         MAX_(max_stat.tx.reorder, audio->rtcp.stat.tx.reorder);
1691         AVG_(avg_stat.tx.reorder, audio->rtcp.stat.tx.reorder);
1692
1693         /* Jitter  */
1694         MIN_(min_stat.tx.jitter.min, audio->rtcp.stat.tx.jitter.min);
1695         MAX_(max_stat.tx.jitter.max, audio->rtcp.stat.tx.jitter.max);
1696         AVG_(avg_stat.tx.jitter.mean, audio->rtcp.stat.tx.jitter.mean);
1697
1698
1699         /* RTT */
1700         MIN_(min_stat.rtt.min, audio->rtcp.stat.rtt.min);
1701         MAX_(max_stat.rtt.max, audio->rtcp.stat.rtt.max);
1702         AVG_(avg_stat.rtt.mean, audio->rtcp.stat.rtt.mean);
1703
1704         ++count;
1705     }
1706
1707     if (count == 0) {
1708         puts("No active calls");
1709         return;
1710     }
1711
1712     printf("Total %d call(s) active.\n"
1713            "                    Average Statistics\n"
1714            "                    min     avg     max \n"
1715            "                -----------------------\n"
1716            " call duration: %7d %7d %7d %s\n"
1717            " connect delay: %7d %7d %7d %s\n"
1718            " RX stat:\n"
1719            "       packets: %7s %7s %7s %s\n"
1720            "       payload: %7s %7s %7s %s\n"
1721            "          loss: %7d %7d %7d %s\n"
1722            "  percent loss: %7.3f %7.3f %7.3f %s\n"
1723            "           dup: %7d %7d %7d %s\n"
1724            "       reorder: %7d %7d %7d %s\n"
1725            "        jitter: %7.3f %7.3f %7.3f %s\n"
1726            " TX stat:\n"
1727            "       packets: %7s %7s %7s %s\n"
1728            "       payload: %7s %7s %7s %s\n"
1729            "          loss: %7d %7d %7d %s\n"
1730            "  percent loss: %7.3f %7.3f %7.3f %s\n"
1731            "           dup: %7d %7d %7d %s\n"
1732            "       reorder: %7d %7d %7d %s\n"
1733            "        jitter: %7.3f %7.3f %7.3f %s\n"
1734            " RTT          : %7.3f %7.3f %7.3f %s\n"
1735            ,
1736            count,
1737            call_dur.min/1000, call_dur.avg/1000, call_dur.max/1000, 
1738            "seconds",
1739
1740            call_pdd.min, call_pdd.avg, call_pdd.max, 
1741            "ms",
1742
1743            /* rx */
1744
1745            good_number(srx_min, min_stat.rx.pkt),
1746            good_number(srx_avg, avg_stat.rx.pkt),
1747            good_number(srx_max, max_stat.rx.pkt),
1748            "packets",
1749
1750            good_number(brx_min, min_stat.rx.bytes),
1751            good_number(brx_avg, avg_stat.rx.bytes),
1752            good_number(brx_max, max_stat.rx.bytes),
1753            "bytes",
1754
1755            min_stat.rx.loss, avg_stat.rx.loss, max_stat.rx.loss,
1756            "packets",
1757            
1758            min_stat.rx.loss*100.0/(min_stat.rx.pkt+min_stat.rx.loss),
1759            avg_stat.rx.loss*100.0/(avg_stat.rx.pkt+avg_stat.rx.loss),
1760            max_stat.rx.loss*100.0/(max_stat.rx.pkt+max_stat.rx.loss),
1761            "%",
1762
1763
1764            min_stat.rx.dup, avg_stat.rx.dup, max_stat.rx.dup,
1765            "packets",
1766
1767            min_stat.rx.reorder, avg_stat.rx.reorder, max_stat.rx.reorder,
1768            "packets",
1769
1770            min_stat.rx.jitter.min/1000.0, 
1771            avg_stat.rx.jitter.mean/1000.0, 
1772            max_stat.rx.jitter.max/1000.0,
1773            "ms",
1774         
1775            /* tx */
1776
1777            good_number(stx_min, min_stat.tx.pkt),
1778            good_number(stx_avg, avg_stat.tx.pkt),
1779            good_number(stx_max, max_stat.tx.pkt),
1780            "packets",
1781
1782            good_number(btx_min, min_stat.tx.bytes),
1783            good_number(btx_avg, avg_stat.tx.bytes),
1784            good_number(btx_max, max_stat.tx.bytes),
1785            "bytes",
1786
1787            min_stat.tx.loss, avg_stat.tx.loss, max_stat.tx.loss,
1788            "packets",
1789            
1790            min_stat.tx.loss*100.0/(min_stat.tx.pkt+min_stat.tx.loss),
1791            avg_stat.tx.loss*100.0/(avg_stat.tx.pkt+avg_stat.tx.loss),
1792            max_stat.tx.loss*100.0/(max_stat.tx.pkt+max_stat.tx.loss),
1793            "%",
1794
1795            min_stat.tx.dup, avg_stat.tx.dup, max_stat.tx.dup,
1796            "packets",
1797
1798            min_stat.tx.reorder, avg_stat.tx.reorder, max_stat.tx.reorder,
1799            "packets",
1800
1801            min_stat.tx.jitter.min/1000.0, 
1802            avg_stat.tx.jitter.mean/1000.0, 
1803            max_stat.tx.jitter.max/1000.0,
1804            "ms",
1805
1806            /* rtt */
1807            min_stat.rtt.min/1000.0, 
1808            avg_stat.rtt.mean/1000.0, 
1809            max_stat.rtt.max/1000.0,
1810            "ms"
1811            );
1812
1813 }
1814
1815
1816 #include "siprtp_report.c"
1817
1818
1819 static void list_calls()
1820 {
1821     unsigned i;
1822     puts("List all calls:");
1823     for (i=0; i<app.max_calls; ++i) {
1824         if (!app.call[i].inv)
1825             continue;
1826         print_call(i);
1827     }
1828 }
1829
1830 static void hangup_call(unsigned index)
1831 {
1832     pjsip_tx_data *tdata;
1833     pj_status_t status;
1834
1835     if (app.call[index].inv == NULL)
1836         return;
1837
1838     status = pjsip_inv_end_session(app.call[index].inv, 603, NULL, &tdata);
1839     if (status==PJ_SUCCESS && tdata!=NULL)
1840         pjsip_inv_send_msg(app.call[index].inv, tdata);
1841 }
1842
1843 static void hangup_all_calls()
1844 {
1845     unsigned i;
1846     for (i=0; i<app.max_calls; ++i) {
1847         if (!app.call[i].inv)
1848             continue;
1849         hangup_call(i);
1850         pj_thread_sleep(app.call_gap);
1851     }
1852     
1853     /* Wait until all calls are terminated */
1854     for (i=0; i<app.max_calls; ++i) {
1855         while (app.call[i].inv)
1856             pj_thread_sleep(10);
1857     }
1858 }
1859
1860 static pj_bool_t simple_input(const char *title, char *buf, pj_size_t len)
1861 {
1862     char *p;
1863
1864     printf("%s (empty to cancel): ", title); fflush(stdout);
1865     if (fgets(buf, len, stdin) == NULL)
1866         return PJ_FALSE;
1867
1868     /* Remove trailing newlines. */
1869     for (p=buf; ; ++p) {
1870         if (*p=='\r' || *p=='\n') *p='\0';
1871         else if (!*p) break;
1872     }
1873
1874     if (!*buf)
1875         return PJ_FALSE;
1876     
1877     return PJ_TRUE;
1878 }
1879
1880
1881 static const char *MENU =
1882 "\n"
1883 "Enter menu character:\n"
1884 "  s    Summary\n"
1885 "  l    List all calls\n"
1886 "  h    Hangup a call\n"
1887 "  H    Hangup all calls\n"
1888 "  q    Quit\n"
1889 "\n";
1890
1891
1892 /* Main screen menu */
1893 static void console_main()
1894 {
1895     char input1[10];
1896     unsigned i;
1897
1898     printf("%s", MENU);
1899
1900     for (;;) {
1901         printf(">>> "); fflush(stdout);
1902         if (fgets(input1, sizeof(input1), stdin) == NULL) {
1903             puts("EOF while reading stdin, will quit now..");
1904             break;
1905         }
1906
1907         switch (input1[0]) {
1908
1909         case 's':
1910             print_avg_stat();
1911             break;
1912
1913         case 'l':
1914             list_calls();
1915             break;
1916
1917         case 'h':
1918             if (!simple_input("Call number to hangup", input1, sizeof(input1)))
1919                 break;
1920
1921             i = atoi(input1);
1922             hangup_call(i);
1923             break;
1924
1925         case 'H':
1926             hangup_all_calls();
1927             break;
1928
1929         case 'q':
1930             goto on_exit;
1931
1932         default:
1933             puts("Invalid command");
1934             printf("%s", MENU);
1935             break;
1936         }
1937
1938         fflush(stdout);
1939     }
1940
1941 on_exit:
1942     hangup_all_calls();
1943 }
1944
1945
1946 /*****************************************************************************
1947  * Below is a simple module to log all incoming and outgoing SIP messages
1948  */
1949
1950
1951 /* Notification on incoming messages */
1952 static pj_bool_t logger_on_rx_msg(pjsip_rx_data *rdata)
1953 {
1954     PJ_LOG(4,(THIS_FILE, "RX %d bytes %s from %s:%d:\n"
1955                          "%s\n"
1956                          "--end msg--",
1957                          rdata->msg_info.len,
1958                          pjsip_rx_data_get_info(rdata),
1959                          rdata->pkt_info.src_name,
1960                          rdata->pkt_info.src_port,
1961                          rdata->msg_info.msg_buf));
1962     
1963     /* Always return false, otherwise messages will not get processed! */
1964     return PJ_FALSE;
1965 }
1966
1967 /* Notification on outgoing messages */
1968 static pj_status_t logger_on_tx_msg(pjsip_tx_data *tdata)
1969 {
1970     
1971     /* Important note:
1972      *  tp_info field is only valid after outgoing messages has passed
1973      *  transport layer. So don't try to access tp_info when the module
1974      *  has lower priority than transport layer.
1975      */
1976
1977     PJ_LOG(4,(THIS_FILE, "TX %d bytes %s to %s:%d:\n"
1978                          "%s\n"
1979                          "--end msg--",
1980                          (tdata->buf.cur - tdata->buf.start),
1981                          pjsip_tx_data_get_info(tdata),
1982                          tdata->tp_info.dst_name,
1983                          tdata->tp_info.dst_port,
1984                          tdata->buf.start));
1985
1986     /* Always return success, otherwise message will not get sent! */
1987     return PJ_SUCCESS;
1988 }
1989
1990 /* The module instance. */
1991 static pjsip_module msg_logger = 
1992 {
1993     NULL, NULL,                         /* prev, next.          */
1994     { "mod-siprtp-log", 14 },           /* Name.                */
1995     -1,                                 /* Id                   */
1996     PJSIP_MOD_PRIORITY_TRANSPORT_LAYER-1,/* Priority            */
1997     NULL,                               /* load()               */
1998     NULL,                               /* start()              */
1999     NULL,                               /* stop()               */
2000     NULL,                               /* unload()             */
2001     &logger_on_rx_msg,                  /* on_rx_request()      */
2002     &logger_on_rx_msg,                  /* on_rx_response()     */
2003     &logger_on_tx_msg,                  /* on_tx_request.       */
2004     &logger_on_tx_msg,                  /* on_tx_response()     */
2005     NULL,                               /* on_tsx_state()       */
2006
2007 };
2008
2009
2010
2011 /*****************************************************************************
2012  * Console application custom logging:
2013  */
2014
2015
2016 static FILE *log_file;
2017
2018
2019 static void app_log_writer(int level, const char *buffer, int len)
2020 {
2021     /* Write to both stdout and file. */
2022
2023     if (level <= app.app_log_level)
2024         pj_log_write(level, buffer, len);
2025
2026     if (log_file) {
2027         int count = fwrite(buffer, len, 1, log_file);
2028         PJ_UNUSED_ARG(count);
2029         fflush(log_file);
2030     }
2031 }
2032
2033
2034 pj_status_t app_logging_init(void)
2035 {
2036     /* Redirect log function to ours */
2037
2038     pj_log_set_log_func( &app_log_writer );
2039
2040     /* If output log file is desired, create the file: */
2041
2042     if (app.log_filename) {
2043         log_file = fopen(app.log_filename, "wt");
2044         if (log_file == NULL) {
2045             PJ_LOG(1,(THIS_FILE, "Unable to open log file %s", 
2046                       app.log_filename));   
2047             return -1;
2048         }
2049     }
2050
2051     return PJ_SUCCESS;
2052 }
2053
2054
2055 void app_logging_shutdown(void)
2056 {
2057     /* Close logging file, if any: */
2058
2059     if (log_file) {
2060         fclose(log_file);
2061         log_file = NULL;
2062     }
2063 }
2064
2065
2066 /*
2067  * main()
2068  */
2069 int main(int argc, char *argv[])
2070 {
2071     unsigned i;
2072     pj_status_t status;
2073
2074     /* Must init PJLIB first */
2075     status = pj_init();
2076     if (status != PJ_SUCCESS)
2077         return 1;
2078
2079     /* Get command line options */
2080     status = init_options(argc, argv);
2081     if (status != PJ_SUCCESS)
2082         return 1;
2083
2084     /* Verify options: */
2085
2086     /* Auto-quit can not be specified for UAS */
2087     if (app.auto_quit && app.uri_to_call.slen == 0) {
2088         printf("Error: --auto-quit option only valid for outgoing "
2089                "mode (UAC) only\n");
2090         return 1;
2091     }
2092
2093     /* Init logging */
2094     status = app_logging_init();
2095     if (status != PJ_SUCCESS)
2096         return 1;
2097
2098     /* Init SIP etc */
2099     status = init_sip();
2100     if (status != PJ_SUCCESS) {
2101         app_perror(THIS_FILE, "Initialization has failed", status);
2102         destroy_sip();
2103         return 1;
2104     }
2105
2106     /* Register module to log incoming/outgoing messages */
2107     pjsip_endpt_register_module(app.sip_endpt, &msg_logger);
2108
2109     /* Init media */
2110     status = init_media();
2111     if (status != PJ_SUCCESS) {
2112         app_perror(THIS_FILE, "Media initialization failed", status);
2113         destroy_sip();
2114         return 1;
2115     }
2116
2117     /* Start worker threads */
2118 #if PJ_HAS_THREADS
2119     for (i=0; i<app.thread_count; ++i) {
2120         pj_thread_create( app.pool, "app", &sip_worker_thread, NULL,
2121                           0, 0, &app.sip_thread[i]);
2122     }
2123 #endif
2124
2125     /* If URL is specified, then make call immediately */
2126     if (app.uri_to_call.slen) {
2127         unsigned i;
2128
2129         PJ_LOG(3,(THIS_FILE, "Making %d calls to %s..", app.max_calls,
2130                   app.uri_to_call.ptr));
2131
2132         for (i=0; i<app.max_calls; ++i) {
2133             status = make_call(&app.uri_to_call);
2134             if (status != PJ_SUCCESS) {
2135                 app_perror(THIS_FILE, "Error making call", status);
2136                 break;
2137             }
2138             pj_thread_sleep(app.call_gap);
2139         }
2140
2141         if (app.auto_quit) {
2142             /* Wait for calls to complete */
2143             while (app.uac_calls < app.max_calls)
2144                 pj_thread_sleep(100);
2145             pj_thread_sleep(200);
2146         } else {
2147 #if PJ_HAS_THREADS
2148             /* Start user interface loop */
2149             console_main();
2150 #endif
2151         }
2152
2153     } else {
2154
2155         PJ_LOG(3,(THIS_FILE, "Ready for incoming calls (max=%d)", 
2156                   app.max_calls));
2157
2158 #if PJ_HAS_THREADS
2159         /* Start user interface loop */
2160         console_main();
2161 #endif
2162     }
2163
2164 #if !PJ_HAS_THREADS
2165     PJ_LOG(3,(THIS_FILE, "Press Ctrl-C to quit"));
2166     for (;;) {
2167         pj_time_val t = {0, 10};
2168         pjsip_endpt_handle_events(app.sip_endpt, &t);
2169     }
2170 #endif
2171     
2172     /* Shutting down... */
2173     destroy_sip();
2174     destroy_media();
2175
2176     if (app.pool) {
2177         pj_pool_release(app.pool);
2178         app.pool = NULL;
2179         pj_caching_pool_destroy(&app.cp);
2180     }
2181
2182     app_logging_shutdown();
2183
2184     /* Shutdown PJLIB */
2185     pj_shutdown();
2186
2187     return 0;
2188 }
2189