Home --> Documentations --> PJMEDIA Reference
This source is an example to demonstrate using SIP and RTP/RTCP framework to measure the network quality/impairment from the SIP call. This program can be used to make calls or to receive calls from other SIP endpoint (or other siprtp program), and to display the media quality statistics at the end of the call.
Note that the remote peer must support RTCP.
The layout of the program has been designed so that custom reporting can be generated instead of plain human readable text.
The source code of the file is pjsip-apps/src/samples/siprtp.c
Screenshots on WinXP:
25static const char *USAGE =
27" This program establishes SIP INVITE session and media, and calculate \n"
28" the media quality (packet lost, jitter, rtt, etc.). Unlike normal \n"
29" pjmedia applications, this program bypasses all pjmedia stream \n"
30" framework and transmit encoded RTP packets manually using own thread. \n"
33" siprtp [options] => to start in server mode\n"
34" siprtp [options] URL => to start in client mode\n"
37" --count=N, -c Set number of calls to create (default:1) \n"
38" --gap=N -g Set call gapping to N msec (default:0)\n"
39" --duration=SEC, -d Set maximum call duration (default:unlimited) \n"
40" --auto-quit, -q Quit when calls have been completed (default:no)\n"
41" --call-report -R Display report on call termination (default:yes)\n"
43" Address and ports options:\n"
44" --local-port=PORT,-p Set local SIP port (default: 5060)\n"
45" --rtp-port=PORT, -r Set start of RTP port (default: 4000)\n"
46" --ip-addr=IP, -i Set local IP address to use (otherwise it will\n"
47" try to determine local IP address from hostname)\n"
50" --log-level=N, -l Set log verbosity level (default=5)\n"
51" --app-log-level=N Set app screen log verbosity (default=3)\n"
52" --log-file=FILE Write log to file FILE\n"
53" --report-file=FILE Write report to file FILE\n"
73#include <pjsip_simple.h>
74#include <pjlib-util.h>
90#if PJ_HAS_HIGH_RES_TIMER==0
91# error "High resolution timer is needed for this sample"
94#define THIS_FILE "siprtp.c"
96#define RTP_START_PORT 4000
116 unsigned media_index;
127 unsigned samples_per_frame;
128 unsigned bytes_per_frame;
149 pjsip_inv_session *inv;
150 unsigned media_count;
169 unsigned thread_count;
179 char *report_filename;
181 struct codec audio_codec;
188 pjsip_endpoint *sip_endpt;
203static void call_on_media_update( pjsip_inv_session *inv,
207static void call_on_state_changed( pjsip_inv_session *inv,
211static void call_on_forked(pjsip_inv_session *inv, pjsip_event *e);
214static pj_bool_t on_rx_request( pjsip_rx_data *rdata );
217static int sip_worker_thread( void *arg);
225static void hangup_call( unsigned index);
228static void destroy_call_media( unsigned call_index);
231static void destroy_media();
234static void on_rx_rtp( void *user_data, void *pkt, pj_ssize_t size);
237static void on_rx_rtcp( void *user_data, void *pkt, pj_ssize_t size);
240static void app_perror( const char *sender, const char *title,
244static void print_call( int call_index);
252static pjsip_module mod_siprtp =
255 { "mod-siprtpapp", 13 },
257 PJSIP_MOD_PRIORITY_APPLICATION,
271struct codec audio_codecs[] =
273 { 0, "PCMU", 8000, 64000, 20, "G.711 ULaw" },
274 { 3, "GSM", 8000, 13200, 20, "GSM" },
275 { 4, "G723", 8000, 6400, 30, "G.723.1" },
276 { 8, "PCMA", 8000, 64000, 20, "G.711 ALaw" },
277 { 18, "G729", 8000, 8000, 20, "G.729" },
297 app.pool = pj_pool_create(&app.cp.factory, "app", 1000, 1000, NULL);
300 status = pjsip_endpt_create(&app.cp.factory, pj_gethostname()->ptr,
308 pjsip_host_port addrname;
316 if (app.local_addr.slen) {
318 addrname.host = app.local_addr;
319 addrname.port = app.sip_port;
324 app_perror(THIS_FILE, "Unable to resolve IP interface", status);
329 status = pjsip_udp_transport_start( app.sip_endpt, &addr,
330 (app.local_addr.slen ? &addrname:NULL),
333 app_perror(THIS_FILE, "Unable to start UDP transport", status);
337 PJ_LOG(3,(THIS_FILE, "SIP UDP listening on %.*s:%d",
338 ( int)tp->local_name.host.slen, tp->local_name.host.ptr,
339 tp->local_name.port));
346 status = pjsip_tsx_layer_init_module(app.sip_endpt);
350 status = pjsip_ua_init_module( app.sip_endpt, NULL );
354 status = pjsip_100rel_init_module(app.sip_endpt);
359 pjsip_inv_callback inv_cb;
363 inv_cb.on_state_changed = &call_on_state_changed;
364 inv_cb.on_new_session = &call_on_forked;
365 inv_cb.on_media_update = &call_on_media_update;
368 status = pjsip_inv_usage_init(app.sip_endpt, &inv_cb);
373 status = pjsip_endpt_register_module( app.sip_endpt, &mod_siprtp);
377 for (i=0; i<app.max_calls; ++i)
378 app.call[i].index = i;
388static void destroy_sip()
393 for (i=0; i<app.thread_count; ++i) {
394 if (app.sip_thread[i]) {
397 app.sip_thread[i] = NULL;
402 pjsip_endpt_destroy(app.sip_endpt);
403 app.sip_endpt = NULL;
426 pjsip_endpt_get_ioqueue(app.sip_endpt),
433#if defined(PJMEDIA_HAS_G711_CODEC) && PJMEDIA_HAS_G711_CODEC!=0
438 rtp_port = ( pj_uint16_t)(app.rtp_start_port & 0xFFFE);
441 for (i=0, count=0; i<app.max_calls; ++i, ++count) {
452 app.call[i].media[j].call_index = i;
453 app.call[i].media[j].media_index = j;
456 for (retry=0; retry<100; ++retry,rtp_port+=2) {
487static void destroy_media()
491 for (i=0; i<app.max_calls; ++i) {
505 app.med_endpt = NULL;
519 pjsip_tx_data *tdata;
524 for (i=0; i<app.max_calls; ++i) {
525 if (app.call[i].inv == NULL)
529 if (i == app.max_calls)
535 status = pjsip_dlg_create_uac( pjsip_ua_instance(),
547 create_sdp( dlg->pool, call, &sdp);
550 status = pjsip_inv_create_uac( dlg, sdp, 0, & call->inv);
552 pjsip_dlg_terminate(dlg);
559 call->inv->mod_data[mod_siprtp.id] = call;
569 status = pjsip_inv_invite( call->inv, &tdata);
577 status = pjsip_inv_send_msg( call->inv, tdata);
588static void process_incoming_call(pjsip_rx_data *rdata)
594 pjsip_tx_data *tdata;
598 for (i=0; i<app.max_calls; ++i) {
599 if (app.call[i].inv == NULL)
603 if (i == app.max_calls) {
605 pjsip_endpt_respond_stateless( app.sip_endpt, rdata,
615 status = pjsip_inv_verify_request(rdata, &options, NULL, NULL,
616 app.sip_endpt, &tdata);
622 pjsip_response_addr res_addr;
624 pjsip_get_response_addr(tdata->pool, rdata, &res_addr);
625 status = pjsip_endpt_send_response(app.sip_endpt, &res_addr, tdata,
627 if (status != PJ_SUCCESS) pjsip_tx_data_dec_ref(tdata);
632 pjsip_endpt_respond_stateless(app.sip_endpt, rdata, 500, NULL,
640 status = pjsip_dlg_create_uas_and_inc_lock( pjsip_ua_instance(), rdata,
641 &app.local_contact, &dlg);
644 pjsip_endpt_respond_stateless( app.sip_endpt, rdata,
651 create_sdp( dlg->pool, call, &sdp);
654 status = pjsip_inv_create_uas( dlg, rdata, sdp, 0, & call->inv);
656 pjsip_dlg_create_response(dlg, rdata, 500, NULL, &tdata);
657 pjsip_dlg_send_response(dlg, pjsip_rdata_get_tsx(rdata), tdata);
658 pjsip_dlg_dec_lock(dlg);
663 pjsip_dlg_dec_lock(dlg);
666 call->inv->mod_data[mod_siprtp.id] = call;
674 status = pjsip_inv_initial_answer( call->inv, rdata, 200,
677 status = pjsip_inv_initial_answer( call->inv, rdata,
678 PJSIP_SC_NOT_ACCEPTABLE,
681 pjsip_inv_send_msg( call->inv, tdata);
689 status = pjsip_inv_send_msg( call->inv, tdata);
698static void call_on_forked(pjsip_inv_session *inv, pjsip_event *e)
708static pj_bool_t on_rx_request( pjsip_rx_data *rdata )
711 if (rdata->msg_info.msg->line.req.method.id == PJSIP_ACK_METHOD)
715 if (rdata->msg_info.msg->line.req.method.id != PJSIP_INVITE_METHOD) {
717 pjsip_endpt_respond_stateless( app.sip_endpt, rdata,
724 process_incoming_call(rdata);
740 hangup_call( call->index);
745static void call_on_state_changed( pjsip_inv_session *inv,
748 struct call * call = ( struct call *)inv->mod_data[mod_siprtp.id];
755 if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
760 pjsip_endpt_cancel_timer(app.sip_endpt, & call-> d_timer);
764 PJ_LOG(3,(THIS_FILE, "Call #%d disconnected. Reason=%d (%.*s)",
767 ( int)inv->cause_text.slen,
768 inv->cause_text.ptr));
770 if (app.call_report) {
771 PJ_LOG(3,(THIS_FILE, "Call #%d statistics:", call->index));
772 print_call( call->index);
777 inv->mod_data[mod_siprtp.id] = NULL;
779 destroy_call_media( call->index);
781 call->start_time = null_time;
782 call->response_time = null_time;
783 call->connect_time = null_time;
787 } else if (inv->state == PJSIP_INV_STATE_CONFIRMED) {
792 if ( call->response_time. sec == 0)
793 call->response_time = call->connect_time;
795 t = call->connect_time;
798 PJ_LOG(3,(THIS_FILE, "Call #%d connected in %d ms", call->index,
801 if (app.duration != 0) {
806 t. sec = app.duration;
809 pjsip_endpt_schedule_timer(app.sip_endpt, & call-> d_timer, &t);
812 } else if ( inv->state == PJSIP_INV_STATE_EARLY ||
813 inv->state == PJSIP_INV_STATE_CONNECTING) {
815 if ( call->response_time. sec == 0)
823static void app_perror( const char *sender, const char *title,
829 PJ_LOG(3,(sender, "%s: %s [status=%d]", title, errmsg, status));
834static int sip_worker_thread( void *arg)
838 while (!app.thread_quit) {
840 pjsip_endpt_handle_events(app.sip_endpt, &timeout);
848static pj_status_t init_options( int argc, char *argv[])
851 static char local_uri[64];
854 OPT_APP_LOG_LEVEL, OPT_LOG_FILE,
855 OPT_A_PT, OPT_A_NAME, OPT_A_CLOCK, OPT_A_BITRATE, OPT_A_PTIME,
859 { "count", 1, 0, 'c' },
860 { "gap", 1, 0, 'g' },
861 { "call-report", 0, 0, 'R' },
862 { "duration", 1, 0, 'd' },
863 { "auto-quit", 0, 0, 'q' },
864 { "local-port", 1, 0, 'p' },
865 { "rtp-port", 1, 0, 'r' },
866 { "ip-addr", 1, 0, 'i' },
868 { "log-level", 1, 0, 'l' },
869 { "app-log-level", 1, 0, OPT_APP_LOG_LEVEL },
870 { "log-file", 1, 0, OPT_LOG_FILE },
872 { "report-file", 1, 0, OPT_REPORT_FILE },
900 app.thread_count = 1;
902 app.rtp_start_port = RTP_START_PORT;
903 app.local_addr = pj_str(ip_addr);
905 app.app_log_level = 3;
906 app.log_filename = NULL;
909 app.audio_codec = audio_codecs[0];
913 while((c=pj_getopt_long(argc,argv, "c:d:p:r:i:l:g:qR",
914 long_options, &option_index))!=-1)
918 app.max_calls = atoi(pj_optarg);
919 if (app.max_calls > MAX_CALLS) {
920 PJ_LOG(3,(THIS_FILE, "Invalid max calls value %s "
921 "(must be <= %d)", pj_optarg, MAX_CALLS));
926 app.call_gap = atoi(pj_optarg);
932 app.duration = atoi(pj_optarg);
939 app.sip_port = atoi(pj_optarg);
942 app.rtp_start_port = atoi(pj_optarg);
945 app.local_addr = pj_str(pj_optarg);
949 app.log_level = atoi(pj_optarg);
951 case OPT_APP_LOG_LEVEL:
952 app.app_log_level = atoi(pj_optarg);
955 app.log_filename = pj_optarg;
959 app.audio_codec.pt = atoi(pj_optarg);
962 app.audio_codec.name = pj_optarg;
965 app.audio_codec.clock_rate = atoi(pj_optarg);
968 app.audio_codec.bit_rate = atoi(pj_optarg);
971 app.audio_codec.ptime = atoi(pj_optarg);
973 case OPT_REPORT_FILE:
974 app.report_filename = pj_optarg;
984 if (pj_optind < argc)
985 app.uri_to_call = pj_str(argv[pj_optind]);
988 pj_ansi_sprintf( local_uri, "sip:%s:%d", app.local_addr.ptr, app.sip_port);
989 app.local_uri = pj_str(local_uri);
990 app.local_contact = app.local_uri;
1066 sprintf(ptstr, "%d", app.audio_codec.pt);
1069 rtpmap. clock_rate = app.audio_codec.clock_rate;
1106#if (defined(PJ_WIN32) && PJ_WIN32 != 0) || (defined(PJ_WIN64) && PJ_WIN64 != 0)
1108static void boost_priority( void)
1110 SetPriorityClass( GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
1111 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
1114#elif defined(PJ_LINUX) && PJ_LINUX != 0
1116static void boost_priority( void)
1118#define POLICY SCHED_FIFO
1119 struct sched_param tp;
1124 if (sched_get_priority_min(POLICY) < sched_get_priority_max(POLICY))
1125 max_prio = sched_get_priority_max(POLICY)-1;
1127 max_prio = sched_get_priority_max(POLICY)+1;
1132 rc = sched_getparam(0, &tp);
1134 app_perror( THIS_FILE, "sched_getparam error",
1138 tp.sched_priority = max_prio;
1140 rc = sched_setscheduler(0, POLICY, &tp);
1142 app_perror( THIS_FILE, "sched_setscheduler error",
1146 PJ_LOG(4, (THIS_FILE, "New process policy=%d, priority=%d",
1147 policy, tp.sched_priority));
1152 rc = pthread_getschedparam(pthread_self(), &policy, &tp);
1154 app_perror( THIS_FILE, "pthread_getschedparam error",
1159 PJ_LOG(4, (THIS_FILE, "Old thread policy=%d, priority=%d",
1160 policy, tp.sched_priority));
1163 tp.sched_priority = max_prio;
1165 rc = pthread_setschedparam(pthread_self(), policy, &tp);
1167 app_perror( THIS_FILE, "pthread_setschedparam error",
1172 PJ_LOG(4, (THIS_FILE, "New thread policy=%d, priority=%d",
1173 policy, tp.sched_priority));
1177# define boost_priority()
1184static void on_rx_rtp( void *user_data, void *pkt, pj_ssize_t size)
1189 const void *payload;
1190 unsigned payload_len;
1200 app_perror(THIS_FILE, "RTP recv() error", ( pj_status_t)-size);
1207 &hdr, &payload, &payload_len);
1209 app_perror(THIS_FILE, "RTP decode error", status);
1227static void on_rx_rtcp( void *user_data, void *pkt, pj_ssize_t size)
1239 app_perror(THIS_FILE, "Error receiving RTCP packet",( pj_status_t)-size);
1253static int media_thread( void *arg)
1255 enum { RTCP_INTERVAL = 5000, RTCP_RAND = 2000 };
1258 unsigned msec_interval;
1268 msec_interval = strm->samples_per_frame * 1000 / strm->clock_rate;
1272 next_rtp.u64 += (freq.u64 * msec_interval / 1000);
1274 next_rtcp = next_rtp;
1275 next_rtcp.u64 += (freq.u64 * (RTCP_INTERVAL+( pj_rand()%RTCP_RAND)) / 1000);
1278 while (!strm->thread_quit_flag) {
1286 if (next_rtp.u64 < next_rtcp.u64) {
1295 if (lesser.u64 <= now.u64) {
1296 timeout. sec = timeout. msec = 0;
1299 pj_uint64_t tick_delay;
1300 tick_delay = lesser.u64 - now.u64;
1311 if (strm->thread_quit_flag)
1317 if (send_rtp || next_rtp.u64 <= now.u64) {
1330 strm->bytes_per_frame,
1331 strm->samples_per_frame,
1343 pj_bzero(packet+hdrlen, strm->bytes_per_frame);
1346 size = hdrlen + strm->bytes_per_frame;
1350 app_perror(THIS_FILE, "Error sending RTP packet", status);
1360 next_rtp.u64 += (msec_interval * freq.u64 / 1000);
1364 if (send_rtcp || next_rtcp.u64 <= now.u64) {
1382 app_perror(THIS_FILE, "Error sending RTCP packet", status);
1386 next_rtcp.u64 += (freq.u64 * (RTCP_INTERVAL+( pj_rand()%RTCP_RAND)) /
1396static void call_on_media_update( pjsip_inv_session *inv,
1402 struct codec *codec_desc = NULL;
1405 call = ( struct call *)inv->mod_data[mod_siprtp.id];
1406 audio = & call->media[0];
1409 if (audio->thread != NULL)
1410 destroy_call_media( call->index);
1415 app_perror(THIS_FILE, "SDP negotiation failed", status);
1425 local_sdp, remote_sdp, 0);
1427 app_perror(THIS_FILE, "Error creating stream info from SDP", status);
1432 if (audio->si. fmt. pt == app.audio_codec.pt)
1433 codec_desc = &app.audio_codec;
1437 if (audio_codecs[i].pt == audio->si. fmt. pt) {
1438 codec_desc = &audio_codecs[i];
1443 if (codec_desc == NULL) {
1444 PJ_LOG(3, (THIS_FILE, "Error: Invalid codec payload type"));
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;
1458 audio->samples_per_frame, 0);
1469 app_perror(THIS_FILE, "Error on pjmedia_transport_attach()", status);
1477 audio->thread_quit_flag = 0;
1480 0, 0, &audio->thread);
1482 app_perror(THIS_FILE, "Error creating media thread", status);
1494static void destroy_call_media( unsigned call_index)
1496 struct media_stream *audio = &app.call[call_index].media[0];
1501 if (audio->thread) {
1502 audio->thread_quit_flag = 1;
1505 audio->thread = NULL;
1506 audio->thread_quit_flag = 0;
1518static void call_get_duration( int call_index, pj_time_val *dur)
1520 struct call * call = &app.call[call_index];
1521 pjsip_inv_session *inv;
1532 if (inv->state >= PJSIP_INV_STATE_CONFIRMED && call->connect_time. sec) {
1540static const char *good_number( char *buf, pj_int32_t val)
1543 pj_ansi_sprintf(buf, "%d", val);
1544 } else if (val < 1000000) {
1545 pj_ansi_sprintf(buf, "%d.%02dK",
1547 (val % 1000) / 100);
1549 pj_ansi_sprintf(buf, "%d.%02dM",
1551 (val % 1000000) / 10000);
1559static void print_avg_stat( void)
1561#define MIN_(var,val) if ((int)val < (int)var) var = val
1562#define MAX_(var,val) if ((int)val > (int)var) var = val
1563#define AVG_(var,val) var = ( ((var * count) + val) / (count+1) )
1564#define BIGVAL 0x7FFFFFFFL
1570 struct stat_entry call_dur, call_pdd;
1573 char srx_min[16], srx_avg[16], srx_max[16];
1574 char brx_min[16], brx_avg[16], brx_max[16];
1575 char stx_min[16], stx_avg[16], stx_max[16];
1576 char btx_min[16], btx_avg[16], btx_max[16];
1581 pj_bzero(&call_dur, sizeof(call_dur));
1582 call_dur.min = BIGVAL;
1584 pj_bzero(&call_pdd, sizeof(call_pdd));
1585 call_pdd.min = BIGVAL;
1587 pj_bzero(&min_stat, sizeof(min_stat));
1588 min_stat.rx.pkt = min_stat.tx.pkt = BIGVAL;
1589 min_stat.rx.bytes = min_stat.tx.bytes = BIGVAL;
1590 min_stat.rx.loss = min_stat.tx.loss = BIGVAL;
1591 min_stat.rx.dup = min_stat.tx.dup = BIGVAL;
1592 min_stat.rx.reorder = min_stat.tx.reorder = BIGVAL;
1593 min_stat.rx.jitter.min = min_stat.tx.jitter.min = BIGVAL;
1594 min_stat.rtt.min = BIGVAL;
1596 pj_bzero(&avg_stat, sizeof(avg_stat));
1597 pj_bzero(&max_stat, sizeof(max_stat));
1600 for (i=0, count=0; i<app.max_calls; ++i) {
1607 if ( call->inv == NULL ||
1608 call->inv->state < PJSIP_INV_STATE_CONFIRMED ||
1615 call_get_duration(i, &dur);
1618 MIN_(call_dur.min, msec_dur);
1619 MAX_(call_dur.max, msec_dur);
1620 AVG_(call_dur.avg, msec_dur);
1631 MIN_(call_pdd.min, msec_dur);
1632 MAX_(call_pdd.max, msec_dur);
1633 AVG_(call_pdd.avg, msec_dur);
1638 MIN_(min_stat.rx.pkt, audio->rtcp. stat. rx. pkt);
1639 MAX_(max_stat.rx.pkt, audio->rtcp. stat. rx. pkt);
1640 AVG_(avg_stat.rx.pkt, audio->rtcp. stat. rx. pkt);
1643 MIN_(min_stat.rx.bytes, audio->rtcp. stat. rx. bytes);
1644 MAX_(max_stat.rx.bytes, audio->rtcp. stat. rx. bytes);
1645 AVG_(avg_stat.rx.bytes, audio->rtcp. stat. rx. bytes);
1649 MIN_(min_stat.rx.loss, audio->rtcp. stat. rx. loss);
1650 MAX_(max_stat.rx.loss, audio->rtcp. stat. rx. loss);
1651 AVG_(avg_stat.rx.loss, audio->rtcp. stat. rx. loss);
1654 MIN_(min_stat.rx.dup, audio->rtcp. stat. rx. dup);
1655 MAX_(max_stat.rx.dup, audio->rtcp. stat. rx. dup);
1656 AVG_(avg_stat.rx.dup, audio->rtcp. stat. rx. dup);
1672 MIN_(min_stat.tx.pkt, audio->rtcp. stat. tx. pkt);
1673 MAX_(max_stat.tx.pkt, audio->rtcp. stat. tx. pkt);
1674 AVG_(avg_stat.tx.pkt, audio->rtcp. stat. tx. pkt);
1677 MIN_(min_stat.tx.bytes, audio->rtcp. stat. tx. bytes);
1678 MAX_(max_stat.tx.bytes, audio->rtcp. stat. tx. bytes);
1679 AVG_(avg_stat.tx.bytes, audio->rtcp. stat. tx. bytes);
1682 MIN_(min_stat.tx.loss, audio->rtcp. stat. tx. loss);
1683 MAX_(max_stat.tx.loss, audio->rtcp. stat. tx. loss);
1684 AVG_(avg_stat.tx.loss, audio->rtcp. stat. tx. loss);
1687 MIN_(min_stat.tx.dup, audio->rtcp. stat. tx. dup);
1688 MAX_(max_stat.tx.dup, audio->rtcp. stat. tx. dup);
1689 AVG_(avg_stat.tx.dup, audio->rtcp. stat. tx. dup);
1703 MIN_(min_stat.rtt.min, audio->rtcp. stat. rtt. min);
1704 MAX_(max_stat.rtt.max, audio->rtcp. stat. rtt. max);
1705 AVG_(avg_stat.rtt.mean, audio->rtcp. stat. rtt. mean);
1711 puts( "No active calls");
1715 printf( "Total %d call(s) active.\n"
1716 " Average Statistics\n"
1718 " -----------------------\n"
1719 " call duration: %7d %7d %7d %s\n"
1720 " connect delay: %7d %7d %7d %s\n"
1722 " packets: %7s %7s %7s %s\n"
1723 " payload: %7s %7s %7s %s\n"
1724 " loss: %7d %7d %7d %s\n"
1725 " percent loss: %7.3f %7.3f %7.3f %s\n"
1726 " dup: %7d %7d %7d %s\n"
1727 " reorder: %7d %7d %7d %s\n"
1728 " jitter: %7.3f %7.3f %7.3f %s\n"
1730 " packets: %7s %7s %7s %s\n"
1731 " payload: %7s %7s %7s %s\n"
1732 " loss: %7d %7d %7d %s\n"
1733 " percent loss: %7.3f %7.3f %7.3f %s\n"
1734 " dup: %7d %7d %7d %s\n"
1735 " reorder: %7d %7d %7d %s\n"
1736 " jitter: %7.3f %7.3f %7.3f %s\n"
1737 " RTT : %7.3f %7.3f %7.3f %s\n"
1740 call_dur.min/1000, call_dur.avg/1000, call_dur.max/1000,
1743 call_pdd.min, call_pdd.avg, call_pdd.max,
1748 good_number(srx_min, min_stat.rx.pkt),
1749 good_number(srx_avg, avg_stat.rx.pkt),
1750 good_number(srx_max, max_stat.rx.pkt),
1753 good_number(brx_min, min_stat.rx.bytes),
1754 good_number(brx_avg, avg_stat.rx.bytes),
1755 good_number(brx_max, max_stat.rx.bytes),
1758 min_stat.rx.loss, avg_stat.rx.loss, max_stat.rx.loss,
1761 min_stat.rx.loss*100.0/(min_stat.rx.pkt+min_stat.rx.loss),
1762 avg_stat.rx.loss*100.0/(avg_stat.rx.pkt+avg_stat.rx.loss),
1763 max_stat.rx.loss*100.0/(max_stat.rx.pkt+max_stat.rx.loss),
1767 min_stat.rx.dup, avg_stat.rx.dup, max_stat.rx.dup,
1770 min_stat.rx.reorder, avg_stat.rx.reorder, max_stat.rx.reorder,
1773 min_stat.rx.jitter.min/1000.0,
1774 avg_stat.rx.jitter.mean/1000.0,
1775 max_stat.rx.jitter.max/1000.0,
1780 good_number(stx_min, min_stat.tx.pkt),
1781 good_number(stx_avg, avg_stat.tx.pkt),
1782 good_number(stx_max, max_stat.tx.pkt),
1785 good_number(btx_min, min_stat.tx.bytes),
1786 good_number(btx_avg, avg_stat.tx.bytes),
1787 good_number(btx_max, max_stat.tx.bytes),
1790 min_stat.tx.loss, avg_stat.tx.loss, max_stat.tx.loss,
1793 min_stat.tx.loss*100.0/(min_stat.tx.pkt+min_stat.tx.loss),
1794 avg_stat.tx.loss*100.0/(avg_stat.tx.pkt+avg_stat.tx.loss),
1795 max_stat.tx.loss*100.0/(max_stat.tx.pkt+max_stat.tx.loss),
1798 min_stat.tx.dup, avg_stat.tx.dup, max_stat.tx.dup,
1801 min_stat.tx.reorder, avg_stat.tx.reorder, max_stat.tx.reorder,
1804 min_stat.tx.jitter.min/1000.0,
1805 avg_stat.tx.jitter.mean/1000.0,
1806 max_stat.tx.jitter.max/1000.0,
1810 min_stat.rtt.min/1000.0,
1811 avg_stat.rtt.mean/1000.0,
1812 max_stat.rtt.max/1000.0,
1819#include "siprtp_report.c"
1822static void list_calls()
1825 puts( "List all calls:");
1826 for (i=0; i<app.max_calls; ++i) {
1827 if (!app.call[i].inv)
1833static void hangup_call( unsigned index)
1835 pjsip_tx_data *tdata;
1838 if (app.call[index].inv == NULL)
1841 status = pjsip_inv_end_session(app.call[index].inv, 603, NULL, &tdata);
1843 pjsip_inv_send_msg(app.call[index].inv, tdata);
1846static void hangup_all_calls()
1849 for (i=0; i<app.max_calls; ++i) {
1850 if (!app.call[i].inv)
1857 for (i=0; i<app.max_calls; ++i) {
1858 while (app.call[i].inv)
1867 printf( "%s (empty to cancel): ", title); fflush(stdout);
1868 if (fgets(buf, ( int)len, stdin) == NULL)
1872 for (p=buf; ; ++p) {
1873 if (*p== '\r' || *p== '\n') *p= '\0';
1874 else if (!*p) break;
1884static const char *MENU =
1886"Enter menu character:\n"
1888" l List all calls\n"
1890" H Hangup all calls\n"
1896static void console_main()
1904 printf( ">>> "); fflush(stdout);
1905 if (fgets(input1, sizeof(input1), stdin) == NULL) {
1906 puts( "EOF while reading stdin, will quit now..");
1910 switch (input1[0]) {
1921 if (!simple_input( "Call number to hangup", input1, sizeof(input1)))
1936 puts( "Invalid command");
1955static pj_bool_t logger_on_rx_msg(pjsip_rx_data *rdata)
1957 PJ_LOG(4,(THIS_FILE, "RX %d bytes %s from %s:%d:\n"
1960 rdata->msg_info.len,
1961 pjsip_rx_data_get_info(rdata),
1962 rdata->pkt_info.src_name,
1963 rdata->pkt_info.src_port,
1964 rdata->msg_info.msg_buf));
1971static pj_status_t logger_on_tx_msg(pjsip_tx_data *tdata)
1980 PJ_LOG(4,(THIS_FILE, "TX %d bytes %s to %s:%d:\n"
1983 (tdata->buf.cur - tdata->buf.start),
1984 pjsip_tx_data_get_info(tdata),
1985 tdata->tp_info.dst_name,
1986 tdata->tp_info.dst_port,
1994static pjsip_module msg_logger =
1997 { "mod-siprtp-log", 14 },
1999 PJSIP_MOD_PRIORITY_TRANSPORT_LAYER-1,
2019static FILE *log_file;
2022static void app_log_writer( int level, const char *buffer, int len)
2026 if (level <= app.app_log_level)
2030 pj_size_t count = fwrite(buffer, len, 1, log_file);
2045 if (app.log_filename) {
2046 log_file = fopen(app.log_filename, "wt");
2047 if (log_file == NULL) {
2048 PJ_LOG(1,(THIS_FILE, "Unable to open log file %s",
2058void app_logging_shutdown( void)
2072int main( int argc, char *argv[])
2083 status = init_options(argc, argv);
2090 if (app.auto_quit && app.uri_to_call.slen == 0) {
2091 printf( "Error: --auto-quit option only valid for outgoing "
2092 "mode (UAC) only\n");
2097 status = app_logging_init();
2102 status = init_sip();
2104 app_perror(THIS_FILE, "Initialization has failed", status);
2110 pjsip_endpt_register_module(app.sip_endpt, &msg_logger);
2113 status = init_media();
2115 app_perror(THIS_FILE, "Media initialization failed", status);
2122 for (i=0; i<app.thread_count; ++i) {
2124 0, 0, &app.sip_thread[i]);
2129 if (app.uri_to_call.slen) {
2130 PJ_LOG(3,(THIS_FILE, "Making %d calls to %s..", app.max_calls,
2131 app.uri_to_call.ptr));
2133 for (i=0; i<app.max_calls; ++i) {
2134 status = make_call(&app.uri_to_call);
2136 app_perror(THIS_FILE, "Error making call", status);
2142 if (app.auto_quit) {
2144 while (app.uac_calls < app.max_calls)
2156 PJ_LOG(3,(THIS_FILE, "Ready for incoming calls (max=%d)",
2166 PJ_LOG(3,(THIS_FILE, "Press Ctrl-C to quit"));
2169 pjsip_endpt_handle_events(app.sip_endpt, &t);
2183 app_logging_shutdown();
pj_status_t pjlib_util_init(void)
pj_status_t pjmedia_endpt_create(pj_pool_factory *pf, pj_ioqueue_t *ioqueue, unsigned worker_cnt, pjmedia_endpt **p_endpt) Definition: endpoint.h:127
pj_status_t pjmedia_endpt_destroy(pjmedia_endpt *endpt) Definition: endpoint.h:168
pj_status_t pjmedia_codec_g711_init(pjmedia_endpt *endpt)
void pjmedia_rtcp_rx_rtcp(pjmedia_rtcp_session *session, const void *rtcp_pkt, pj_size_t size)
void pjmedia_rtcp_rx_rtp(pjmedia_rtcp_session *session, unsigned seq, unsigned ts, unsigned payload)
void pjmedia_rtcp_build_rtcp(pjmedia_rtcp_session *session, void **rtcp_pkt, int *len)
void pjmedia_rtcp_tx_rtp(pjmedia_rtcp_session *session, unsigned ptsize)
void pjmedia_rtcp_init(pjmedia_rtcp_session *session, char *name, unsigned clock_rate, unsigned samples_per_frame, pj_uint32_t ssrc)
pj_status_t pjmedia_rtp_encode_rtp(pjmedia_rtp_session *ses, int pt, int m, int payload_len, int ts_len, const void **rtphdr, int *hdrlen)
void pjmedia_rtp_session_update(pjmedia_rtp_session *ses, const pjmedia_rtp_hdr *hdr, pjmedia_rtp_status *seq_st)
pj_status_t pjmedia_rtp_decode_rtp(pjmedia_rtp_session *ses, const void *pkt, int pkt_len, const pjmedia_rtp_hdr **hdr, const void **payload, unsigned *payloadlen)
pj_status_t pjmedia_rtp_session_init(pjmedia_rtp_session *ses, int default_pt, pj_uint32_t sender_ssrc)
pj_status_t pj_init(void)
unsigned short pj_uint16_t
struct pj_thread_t pj_thread_t
struct pj_timer_heap_t pj_timer_heap_t
void pj_caching_pool_destroy(pj_caching_pool *ch_pool)
void pj_caching_pool_init(pj_caching_pool *ch_pool, const pj_pool_factory_policy *policy, pj_size_t max_capacity)
void pj_log_write(int level, const char *buffer, int len)
#define PJ_LOG(level, arg)
void pj_log_set_log_func(pj_log_func *func)
pj_pool_factory_policy pj_pool_factory_default_policy
#define PJ_POOL_ZALLOC_T(pool, type)
pj_pool_t * pj_pool_create(pj_pool_factory *factory, const char *name, pj_size_t initial_size, pj_size_t increment_size, pj_pool_callback *callback)
void pj_pool_release(pj_pool_t *pool)
void * pj_memcpy(void *dst, const void *src, pj_size_t size)
pj_str_t pj_str(char *str)
pj_str_t * pj_strdup2(pj_pool_t *pool, pj_str_t *dst, const char *src)
void pj_bzero(void *dst, pj_size_t size)
pj_uint16_t pj_htons(pj_uint16_t hostshort)
#define PJ_INET_ADDRSTRLEN
pj_status_t pj_inet_ntop(int af, const void *src, char *dst, int size)
const pj_str_t * pj_gethostname(void)
pj_uint32_t pj_ntohl(pj_uint32_t netlong)
pj_uint16_t pj_ntohs(pj_uint16_t netshort)
pj_status_t pj_sockaddr_in_init(pj_sockaddr_in *addr, const pj_str_t *cp, pj_uint16_t port)
pj_status_t pj_thread_destroy(pj_thread_t *thread)
pj_status_t pj_thread_join(pj_thread_t *thread)
pj_status_t pj_thread_create(pj_pool_t *pool, const char *thread_name, pj_thread_proc *proc, void *arg, pj_size_t stack_size, unsigned flags, pj_thread_t **thread)
pj_status_t pj_thread_sleep(unsigned msec)
pj_status_t pj_get_timestamp_freq(pj_timestamp *freq)
pj_status_t pj_get_timestamp(pj_timestamp *ts)
pj_status_t pj_gettimeofday(pj_time_val *tv)
void pj_time_val_normalize(pj_time_val *t)
#define PJ_TIME_VAL_MSEC(t)
#define PJ_TIME_VAL_SUB(t1, t2)
#define PJ_ASSERT_ON_FAIL(expr, exec_on_fail)
#define PJ_ASSERT_RETURN(expr, retval)
#define PJ_UNUSED_ARG(arg)
pj_str_t pj_strerror(pj_status_t statcode, char *buf, pj_size_t bufsize)
#define PJ_RETURN_OS_ERROR(os_code)
Definition: pjsip-perf.c:172
pj_timer_entry d_timer Definition: siprtp.c:156
pj_timer_heap_callback * cb
PJMEDIA small footprint Open Source media stack
Copyright (C) 2006-2008 Teluu Inc.
|