Changeset 379


Ignore:
Timestamp:
Apr 4, 2006 1:12:38 PM (18 years ago)
Author:
bennylp
Message:

Added more stats and options in siprtp samples

Location:
pjproject/trunk/pjsip-apps
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjsip-apps/build/Samples-vc.mak

    r361 r379  
    4141          $(BINDIR)\confsample.exe $(BINDIR)\sndinfo.exe \ 
    4242          $(BINDIR)\level.exe $(BINDIR)\recfile.exe  \ 
    43           $(BINDIR)\resampleplay.exe 
     43          $(BINDIR)\resampleplay.exe $(BINDIR)\siprtp.exe 
    4444 
    4545 
  • pjproject/trunk/pjsip-apps/build/Samples.mak

    r361 r379  
    3939BINDIR := ../bin/samples 
    4040 
    41 SAMPLES := simpleua playfile playsine confsample sndinfo level recfile resampleplay 
     41SAMPLES := simpleua playfile playsine confsample sndinfo level recfile resampleplay \ 
     42           siprtp 
    4243 
    4344EXES := $(foreach file, $(SAMPLES), $(BINDIR)/$(file)-$(MACHINE_NAME)-$(OS_NAME)-$(CC_NAME)$(HOST_EXE)) 
  • pjproject/trunk/pjsip-apps/src/samples/siprtp.c

    r375 r379  
    3535 
    3636 
     37/* Codec descriptor: */ 
     38struct 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: */ 
     50struct 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 
    3761/* A bidirectional media stream */ 
    3862struct media_stream 
     
    6185    pjmedia_rtcp_pkt     rem_rtcp;          /* received RTCP stat.      */ 
    6286 
     87    /* More stats: */ 
     88    struct stream_stat   rx_stat;           /* incoming stream stat     */ 
     89    struct stream_stat   tx_stat;           /* outgoing stream stat.    */ 
     90 
    6391    /* Thread: */ 
    6492    pj_bool_t            thread_quit_flag;  /* worker thread quit flag  */ 
     
    73101    unsigned             media_count; 
    74102    struct media_stream  media[2]; 
     103    pj_time_val          start_time; 
     104    pj_time_val          response_time; 
     105    pj_time_val          connect_time; 
    75106}; 
    76107 
     
    85116    pj_str_t             local_uri; 
    86117    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; 
    87124 
    88125    pj_str_t             uri_to_call; 
     
    133170static void app_perror(const char *sender, const char *title,  
    134171                       pj_status_t status); 
     172 
     173 
    135174 
    136175 
     
    158197 
    159198 
     199/* Codec constants */ 
     200struct 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 
    160210/* 
    161211 * Init SIP stack 
     
    163213static pj_status_t init_sip() 
    164214{ 
    165     unsigned i; 
    166215    pj_status_t status; 
    167216 
     
    241290    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 
    242291 
    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     } 
    249292 
    250293    /* Done */ 
     
    463506    call->inv->mod_data[mod_siprtp.id] = call; 
    464507 
     508    /* Mark start of call */ 
     509    pj_gettimeofday(&call->start_time); 
     510 
    465511 
    466512    /* Create initial INVITE request. 
     
    529575    status = pjsip_inv_create_uas( dlg, rdata, sdp, 0, &call->inv); 
    530576    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); 
    532579        return; 
    533580    } 
    534581     
     582 
    535583    /* Attach call data to invite session */ 
    536584    call->inv->mod_data[mod_siprtp.id] = call; 
     585 
     586    /* Mark start of call */ 
     587    pj_gettimeofday(&call->start_time); 
     588 
     589 
    537590 
    538591    /* Create 200 response .*/ 
    539592    status = pjsip_inv_initial_answer(call->inv, rdata, 200,  
    540593                                      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 
    542605 
    543606    /* Send the 200 response. */   
     
    563626static pj_bool_t on_rx_request( pjsip_rx_data *rdata ) 
    564627{ 
     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 
    565632    /* Respond (statelessly) any non-INVITE requests with 500  */ 
    566633    if (rdata->msg_info.msg->line.req.method.id != PJSIP_INVITE_METHOD) { 
     
    584651                                   pjsip_event *e) 
    585652{ 
     653    struct call *call = inv->mod_data[mod_siprtp.id]; 
     654 
    586655    PJ_UNUSED_ARG(e); 
    587656 
     657    if (!call) 
     658        return; 
     659 
    588660    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}; 
    593663 
    594664        call->inv = NULL; 
     
    596666 
    597667        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 
    598697    } 
    599698} 
     
    627726/* Usage */ 
    628727static const char *USAGE =  
    629 "Usage:                                                 \n" 
    630 "   siprtp [options]        => to start in server mode  \n" 
    631 "   siprtp [options] URL    => to start in client mode  \n" 
     728"Usage:\n" 
     729"   siprtp [options]        => to start in server mode\n" 
     730"   siprtp [options] URL    => to start in client mode\n" 
    632731"\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" 
    638739"                           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" 
    639752; 
    640753 
     
    646759    static char local_uri[64]; 
    647760 
     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 
    648765    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 
    653780        { NULL, 0, 0, 0 }, 
    654781    }; 
     
    668795    } 
    669796 
    670     /* Init default */ 
     797    /* Init defaults */ 
    671798    app.max_calls = 1; 
    672799    app.thread_count = 1; 
     
    674801    app.rtp_start_port = 4000; 
    675802    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]; 
    676809 
    677810    /* Parse options */ 
    678811    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:",  
    680813                            long_options, &option_index))!=-1)  
    681814    { 
     
    697830            app.local_addr = pj_optarg; 
    698831            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 
    699859        default: 
    700860            puts(USAGE); 
     
    717877 
    718878 
    719 ////////////////////////////////////////////////////////////////////////////// 
    720 /* 
     879/***************************************************************************** 
    721880 * MEDIA STUFFS 
    722881 */ 
     
    781940        pjmedia_sdp_rtpmap rtpmap; 
    782941        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); 
    790949        rtpmap.param.slen = 0; 
    791950 
     
    803962     * Add support telephony event 
    804963     */ 
    805     m->desc.fmt[m->desc.fmt_count++] = pj_str("101"); 
     964    m->desc.fmt[m->desc.fmt_count++] = pj_str("121"); 
    806965    /* Add rtpmap. */ 
    807966    attr = pj_pool_zalloc(pool, sizeof(pjmedia_sdp_attr)); 
    808967    attr->name = pj_str("rtpmap"); 
    809     attr->value = pj_str(":101 telephone-event/8000"); 
     968    attr->value = pj_str(":121 telephone-event/8000"); 
    810969    m->attr[m->attr_count++] = attr; 
    811970    /* Add fmtp */ 
    812971    attr = pj_pool_zalloc(pool, sizeof(pjmedia_sdp_attr)); 
    813972    attr->name = pj_str("fmtp"); 
    814     attr->value = pj_str(":101 0-15"); 
     973    attr->value = pj_str(":121 0-15"); 
    815974    m->attr[m->attr_count++] = attr; 
    816975#endif 
     
    823982 
    824983 
    825 /* Media thread */ 
     984/*  
     985 * Media thread  
     986 * 
     987 * This is the thread to send and receive both RTP and RTCP packets. 
     988 */ 
    826989static int media_thread(void *arg) 
    827990{ 
     
    8811044            } 
    8821045 
     1046            ++strm->rx_stat.pkt; 
     1047            strm->rx_stat.payload += (size - 12); 
     1048 
    8831049            /* Decode RTP packet. */ 
    8841050            status = pjmedia_rtp_decode_rtp(&strm->in_sess,  
     
    8881054            if (status != PJ_SUCCESS) { 
    8891055                app_perror(THIS_FILE, "RTP decode error", status); 
     1056                strm->rx_stat.discard++; 
    8901057                continue; 
    8911058            } 
     
    9001067                PJ_LOG(3,(THIS_FILE,"RTP packet detail: pt=%d, seq=%d", 
    9011068                          hdr->pt, pj_ntohs(hdr->seq))); 
     1069                strm->rx_stat.discard++; 
    9021070                continue; 
    9031071            } 
     
    9201088                app_perror(THIS_FILE, "Error receiving RTCP packet", status); 
    9211089            else { 
    922                 if (size > sizeof(strm->rem_rtcp)) 
     1090                if (size > sizeof(strm->rem_rtcp)) { 
    9231091                    PJ_LOG(3,(THIS_FILE, "Error: RTCP packet too large")); 
    924                 else 
     1092                    status = -1; 
     1093                } else { 
    9251094                    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++; 
    9261113            } 
    9271114        } 
     
    9701157            next_rtp.msec += strm->samples_per_frame * 1000 / strm->clock_rate; 
    9711158            pj_time_val_normalize(&next_rtp); 
     1159 
     1160            /* Update stats */ 
     1161            strm->tx_stat.pkt++; 
     1162            strm->tx_stat.payload += strm->bytes_per_frame; 
    9721163        } 
    9731164 
     
    10021193             
    10031194 
     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 
    10041211            next_rtcp.sec += 5; 
    10051212        } 
     
    10191226    struct media_stream *audio; 
    10201227    pjmedia_sdp_session *local_sdp, *remote_sdp; 
    1021  
     1228    struct codec *codec_desc = NULL; 
     1229    unsigned i; 
    10221230 
    10231231    call = inv->mod_data[mod_siprtp.id]; 
     
    10481256    } 
    10491257 
     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    } 
    10501275 
    10511276    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; 
    10551279 
    10561280 
     
    10591283    pjmedia_rtp_session_init(&audio->in_sess, audio->si.fmt.pt, 0); 
    10601284    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 
    10611291 
    10621292    /* Start media thread. */ 
     
    10821312        audio->thread = NULL; 
    10831313        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/***************************************************************************** 
    10901347 * USER INTERFACE STUFFS 
    10911348 */ 
     
    11111368static void print_call(int call_index) 
    11121369{ 
     1370    struct call *call = &app.call[call_index]; 
    11131371    int len; 
    1114     pjsip_inv_session *inv = app.call[call_index].inv; 
     1372    pjsip_inv_session *inv = call->inv; 
    11151373    pjsip_dialog *dlg = inv->dlg; 
    1116     struct media_stream *audio = &app.call[call_index].media[0]; 
     1374    struct media_stream *audio = &call->media[0]; 
    11171375    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 */ 
    11221407    len = pjsip_hdr_print_on(dlg->remote.info, userinfo, sizeof(userinfo)); 
    11231408    if (len < 1) 
     
    11251410    else 
    11261411        userinfo[len] = '\0'; 
    1127      
    1128     printf("Call #%d: %s\n", call_index, pjsip_inv_state_name(inv->state)); 
     1412 
    11291413    printf("   %s\n", userinfo); 
    11301414 
    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) { 
    11321442        return; 
    11331443    } 
    11341444 
    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", 
    11361446           (int)audio->si.fmt.encoding_name.slen, 
    11371447           audio->si.fmt.encoding_name.ptr, 
    11381448           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 
    11481508} 
    11491509 
     
    12191579    unsigned i; 
    12201580 
     1581    printf("%s", MENU); 
     1582 
    12211583    for (;;) { 
    12221584        printf(">>> "); fflush(stdout); 
     
    12441606 
    12451607        default: 
     1608            puts("Invalid command"); 
    12461609            printf("%s", MENU); 
    12471610            break; 
     
    12521615 
    12531616on_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 */ 
    12561624 
    12571625 
    12581626/* Notification on incoming messages */ 
    1259 static pj_bool_t console_on_rx_msg(pjsip_rx_data *rdata) 
     1627static pj_bool_t logger_on_rx_msg(pjsip_rx_data *rdata) 
    12601628{ 
    12611629    PJ_LOG(4,(THIS_FILE, "RX %d bytes %s from %s:%d:\n" 
     
    12731641 
    12741642/* Notification on outgoing messages */ 
    1275 static pj_status_t console_on_tx_msg(pjsip_tx_data *tdata) 
     1643static pj_status_t logger_on_tx_msg(pjsip_tx_data *tdata) 
    12761644{ 
    12771645     
     
    13061674    NULL,                               /* stop()               */ 
    13071675    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()     */ 
    13121680    NULL,                               /* on_tsx_state()       */ 
    13131681 
     
    13151683 
    13161684 
     1685 
     1686/***************************************************************************** 
     1687 * Console application custom logging: 
     1688 */ 
     1689 
     1690 
     1691static FILE *log_file; 
     1692 
     1693 
     1694static 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 
     1708pj_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 
     1729void 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} 
    13171738 
    13181739 
     
    13221743int main(int argc, char *argv[]) 
    13231744{ 
     1745    unsigned i; 
    13241746    pj_status_t status; 
    13251747 
     1748    /* Must init PJLIB first */ 
    13261749    status = pj_init(); 
    13271750    if (status != PJ_SUCCESS) 
    13281751        return 1; 
    13291752 
     1753    /* Get command line options */ 
    13301754    status = init_options(argc, argv); 
    13311755    if (status != PJ_SUCCESS) 
    13321756        return 1; 
    13331757 
     1758    /* Init logging */ 
     1759    status = app_logging_init(); 
     1760    if (status != PJ_SUCCESS) 
     1761        return 1; 
     1762 
     1763    /* Init SIP etc */ 
    13341764    status = init_sip(); 
    13351765    if (status != PJ_SUCCESS) { 
     
    13391769    } 
    13401770 
     1771    /* Register module to log incoming/outgoing messages */ 
    13411772    pjsip_endpt_register_module(app.sip_endpt, &msg_logger); 
    13421773 
     1774    /* Init media */ 
    13431775    status = init_media(); 
    13441776    if (status != PJ_SUCCESS) { 
     
    13481780    } 
    13491781 
     1782    /* If URL is specified, then make call immediately */ 
    13501783    if (app.uri_to_call.slen) { 
    13511784        unsigned i; 
     1785 
     1786        PJ_LOG(3,(THIS_FILE, "Making %d calls to %s..", app.max_calls, 
     1787                  app.uri_to_call.ptr)); 
    13521788 
    13531789        for (i=0; i<app.max_calls; ++i) { 
     
    13581794            } 
    13591795        } 
    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 */ 
    13621810    console_main(); 
    13631811 
    1364  
     1812     
     1813    /* Shutting down... */ 
    13651814    destroy_media(); 
    13661815    destroy_sip(); 
     1816    app_logging_shutdown(); 
     1817 
    13671818 
    13681819    return 0; 
Note: See TracChangeset for help on using the changeset viewer.