- Timestamp:
- Apr 4, 2006 1:12:38 PM (19 years ago)
- Location:
- pjproject/trunk/pjsip-apps
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjsip-apps/build/Samples-vc.mak
r361 r379 41 41 $(BINDIR)\confsample.exe $(BINDIR)\sndinfo.exe \ 42 42 $(BINDIR)\level.exe $(BINDIR)\recfile.exe \ 43 $(BINDIR)\resampleplay.exe 43 $(BINDIR)\resampleplay.exe $(BINDIR)\siprtp.exe 44 44 45 45 -
pjproject/trunk/pjsip-apps/build/Samples.mak
r361 r379 39 39 BINDIR := ../bin/samples 40 40 41 SAMPLES := simpleua playfile playsine confsample sndinfo level recfile resampleplay 41 SAMPLES := simpleua playfile playsine confsample sndinfo level recfile resampleplay \ 42 siprtp 42 43 43 44 EXES := $(foreach file, $(SAMPLES), $(BINDIR)/$(file)-$(MACHINE_NAME)-$(OS_NAME)-$(CC_NAME)$(HOST_EXE)) -
pjproject/trunk/pjsip-apps/src/samples/siprtp.c
r375 r379 35 35 36 36 37 /* Codec descriptor: */ 38 struct codec 39 { 40 unsigned pt; 41 char* name; 42 unsigned clock_rate; 43 unsigned bit_rate; 44 unsigned ptime; 45 char* description; 46 }; 47 48 49 /* Unidirectional media stat: */ 50 struct stream_stat 51 { 52 pj_uint32_t pkt, payload; 53 pj_uint32_t discard, reorder; 54 unsigned loss_min, loss_avg, loss_max; 55 char *loss_type; 56 unsigned jitter_min, jitter_avg, jitter_max; 57 unsigned rtcp_cnt; 58 }; 59 60 37 61 /* A bidirectional media stream */ 38 62 struct media_stream … … 61 85 pjmedia_rtcp_pkt rem_rtcp; /* received RTCP stat. */ 62 86 87 /* More stats: */ 88 struct stream_stat rx_stat; /* incoming stream stat */ 89 struct stream_stat tx_stat; /* outgoing stream stat. */ 90 63 91 /* Thread: */ 64 92 pj_bool_t thread_quit_flag; /* worker thread quit flag */ … … 73 101 unsigned media_count; 74 102 struct media_stream media[2]; 103 pj_time_val start_time; 104 pj_time_val response_time; 105 pj_time_val connect_time; 75 106 }; 76 107 … … 85 116 pj_str_t local_uri; 86 117 pj_str_t local_contact; 118 119 int app_log_level; 120 int log_level; 121 char *log_filename; 122 123 struct codec audio_codec; 87 124 88 125 pj_str_t uri_to_call; … … 133 170 static void app_perror(const char *sender, const char *title, 134 171 pj_status_t status); 172 173 135 174 136 175 … … 158 197 159 198 199 /* Codec constants */ 200 struct codec audio_codecs[] = 201 { 202 { 0, "pcmu", 8000, 64000, 20, "G.711 ULaw" }, 203 { 3, "gsm", 8000, 13200, 20, "GSM" }, 204 { 4, "g723", 8000, 6400, 30, "G.723.1" }, 205 { 8, "pcma", 8000, 64000, 20, "G.711 ALaw" }, 206 { 18, "g729", 8000, 8000, 20, "G.729" }, 207 }; 208 209 160 210 /* 161 211 * Init SIP stack … … 163 213 static pj_status_t init_sip() 164 214 { 165 unsigned i;166 215 pj_status_t status; 167 216 … … 241 290 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 242 291 243 244 /* Start worker threads */245 for (i=0; i<app.thread_count; ++i) {246 pj_thread_create( app.pool, "app", &worker_thread, NULL,247 0, 0, &app.thread[i]);248 }249 292 250 293 /* Done */ … … 463 506 call->inv->mod_data[mod_siprtp.id] = call; 464 507 508 /* Mark start of call */ 509 pj_gettimeofday(&call->start_time); 510 465 511 466 512 /* Create initial INVITE request. … … 529 575 status = pjsip_inv_create_uas( dlg, rdata, sdp, 0, &call->inv); 530 576 if (status != PJ_SUCCESS) { 531 pjsip_dlg_terminate(dlg); 577 pjsip_dlg_create_response(dlg, rdata, 500, NULL, &tdata); 578 pjsip_dlg_send_response(dlg, pjsip_rdata_get_tsx(rdata), tdata); 532 579 return; 533 580 } 534 581 582 535 583 /* Attach call data to invite session */ 536 584 call->inv->mod_data[mod_siprtp.id] = call; 585 586 /* Mark start of call */ 587 pj_gettimeofday(&call->start_time); 588 589 537 590 538 591 /* Create 200 response .*/ 539 592 status = pjsip_inv_initial_answer(call->inv, rdata, 200, 540 593 NULL, NULL, &tdata); 541 PJ_ASSERT_ON_FAIL(status == PJ_SUCCESS, return); 594 if (status != PJ_SUCCESS) { 595 status = pjsip_inv_initial_answer(call->inv, rdata, 596 PJSIP_SC_NOT_ACCEPTABLE, 597 NULL, NULL, &tdata); 598 if (status == PJ_SUCCESS) 599 pjsip_inv_send_msg(call->inv, tdata); 600 else 601 pjsip_inv_terminate(call->inv, 500, PJ_FALSE); 602 return; 603 } 604 542 605 543 606 /* Send the 200 response. */ … … 563 626 static pj_bool_t on_rx_request( pjsip_rx_data *rdata ) 564 627 { 628 /* Ignore strandled ACKs (must not send respone */ 629 if (rdata->msg_info.msg->line.req.method.id == PJSIP_ACK_METHOD) 630 return PJ_FALSE; 631 565 632 /* Respond (statelessly) any non-INVITE requests with 500 */ 566 633 if (rdata->msg_info.msg->line.req.method.id != PJSIP_INVITE_METHOD) { … … 584 651 pjsip_event *e) 585 652 { 653 struct call *call = inv->mod_data[mod_siprtp.id]; 654 586 655 PJ_UNUSED_ARG(e); 587 656 657 if (!call) 658 return; 659 588 660 if (inv->state == PJSIP_INV_STATE_DISCONNECTED) { 589 struct call *call = inv->mod_data[mod_siprtp.id]; 590 591 if (!call) 592 return; 661 662 pj_time_val null_time = {0, 0}; 593 663 594 664 call->inv = NULL; … … 596 666 597 667 destroy_call_media(call->index); 668 669 call->start_time = null_time; 670 call->response_time = null_time; 671 call->connect_time = null_time; 672 673 PJ_LOG(3,(THIS_FILE, "Call #%d disconnected. Reason=%s", 674 call->index, 675 pjsip_get_status_text(inv->cause)->ptr)); 676 677 } else if (inv->state == PJSIP_INV_STATE_CONFIRMED) { 678 679 pj_time_val t; 680 681 pj_gettimeofday(&call->connect_time); 682 if (call->response_time.sec == 0) 683 call->response_time = call->connect_time; 684 685 t = call->connect_time; 686 PJ_TIME_VAL_SUB(t, call->start_time); 687 688 PJ_LOG(3,(THIS_FILE, "Call #%d connected in %d ms", call->index, 689 PJ_TIME_VAL_MSEC(t))); 690 691 } else if ( inv->state == PJSIP_INV_STATE_EARLY || 692 inv->state == PJSIP_INV_STATE_CONNECTING) { 693 694 if (call->response_time.sec == 0) 695 pj_gettimeofday(&call->response_time); 696 598 697 } 599 698 } … … 627 726 /* Usage */ 628 727 static const char *USAGE = 629 "Usage: 630 " siprtp [options] => to start in server mode 631 " siprtp [options] URL => to start in client mode 728 "Usage:\n" 729 " siprtp [options] => to start in server mode\n" 730 " siprtp [options] URL => to start in client mode\n" 632 731 "\n" 633 "where options are: \n" 634 " --count=N, -c Set number of calls to create (default:1) \n" 635 " --port=PORT -p Set local SIP port (default: 5060) \n" 636 " --rtp-port=PORT -r Set start of RTP port (default: 4000) \n" 637 " --ip-addr=IP -i Set local IP address to use (otherwise it will\n" 732 "Program options:\n" 733 " --count=N, -c Set number of calls to create (default:1) \n" 734 "\n" 735 "Address and ports options:\n" 736 " --local-port=PORT,-p Set local SIP port (default: 5060)\n" 737 " --rtp-port=PORT, -r Set start of RTP port (default: 4000)\n" 738 " --ip-addr=IP, -i Set local IP address to use (otherwise it will\n" 638 739 " try to determine local IP address from hostname)\n" 740 "\n" 741 "Logging Options:\n" 742 " --log-level=N, -l Set log verbosity level (default=5)\n" 743 " --app-log-level=N Set app screen log verbosity (default=3)\n" 744 " --log-file=FILE Write log to file FILE\n" 745 "\n" 746 "Codec Options:\n" 747 " --a-pt=PT Set audio payload type to PT (default=0)\n" 748 " --a-name=NAME Set audio codec name to NAME (default=pcmu)\n" 749 " --a-clock=RATE Set audio codec rate to RATE Hz (default=8000 Hz)\n" 750 " --a-bitrate=BPS Set audio codec bitrate to BPS (default=64000 bps)\n" 751 " --a-ptime=MS Set audio frame time to MS msec (default=20 msec)\n" 639 752 ; 640 753 … … 646 759 static char local_uri[64]; 647 760 761 enum { OPT_START, 762 OPT_APP_LOG_LEVEL, OPT_LOG_FILE, 763 OPT_A_PT, OPT_A_NAME, OPT_A_CLOCK, OPT_A_BITRATE, OPT_A_PTIME }; 764 648 765 struct pj_getopt_option long_options[] = { 649 { "count", 1, 0, 'c' }, 650 { "port", 1, 0, 'p' }, 651 { "rtp-port", 1, 0, 'r' }, 652 { "ip-addr", 1, 0, 'i' }, 766 { "count", 1, 0, 'c' }, 767 { "local-port", 1, 0, 'p' }, 768 { "rtp-port", 1, 0, 'r' }, 769 { "ip-addr", 1, 0, 'i' }, 770 771 { "log-level", 1, 0, 'l' }, 772 { "app-log-level", 1, 0, OPT_APP_LOG_LEVEL }, 773 { "log-file", 1, 0, OPT_LOG_FILE }, 774 { "a-pt", 1, 0, OPT_A_PT }, 775 { "a-name", 1, 0, OPT_A_NAME }, 776 { "a-clock", 1, 0, OPT_A_CLOCK }, 777 { "a-bitrate", 1, 0, OPT_A_BITRATE }, 778 { "a-ptime", 1, 0, OPT_A_PTIME }, 779 653 780 { NULL, 0, 0, 0 }, 654 781 }; … … 668 795 } 669 796 670 /* Init default */797 /* Init defaults */ 671 798 app.max_calls = 1; 672 799 app.thread_count = 1; … … 674 801 app.rtp_start_port = 4000; 675 802 app.local_addr = ip_addr; 803 app.log_level = 5; 804 app.app_log_level = 3; 805 app.log_filename = NULL; 806 807 /* Default codecs: */ 808 app.audio_codec = audio_codecs[0]; 676 809 677 810 /* Parse options */ 678 811 pj_optind = 0; 679 while((c=pj_getopt_long(argc,argv, "c:p:r:i: ",812 while((c=pj_getopt_long(argc,argv, "c:p:r:i:l:", 680 813 long_options, &option_index))!=-1) 681 814 { … … 697 830 app.local_addr = pj_optarg; 698 831 break; 832 833 case 'l': 834 app.log_level = atoi(pj_optarg); 835 break; 836 case OPT_APP_LOG_LEVEL: 837 app.app_log_level = atoi(pj_optarg); 838 break; 839 case OPT_LOG_FILE: 840 app.log_filename = pj_optarg; 841 break; 842 843 case OPT_A_PT: 844 app.audio_codec.pt = atoi(pj_optarg); 845 break; 846 case OPT_A_NAME: 847 app.audio_codec.name = pj_optarg; 848 break; 849 case OPT_A_CLOCK: 850 app.audio_codec.clock_rate = atoi(pj_optarg); 851 break; 852 case OPT_A_BITRATE: 853 app.audio_codec.bit_rate = atoi(pj_optarg); 854 break; 855 case OPT_A_PTIME: 856 app.audio_codec.ptime = atoi(pj_optarg); 857 break; 858 699 859 default: 700 860 puts(USAGE); … … 717 877 718 878 719 ////////////////////////////////////////////////////////////////////////////// 720 /* 879 /***************************************************************************** 721 880 * MEDIA STUFFS 722 881 */ … … 781 940 pjmedia_sdp_rtpmap rtpmap; 782 941 pjmedia_sdp_attr *attr; 783 784 PJ_TODO(PARAMETERIZE_CODEC); 785 786 m->desc.fmt[0] = pj_str("0");787 rtpmap.pt = pj_str("0");788 rtpmap.clock_rate = 8000;789 rtpmap.enc_name = pj_str( "pcmu");942 char ptstr[10]; 943 944 sprintf(ptstr, "%d", app.audio_codec.pt); 945 pj_strdup2(pool, &m->desc.fmt[0], ptstr); 946 rtpmap.pt = m->desc.fmt[0]; 947 rtpmap.clock_rate = app.audio_codec.clock_rate; 948 rtpmap.enc_name = pj_str(app.audio_codec.name); 790 949 rtpmap.param.slen = 0; 791 950 … … 803 962 * Add support telephony event 804 963 */ 805 m->desc.fmt[m->desc.fmt_count++] = pj_str("1 01");964 m->desc.fmt[m->desc.fmt_count++] = pj_str("121"); 806 965 /* Add rtpmap. */ 807 966 attr = pj_pool_zalloc(pool, sizeof(pjmedia_sdp_attr)); 808 967 attr->name = pj_str("rtpmap"); 809 attr->value = pj_str(":1 01 telephone-event/8000");968 attr->value = pj_str(":121 telephone-event/8000"); 810 969 m->attr[m->attr_count++] = attr; 811 970 /* Add fmtp */ 812 971 attr = pj_pool_zalloc(pool, sizeof(pjmedia_sdp_attr)); 813 972 attr->name = pj_str("fmtp"); 814 attr->value = pj_str(":1 01 0-15");973 attr->value = pj_str(":121 0-15"); 815 974 m->attr[m->attr_count++] = attr; 816 975 #endif … … 823 982 824 983 825 /* Media thread */ 984 /* 985 * Media thread 986 * 987 * This is the thread to send and receive both RTP and RTCP packets. 988 */ 826 989 static int media_thread(void *arg) 827 990 { … … 881 1044 } 882 1045 1046 ++strm->rx_stat.pkt; 1047 strm->rx_stat.payload += (size - 12); 1048 883 1049 /* Decode RTP packet. */ 884 1050 status = pjmedia_rtp_decode_rtp(&strm->in_sess, … … 888 1054 if (status != PJ_SUCCESS) { 889 1055 app_perror(THIS_FILE, "RTP decode error", status); 1056 strm->rx_stat.discard++; 890 1057 continue; 891 1058 } … … 900 1067 PJ_LOG(3,(THIS_FILE,"RTP packet detail: pt=%d, seq=%d", 901 1068 hdr->pt, pj_ntohs(hdr->seq))); 1069 strm->rx_stat.discard++; 902 1070 continue; 903 1071 } … … 920 1088 app_perror(THIS_FILE, "Error receiving RTCP packet", status); 921 1089 else { 922 if (size > sizeof(strm->rem_rtcp)) 1090 if (size > sizeof(strm->rem_rtcp)) { 923 1091 PJ_LOG(3,(THIS_FILE, "Error: RTCP packet too large")); 924 else 1092 status = -1; 1093 } else { 925 1094 pj_memcpy(&strm->rem_rtcp, packet, size); 1095 status = PJ_SUCCESS; 1096 } 1097 } 1098 1099 if (status == PJ_SUCCESS) { 1100 /* Process RTCP stats */ 1101 unsigned jitter; 1102 1103 jitter = pj_ntohl(strm->rem_rtcp.rr.jitter) * 1000 / 1104 strm->clock_rate; 1105 if (jitter < strm->tx_stat.jitter_min) 1106 strm->tx_stat.jitter_min = jitter; 1107 if (jitter > strm->tx_stat.jitter_max) 1108 strm->tx_stat.jitter_max = jitter; 1109 strm->tx_stat.jitter_avg = (strm->tx_stat.jitter_avg * strm->tx_stat.rtcp_cnt + 1110 jitter) / (strm->tx_stat.rtcp_cnt + 1); 1111 1112 strm->tx_stat.rtcp_cnt++; 926 1113 } 927 1114 } … … 970 1157 next_rtp.msec += strm->samples_per_frame * 1000 / strm->clock_rate; 971 1158 pj_time_val_normalize(&next_rtp); 1159 1160 /* Update stats */ 1161 strm->tx_stat.pkt++; 1162 strm->tx_stat.payload += strm->bytes_per_frame; 972 1163 } 973 1164 … … 1002 1193 1003 1194 1195 /* Process RTCP stats */ 1196 { 1197 unsigned jitter; 1198 1199 jitter = pj_ntohl(rtcp_pkt->rr.jitter) * 1000 / 1200 strm->clock_rate; 1201 if (jitter < strm->rx_stat.jitter_min) 1202 strm->rx_stat.jitter_min = jitter; 1203 if (jitter > strm->rx_stat.jitter_max) 1204 strm->rx_stat.jitter_max = jitter; 1205 strm->rx_stat.jitter_avg = (strm->rx_stat.jitter_avg * strm->rx_stat.rtcp_cnt + 1206 jitter) / (strm->rx_stat.rtcp_cnt + 1); 1207 1208 strm->rx_stat.rtcp_cnt++; 1209 } 1210 1004 1211 next_rtcp.sec += 5; 1005 1212 } … … 1019 1226 struct media_stream *audio; 1020 1227 pjmedia_sdp_session *local_sdp, *remote_sdp; 1021 1228 struct codec *codec_desc = NULL; 1229 unsigned i; 1022 1230 1023 1231 call = inv->mod_data[mod_siprtp.id]; … … 1048 1256 } 1049 1257 1258 /* Get the remainder of codec information from codec descriptor */ 1259 if (audio->si.fmt.pt == app.audio_codec.pt) 1260 codec_desc = &app.audio_codec; 1261 else { 1262 /* Find the codec description in codec array */ 1263 for (i=0; i<PJ_ARRAY_SIZE(audio_codecs); ++i) { 1264 if (audio_codecs[i].pt == audio->si.fmt.pt) { 1265 codec_desc = &audio_codecs[i]; 1266 break; 1267 } 1268 } 1269 1270 if (codec_desc == NULL) { 1271 PJ_LOG(3, (THIS_FILE, "Error: Invalid codec payload type")); 1272 return; 1273 } 1274 } 1050 1275 1051 1276 audio->clock_rate = audio->si.fmt.sample_rate; 1052 audio->samples_per_frame = audio->clock_rate * 20 / 1000; 1053 audio->bytes_per_frame = 160; 1054 PJ_TODO(TAKE_CODEC_INFO_FROM_ARGUMENT); 1277 audio->samples_per_frame = audio->clock_rate * codec_desc->ptime / 1000; 1278 audio->bytes_per_frame = codec_desc->bit_rate * codec_desc->ptime / 1000 / 8; 1055 1279 1056 1280 … … 1059 1283 pjmedia_rtp_session_init(&audio->in_sess, audio->si.fmt.pt, 0); 1060 1284 pjmedia_rtcp_init(&audio->rtcp, 0); 1285 1286 1287 /* Clear media statistics */ 1288 pj_memset(&audio->rx_stat, 0, sizeof(audio->rx_stat)); 1289 pj_memset(&audio->tx_stat, 0, sizeof(audio->tx_stat)); 1290 1061 1291 1062 1292 /* Start media thread. */ … … 1082 1312 audio->thread = NULL; 1083 1313 audio->thread_quit_flag = 0; 1084 } 1085 } 1086 1087 1088 ///////////////////////////////////////////////////////////////////////////// 1089 /* 1314 1315 /* Flush RTP/RTCP packets */ 1316 { 1317 pj_fd_set_t set; 1318 pj_time_val timeout = {0, 0}; 1319 char packet[1500]; 1320 pj_ssize_t size; 1321 pj_status_t status; 1322 int rc; 1323 1324 do { 1325 PJ_FD_ZERO(&set); 1326 PJ_FD_SET(audio->rtp_sock, &set); 1327 PJ_FD_SET(audio->rtcp_sock, &set); 1328 1329 rc = pj_sock_select(FD_SETSIZE, &set, NULL, NULL, &timeout); 1330 if (rc > 0 && PJ_FD_ISSET(audio->rtp_sock, &set)) { 1331 size = sizeof(packet); 1332 status = pj_sock_recv(audio->rtp_sock, packet, &size, 0); 1333 1334 } 1335 if (rc > 0 && PJ_FD_ISSET(audio->rtcp_sock, &set)) { 1336 size = sizeof(packet); 1337 status = pj_sock_recv(audio->rtcp_sock, packet, &size, 0); 1338 } 1339 1340 } while (rc > 0); 1341 } 1342 } 1343 } 1344 1345 1346 /***************************************************************************** 1090 1347 * USER INTERFACE STUFFS 1091 1348 */ … … 1111 1368 static void print_call(int call_index) 1112 1369 { 1370 struct call *call = &app.call[call_index]; 1113 1371 int len; 1114 pjsip_inv_session *inv = app.call[call_index].inv;1372 pjsip_inv_session *inv = call->inv; 1115 1373 pjsip_dialog *dlg = inv->dlg; 1116 struct media_stream *audio = & app.call[call_index].media[0];1374 struct media_stream *audio = &call->media[0]; 1117 1375 char userinfo[128]; 1118 char packets[16]; 1119 1120 /* Dump invite sesion info. */ 1121 1376 char duration[80]; 1377 char bps[16], ipbps[16], packets[16], bytes[16], ipbytes[16]; 1378 pj_uint32_t total_loss; 1379 1380 1381 /* Print duration */ 1382 if (inv->state == PJSIP_INV_STATE_CONFIRMED) { 1383 pj_time_val now; 1384 1385 pj_gettimeofday(&now); 1386 PJ_TIME_VAL_SUB(now, call->connect_time); 1387 1388 sprintf(duration, " [duration: %02d:%02d:%02d.%03d]", 1389 now.sec / 3600, 1390 (now.sec % 3600) / 60, 1391 (now.sec % 60), 1392 now.msec); 1393 1394 } else { 1395 duration[0] = '\0'; 1396 } 1397 1398 1399 1400 /* Call number and state */ 1401 printf("Call #%d: %s%s\n", call_index, pjsip_inv_state_name(inv->state), 1402 duration); 1403 1404 1405 1406 /* Call identification */ 1122 1407 len = pjsip_hdr_print_on(dlg->remote.info, userinfo, sizeof(userinfo)); 1123 1408 if (len < 1) … … 1125 1410 else 1126 1411 userinfo[len] = '\0'; 1127 1128 printf("Call #%d: %s\n", call_index, pjsip_inv_state_name(inv->state)); 1412 1129 1413 printf(" %s\n", userinfo); 1130 1414 1131 if (app.call[call_index].media[0].thread == NULL) { 1415 1416 /* Signaling quality */ 1417 { 1418 char pdd[64], connectdelay[64]; 1419 pj_time_val t; 1420 1421 if (call->response_time.sec) { 1422 t = call->response_time; 1423 PJ_TIME_VAL_SUB(t, call->start_time); 1424 sprintf(pdd, "got 1st response in %d ms", PJ_TIME_VAL_MSEC(t)); 1425 } else { 1426 pdd[0] = '\0'; 1427 } 1428 1429 if (call->connect_time.sec) { 1430 t = call->connect_time; 1431 PJ_TIME_VAL_SUB(t, call->start_time); 1432 sprintf(connectdelay, ", connected after: %d ms", PJ_TIME_VAL_MSEC(t)); 1433 } else { 1434 connectdelay[0] = '\0'; 1435 } 1436 1437 printf(" Signaling quality: %s%s\n", pdd, connectdelay); 1438 } 1439 1440 1441 if (call->media[0].thread == NULL) { 1132 1442 return; 1133 1443 } 1134 1444 1135 printf(" Stream #0: audio %.*s@%dHz, %d bytes/sec\n",1445 printf(" Stream #0: audio %.*s@%dHz, %dms/frame, %sbps (%sbps +IP hdr)\n", 1136 1446 (int)audio->si.fmt.encoding_name.slen, 1137 1447 audio->si.fmt.encoding_name.ptr, 1138 1448 audio->clock_rate, 1139 audio->bytes_per_frame * audio->clock_rate / audio->samples_per_frame); 1140 printf(" RX pkt=%s, fraction lost=%5.2f%%, jitter=%dms\n", 1141 good_number(packets, audio->rtcp.received), 1142 audio->rtcp.rtcp_pkt.rr.fract_lost/255.0, 1143 pj_ntohl(audio->rtcp.rtcp_pkt.rr.jitter) * 1000 / audio->clock_rate); 1144 printf(" TX pkt=%s, fraction lost=%5.2f%%, jitter=%dms\n", 1145 good_number(packets, pj_ntohl(audio->rtcp.rtcp_pkt.sr.sender_pcount)), 1146 audio->rem_rtcp.rr.fract_lost/255.0, 1147 pj_ntohl(audio->rem_rtcp.rr.jitter) * 1000 / audio->clock_rate); 1449 audio->samples_per_frame * 1000 / audio->clock_rate, 1450 good_number(bps, audio->bytes_per_frame * audio->clock_rate / audio->samples_per_frame), 1451 good_number(ipbps, (audio->bytes_per_frame+32) * audio->clock_rate / audio->samples_per_frame)); 1452 1453 total_loss = (audio->rtcp.rtcp_pkt.rr.total_lost_2 << 16) + 1454 (audio->rtcp.rtcp_pkt.rr.total_lost_1 << 8) + 1455 audio->rtcp.rtcp_pkt.rr.total_lost_0; 1456 1457 printf(" RX total %s packets %sB received (%sB +IP hdr)%s\n" 1458 " pkt discards=%d (%3.1f%%), loss=%d (%3.1f%%), reorder=%d (%3.1f%%)%s\n" 1459 " loss period min=%d ms, avg=%d ms, max=%d ms%s\n" 1460 " jitter min=%d ms, avg=%d ms, max=%d ms, current=%d ms%s\n", 1461 good_number(packets, audio->rx_stat.pkt), 1462 good_number(bytes, audio->rx_stat.payload), 1463 good_number(ipbytes, audio->rx_stat.payload + audio->rx_stat.pkt * 32), 1464 "", 1465 audio->rx_stat.discard, 1466 audio->rx_stat.discard * 100.0 / audio->rx_stat.pkt, 1467 total_loss, 1468 total_loss * 100.0 / audio->rx_stat.pkt, 1469 0, 0.0, 1470 "", 1471 -1, -1, -1, 1472 "", 1473 (audio->rx_stat.rtcp_cnt ? audio->rx_stat.jitter_min : -1), 1474 (audio->rx_stat.rtcp_cnt ? audio->rx_stat.jitter_avg : -1), 1475 (audio->rx_stat.rtcp_cnt ? audio->rx_stat.jitter_max : -1), 1476 (audio->rx_stat.rtcp_cnt ? pj_ntohl(audio->rtcp.rtcp_pkt.rr.jitter)*1000/audio->clock_rate : -1), 1477 "" 1478 ); 1479 1480 1481 total_loss = (audio->rem_rtcp.rr.total_lost_2 << 16) + 1482 (audio->rem_rtcp.rr.total_lost_1 << 8) + 1483 audio->rem_rtcp.rr.total_lost_0; 1484 1485 printf(" TX total %s packets %sB sent (%sB +IP hdr)%s\n" 1486 " pkt discards=%d (%3.1f%%), loss=%d (%3.1f%%), reorder=%d (%3.1f%%)%s\n" 1487 " loss period min=%d ms, avg=%d ms, max=%d ms%s\n" 1488 " jitter min=%d ms, avg=%d ms, max=%d ms, current=%d ms%s\n", 1489 good_number(packets, audio->tx_stat.pkt), 1490 good_number(bytes, audio->tx_stat.payload), 1491 good_number(ipbytes, audio->tx_stat.payload + audio->tx_stat.pkt * 32), 1492 "", 1493 audio->tx_stat.discard, 1494 audio->tx_stat.discard * 100.0 / audio->tx_stat.pkt, 1495 total_loss, 1496 total_loss * 100.0 / audio->tx_stat.pkt, 1497 0, 0.0, 1498 "", 1499 -1, -1, -1, 1500 "", 1501 (audio->tx_stat.rtcp_cnt ? audio->tx_stat.jitter_min : -1), 1502 (audio->tx_stat.rtcp_cnt ? audio->tx_stat.jitter_avg : -1), 1503 (audio->tx_stat.rtcp_cnt ? audio->tx_stat.jitter_max : -1), 1504 (audio->tx_stat.rtcp_cnt ? pj_ntohl(audio->rem_rtcp.rr.jitter)*1000/audio->clock_rate : -1), 1505 "" 1506 ); 1507 1148 1508 } 1149 1509 … … 1219 1579 unsigned i; 1220 1580 1581 printf("%s", MENU); 1582 1221 1583 for (;;) { 1222 1584 printf(">>> "); fflush(stdout); … … 1244 1606 1245 1607 default: 1608 puts("Invalid command"); 1246 1609 printf("%s", MENU); 1247 1610 break; … … 1252 1615 1253 1616 on_exit: 1254 ; 1255 } 1617 hangup_all_calls(); 1618 } 1619 1620 1621 /***************************************************************************** 1622 * Below is a simple module to log all incoming and outgoing SIP messages 1623 */ 1256 1624 1257 1625 1258 1626 /* Notification on incoming messages */ 1259 static pj_bool_t console_on_rx_msg(pjsip_rx_data *rdata)1627 static pj_bool_t logger_on_rx_msg(pjsip_rx_data *rdata) 1260 1628 { 1261 1629 PJ_LOG(4,(THIS_FILE, "RX %d bytes %s from %s:%d:\n" … … 1273 1641 1274 1642 /* Notification on outgoing messages */ 1275 static pj_status_t console_on_tx_msg(pjsip_tx_data *tdata)1643 static pj_status_t logger_on_tx_msg(pjsip_tx_data *tdata) 1276 1644 { 1277 1645 … … 1306 1674 NULL, /* stop() */ 1307 1675 NULL, /* unload() */ 1308 & console_on_rx_msg, /* on_rx_request() */1309 & console_on_rx_msg, /* on_rx_response() */1310 & console_on_tx_msg, /* on_tx_request. */1311 & console_on_tx_msg, /* on_tx_response() */1676 &logger_on_rx_msg, /* on_rx_request() */ 1677 &logger_on_rx_msg, /* on_rx_response() */ 1678 &logger_on_tx_msg, /* on_tx_request. */ 1679 &logger_on_tx_msg, /* on_tx_response() */ 1312 1680 NULL, /* on_tsx_state() */ 1313 1681 … … 1315 1683 1316 1684 1685 1686 /***************************************************************************** 1687 * Console application custom logging: 1688 */ 1689 1690 1691 static FILE *log_file; 1692 1693 1694 static void app_log_writer(int level, const char *buffer, int len) 1695 { 1696 /* Write to both stdout and file. */ 1697 1698 if (level <= app.app_log_level) 1699 pj_log_write(level, buffer, len); 1700 1701 if (log_file) { 1702 fwrite(buffer, len, 1, log_file); 1703 fflush(log_file); 1704 } 1705 } 1706 1707 1708 pj_status_t app_logging_init(void) 1709 { 1710 /* Redirect log function to ours */ 1711 1712 pj_log_set_log_func( &app_log_writer ); 1713 1714 /* If output log file is desired, create the file: */ 1715 1716 if (app.log_filename) { 1717 log_file = fopen(app.log_filename, "wt"); 1718 if (log_file == NULL) { 1719 PJ_LOG(1,(THIS_FILE, "Unable to open log file %s", 1720 app.log_filename)); 1721 return -1; 1722 } 1723 } 1724 1725 return PJ_SUCCESS; 1726 } 1727 1728 1729 void app_logging_shutdown(void) 1730 { 1731 /* Close logging file, if any: */ 1732 1733 if (log_file) { 1734 fclose(log_file); 1735 log_file = NULL; 1736 } 1737 } 1317 1738 1318 1739 … … 1322 1743 int main(int argc, char *argv[]) 1323 1744 { 1745 unsigned i; 1324 1746 pj_status_t status; 1325 1747 1748 /* Must init PJLIB first */ 1326 1749 status = pj_init(); 1327 1750 if (status != PJ_SUCCESS) 1328 1751 return 1; 1329 1752 1753 /* Get command line options */ 1330 1754 status = init_options(argc, argv); 1331 1755 if (status != PJ_SUCCESS) 1332 1756 return 1; 1333 1757 1758 /* Init logging */ 1759 status = app_logging_init(); 1760 if (status != PJ_SUCCESS) 1761 return 1; 1762 1763 /* Init SIP etc */ 1334 1764 status = init_sip(); 1335 1765 if (status != PJ_SUCCESS) { … … 1339 1769 } 1340 1770 1771 /* Register module to log incoming/outgoing messages */ 1341 1772 pjsip_endpt_register_module(app.sip_endpt, &msg_logger); 1342 1773 1774 /* Init media */ 1343 1775 status = init_media(); 1344 1776 if (status != PJ_SUCCESS) { … … 1348 1780 } 1349 1781 1782 /* If URL is specified, then make call immediately */ 1350 1783 if (app.uri_to_call.slen) { 1351 1784 unsigned i; 1785 1786 PJ_LOG(3,(THIS_FILE, "Making %d calls to %s..", app.max_calls, 1787 app.uri_to_call.ptr)); 1352 1788 1353 1789 for (i=0; i<app.max_calls; ++i) { … … 1358 1794 } 1359 1795 } 1360 } 1361 1796 1797 } else { 1798 1799 PJ_LOG(3,(THIS_FILE, "Ready for incoming calls (max=%d)", 1800 app.max_calls)); 1801 } 1802 1803 /* Start worker threads */ 1804 for (i=0; i<app.thread_count; ++i) { 1805 pj_thread_create( app.pool, "app", &worker_thread, NULL, 1806 0, 0, &app.thread[i]); 1807 } 1808 1809 /* Start user interface loop */ 1362 1810 console_main(); 1363 1811 1364 1812 1813 /* Shutting down... */ 1365 1814 destroy_media(); 1366 1815 destroy_sip(); 1816 app_logging_shutdown(); 1817 1367 1818 1368 1819 return 0;
Note: See TracChangeset
for help on using the changeset viewer.