Ignore:
Timestamp:
Jul 7, 2011 7:46:33 AM (13 years ago)
Author:
bennylp
Message:

Initial commit re #1263 (PJSUA-LIB Video API):

  • API designed and reviewed (pjsua.h)
  • Implemented these APIs and added to pjsua sample application:
    • video device enums API
    • video capture preview API
  • refactoring in PJSUA-LIB:
    • video stuffs go to pjsua_vid.c
    • call dump goes to pjsua_dump.c

We're still missing:

  • video call API implementation
  • media info and statistic API implementation
File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/branches/projects/2.0-dev/pjsip/src/pjsua-lib/pjsua_call.c

    r3573 r3609  
    11171117 
    11181118 
    1119 #if DISABLED_FOR_TICKET_1185 
    1120 /* 
    1121  * Retrieve the media session associated with this call. 
    1122  */ 
    1123 PJ_DEF(pjmedia_session*) pjsua_call_get_media_session(pjsua_call_id call_id) 
    1124 { 
    1125     PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls,  
    1126                      NULL); 
    1127     return pjsua_var.calls[call_id].session; 
    1128 } 
    1129  
    1130  
    1131 /* 
    1132  * Retrieve the media transport instance that is used for this call. 
    1133  */ 
    1134 PJ_DEF(pjmedia_transport*) pjsua_call_get_media_transport(pjsua_call_id cid) 
    1135 { 
    1136     PJ_ASSERT_RETURN(cid>=0 && cid<(int)pjsua_var.ua_cfg.max_calls,  
    1137                      NULL); 
    1138     return pjsua_var.calls[cid].tp; 
    1139 } 
    1140 #endif /* Removed in 2.0 */ 
    1141  
    11421119/* Acquire lock to the specified call_id */ 
    11431120pj_status_t acquire_call(const char *title, 
     
    13371314 
    13381315        if (call_med->type == PJMEDIA_TYPE_AUDIO) { 
    1339             info->media[info->media_cnt].stream.audio.conf_slot =  
     1316            info->media[info->media_cnt].stream.aud.conf_slot = 
    13401317                                                call_med->strm.a.conf_slot; 
    13411318        } else if (call_med->type == PJMEDIA_TYPE_VIDEO) { 
    1342             info->media[info->media_cnt].stream.video.capturer = 
    1343                                                 call_med->strm.v.capturer; 
    1344             info->media[info->media_cnt].stream.video.renderer = 
    1345                                                 call_med->strm.v.renderer; 
     1319            PJ_TODO(vid_fill_in_call_info); 
     1320            info->media[info->media_cnt].stream.vid.win_in = PJSUA_INVALID_ID; 
     1321            info->media[info->media_cnt].stream.vid.cap_dev = 
     1322                    PJMEDIA_VID_INVALID_DEV; 
    13461323        } else { 
    13471324            continue; 
     
    21832160} 
    21842161 
    2185  
    2186 const char *good_number(char *buf, pj_int32_t val) 
    2187 { 
    2188     if (val < 1000) { 
    2189         pj_ansi_sprintf(buf, "%d", val); 
    2190     } else if (val < 1000000) { 
    2191         pj_ansi_sprintf(buf, "%d.%dK",  
    2192                         val / 1000, 
    2193                         (val % 1000) / 100); 
    2194     } else { 
    2195         pj_ansi_sprintf(buf, "%d.%02dM",  
    2196                         val / 1000000, 
    2197                         (val % 1000000) / 10000); 
    2198     } 
    2199  
    2200     return buf; 
    2201 } 
    2202  
    2203 static unsigned dump_media_stat(const char *indent,  
    2204                                 char *buf, unsigned maxlen, 
    2205                                 const pjmedia_rtcp_stat *stat, 
    2206                                 const char *rx_info, const char *tx_info) 
    2207 { 
    2208     char last_update[64]; 
    2209     char packets[32], bytes[32], ipbytes[32], avg_bps[32], avg_ipbps[32]; 
    2210     pj_time_val media_duration, now; 
    2211     char *p = buf, *end = buf+maxlen; 
    2212     int len; 
    2213  
    2214     if (stat->rx.update_cnt == 0) 
    2215         strcpy(last_update, "never"); 
    2216     else { 
    2217         pj_gettimeofday(&now); 
    2218         PJ_TIME_VAL_SUB(now, stat->rx.update); 
    2219         sprintf(last_update, "%02ldh:%02ldm:%02ld.%03lds ago", 
    2220                 now.sec / 3600, 
    2221                 (now.sec % 3600) / 60, 
    2222                 now.sec % 60, 
    2223                 now.msec); 
    2224     } 
    2225  
    2226     pj_gettimeofday(&media_duration); 
    2227     PJ_TIME_VAL_SUB(media_duration, stat->start); 
    2228     if (PJ_TIME_VAL_MSEC(media_duration) == 0) 
    2229         media_duration.msec = 1; 
    2230  
    2231     len = pj_ansi_snprintf(p, end-p, 
    2232            "%s     RX %s last update:%s\n" 
    2233            "%s        total %spkt %sB (%sB +IP hdr) @avg=%sbps/%sbps\n" 
    2234            "%s        pkt loss=%d (%3.1f%%), discrd=%d (%3.1f%%), dup=%d (%2.1f%%), reord=%d (%3.1f%%)\n" 
    2235            "%s              (msec)    min     avg     max     last    dev\n" 
    2236            "%s        loss period: %7.3f %7.3f %7.3f %7.3f %7.3f\n" 
    2237            "%s        jitter     : %7.3f %7.3f %7.3f %7.3f %7.3f\n" 
    2238 #if defined(PJMEDIA_RTCP_STAT_HAS_RAW_JITTER) && PJMEDIA_RTCP_STAT_HAS_RAW_JITTER!=0 
    2239            "%s        raw jitter : %7.3f %7.3f %7.3f %7.3f %7.3f\n" 
    2240 #endif 
    2241 #if defined(PJMEDIA_RTCP_STAT_HAS_IPDV) && PJMEDIA_RTCP_STAT_HAS_IPDV!=0 
    2242            "%s        IPDV       : %7.3f %7.3f %7.3f %7.3f %7.3f\n" 
    2243 #endif 
    2244            "%s", 
    2245            indent, 
    2246            rx_info? rx_info : "", 
    2247            last_update, 
    2248  
    2249            indent, 
    2250            good_number(packets, stat->rx.pkt), 
    2251            good_number(bytes, stat->rx.bytes), 
    2252            good_number(ipbytes, stat->rx.bytes + stat->rx.pkt * 40), 
    2253            good_number(avg_bps, (pj_int32_t)((pj_int64_t)stat->rx.bytes * 8 * 1000 / PJ_TIME_VAL_MSEC(media_duration))), 
    2254            good_number(avg_ipbps, (pj_int32_t)(((pj_int64_t)stat->rx.bytes + stat->rx.pkt * 40) * 8 * 1000 / PJ_TIME_VAL_MSEC(media_duration))), 
    2255            indent, 
    2256            stat->rx.loss, 
    2257            (stat->rx.loss? stat->rx.loss * 100.0 / (stat->rx.pkt + stat->rx.loss) : 0), 
    2258            stat->rx.discard,  
    2259            (stat->rx.discard? stat->rx.discard * 100.0 / (stat->rx.pkt + stat->rx.loss) : 0), 
    2260            stat->rx.dup,  
    2261            (stat->rx.dup? stat->rx.dup * 100.0 / (stat->rx.pkt + stat->rx.loss) : 0), 
    2262            stat->rx.reorder,  
    2263            (stat->rx.reorder? stat->rx.reorder * 100.0 / (stat->rx.pkt + stat->rx.loss) : 0), 
    2264            indent, indent, 
    2265            stat->rx.loss_period.min / 1000.0,  
    2266            stat->rx.loss_period.mean / 1000.0,  
    2267            stat->rx.loss_period.max / 1000.0, 
    2268            stat->rx.loss_period.last / 1000.0, 
    2269            pj_math_stat_get_stddev(&stat->rx.loss_period) / 1000.0, 
    2270            indent, 
    2271            stat->rx.jitter.min / 1000.0, 
    2272            stat->rx.jitter.mean / 1000.0, 
    2273            stat->rx.jitter.max / 1000.0, 
    2274            stat->rx.jitter.last / 1000.0, 
    2275            pj_math_stat_get_stddev(&stat->rx.jitter) / 1000.0, 
    2276 #if defined(PJMEDIA_RTCP_STAT_HAS_RAW_JITTER) && PJMEDIA_RTCP_STAT_HAS_RAW_JITTER!=0 
    2277            indent, 
    2278            stat->rx_raw_jitter.min / 1000.0, 
    2279            stat->rx_raw_jitter.mean / 1000.0, 
    2280            stat->rx_raw_jitter.max / 1000.0, 
    2281            stat->rx_raw_jitter.last / 1000.0, 
    2282            pj_math_stat_get_stddev(&stat->rx_raw_jitter) / 1000.0, 
    2283 #endif 
    2284 #if defined(PJMEDIA_RTCP_STAT_HAS_IPDV) && PJMEDIA_RTCP_STAT_HAS_IPDV!=0 
    2285            indent, 
    2286            stat->rx_ipdv.min / 1000.0, 
    2287            stat->rx_ipdv.mean / 1000.0, 
    2288            stat->rx_ipdv.max / 1000.0, 
    2289            stat->rx_ipdv.last / 1000.0, 
    2290            pj_math_stat_get_stddev(&stat->rx_ipdv) / 1000.0, 
    2291 #endif 
    2292            "" 
    2293            ); 
    2294  
    2295     if (len < 1 || len > end-p) { 
    2296         *p = '\0'; 
    2297         return (p-buf); 
    2298     } 
    2299     p += len; 
    2300  
    2301     if (stat->tx.update_cnt == 0) 
    2302         strcpy(last_update, "never"); 
    2303     else { 
    2304         pj_gettimeofday(&now); 
    2305         PJ_TIME_VAL_SUB(now, stat->tx.update); 
    2306         sprintf(last_update, "%02ldh:%02ldm:%02ld.%03lds ago", 
    2307                 now.sec / 3600, 
    2308                 (now.sec % 3600) / 60, 
    2309                 now.sec % 60, 
    2310                 now.msec); 
    2311     } 
    2312  
    2313     len = pj_ansi_snprintf(p, end-p, 
    2314            "%s     TX %s last update:%s\n" 
    2315            "%s        total %spkt %sB (%sB +IP hdr) @avg %sbps/%sbps\n" 
    2316            "%s        pkt loss=%d (%3.1f%%), dup=%d (%3.1f%%), reorder=%d (%3.1f%%)\n" 
    2317            "%s              (msec)    min     avg     max     last    dev \n" 
    2318            "%s        loss period: %7.3f %7.3f %7.3f %7.3f %7.3f\n" 
    2319            "%s        jitter     : %7.3f %7.3f %7.3f %7.3f %7.3f\n", 
    2320            indent, 
    2321            tx_info, 
    2322            last_update, 
    2323  
    2324            indent, 
    2325            good_number(packets, stat->tx.pkt), 
    2326            good_number(bytes, stat->tx.bytes), 
    2327            good_number(ipbytes, stat->tx.bytes + stat->tx.pkt * 40), 
    2328            good_number(avg_bps, (pj_int32_t)((pj_int64_t)stat->tx.bytes * 8 * 1000 / PJ_TIME_VAL_MSEC(media_duration))), 
    2329            good_number(avg_ipbps, (pj_int32_t)(((pj_int64_t)stat->tx.bytes + stat->tx.pkt * 40) * 8 * 1000 / PJ_TIME_VAL_MSEC(media_duration))), 
    2330  
    2331            indent, 
    2332            stat->tx.loss, 
    2333            (stat->tx.loss? stat->tx.loss * 100.0 / (stat->tx.pkt + stat->tx.loss) : 0), 
    2334            stat->tx.dup,  
    2335            (stat->tx.dup? stat->tx.dup * 100.0 / (stat->tx.pkt + stat->tx.loss) : 0), 
    2336            stat->tx.reorder,  
    2337            (stat->tx.reorder? stat->tx.reorder * 100.0 / (stat->tx.pkt + stat->tx.loss) : 0), 
    2338  
    2339            indent, indent, 
    2340            stat->tx.loss_period.min / 1000.0,  
    2341            stat->tx.loss_period.mean / 1000.0,  
    2342            stat->tx.loss_period.max / 1000.0, 
    2343            stat->tx.loss_period.last / 1000.0, 
    2344            pj_math_stat_get_stddev(&stat->tx.loss_period) / 1000.0, 
    2345            indent, 
    2346            stat->tx.jitter.min / 1000.0, 
    2347            stat->tx.jitter.mean / 1000.0, 
    2348            stat->tx.jitter.max / 1000.0, 
    2349            stat->tx.jitter.last / 1000.0, 
    2350            pj_math_stat_get_stddev(&stat->tx.jitter) / 1000.0 
    2351            ); 
    2352  
    2353     if (len < 1 || len > end-p) { 
    2354         *p = '\0'; 
    2355         return (p-buf); 
    2356     } 
    2357     p += len; 
    2358  
    2359     len = pj_ansi_snprintf(p, end-p, 
    2360            "%s     RTT msec      : %7.3f %7.3f %7.3f %7.3f %7.3f\n", 
    2361            indent, 
    2362            stat->rtt.min / 1000.0, 
    2363            stat->rtt.mean / 1000.0, 
    2364            stat->rtt.max / 1000.0, 
    2365            stat->rtt.last / 1000.0, 
    2366            pj_math_stat_get_stddev(&stat->rtt) / 1000.0 
    2367            ); 
    2368     if (len < 1 || len > end-p) { 
    2369         *p = '\0'; 
    2370         return (p-buf); 
    2371     } 
    2372     p += len; 
    2373  
    2374     return (p-buf); 
    2375 } 
    2376  
    2377  
    2378 /* Dump media session */ 
    2379 static void dump_media_session(const char *indent,  
    2380                                char *buf, unsigned maxlen, 
    2381                                pjsua_call *call) 
    2382 { 
    2383     unsigned i; 
    2384     char *p = buf, *end = buf+maxlen; 
    2385     int len; 
    2386  
    2387     for (i=0; i<call->med_cnt; ++i) { 
    2388         pjsua_call_media *call_med = &call->media[i]; 
    2389         pjmedia_rtcp_stat stat; 
    2390         pj_bool_t has_stat; 
    2391         pjmedia_transport_info tp_info; 
    2392         char rem_addr_buf[80]; 
    2393         char codec_info[32] = {'0'}; 
    2394         char rx_info[80] = {'\0'}; 
    2395         char tx_info[80] = {'\0'}; 
    2396         const char *rem_addr; 
    2397         const char *dir_str; 
    2398         const char *media_type_str; 
    2399  
    2400         switch (call_med->type) { 
    2401         case PJMEDIA_TYPE_AUDIO: 
    2402             media_type_str = "audio"; 
    2403             break; 
    2404         case PJMEDIA_TYPE_VIDEO: 
    2405             media_type_str = "video"; 
    2406             break; 
    2407         case PJMEDIA_TYPE_APPLICATION: 
    2408             media_type_str = "application"; 
    2409             break; 
    2410         default: 
    2411             media_type_str = "unknown"; 
    2412             break; 
    2413         } 
    2414  
    2415         /* Check if the stream is deactivated */ 
    2416         if (call_med->tp == NULL || 
    2417             (!call_med->strm.a.stream && !call_med->strm.v.stream)) 
    2418         { 
    2419             len = pj_ansi_snprintf(p, end-p, 
    2420                       "%s #%d %s deactivated\n", 
    2421                       indent, i, media_type_str); 
    2422             if (len < 1 || len > end-p) { 
    2423                 *p = '\0'; 
    2424                 return; 
    2425             } 
    2426  
    2427             p += len; 
    2428             continue; 
    2429         } 
    2430  
    2431         pjmedia_transport_info_init(&tp_info); 
    2432         pjmedia_transport_get_info(call_med->tp, &tp_info); 
    2433  
    2434         // rem_addr will contain actual address of RTP originator, instead of 
    2435         // remote RTP address specified by stream which is fetched from the SDP. 
    2436         // Please note that we are assuming only one stream per call. 
    2437         //rem_addr = pj_sockaddr_print(&info.stream_info[i].rem_addr, 
    2438         //                           rem_addr_buf, sizeof(rem_addr_buf), 3); 
    2439         if (pj_sockaddr_has_addr(&tp_info.src_rtp_name)) { 
    2440             rem_addr = pj_sockaddr_print(&tp_info.src_rtp_name, rem_addr_buf,  
    2441                                          sizeof(rem_addr_buf), 3); 
    2442         } else { 
    2443             pj_ansi_snprintf(rem_addr_buf, sizeof(rem_addr_buf), "-"); 
    2444             rem_addr = rem_addr_buf; 
    2445         } 
    2446  
    2447         if (call_med->dir == PJMEDIA_DIR_NONE) { 
    2448             /* To handle when the stream that is currently being paused 
    2449              * (http://trac.pjsip.org/repos/ticket/1079) 
    2450              */ 
    2451             dir_str = "inactive"; 
    2452         } else if (call_med->dir == PJMEDIA_DIR_ENCODING) 
    2453             dir_str = "sendonly"; 
    2454         else if (call_med->dir == PJMEDIA_DIR_DECODING) 
    2455             dir_str = "recvonly"; 
    2456         else if (call_med->dir == PJMEDIA_DIR_ENCODING_DECODING) 
    2457             dir_str = "sendrecv"; 
    2458         else 
    2459             dir_str = "inactive"; 
    2460  
    2461         if (call_med->type == PJMEDIA_TYPE_AUDIO) { 
    2462             pjmedia_stream *stream = call_med->strm.a.stream; 
    2463             pjmedia_stream_info info; 
    2464  
    2465             pjmedia_stream_get_stat(stream, &stat); 
    2466             has_stat = PJ_TRUE; 
    2467  
    2468             pjmedia_stream_get_info(stream, &info); 
    2469             pj_ansi_snprintf(codec_info, sizeof(codec_info), " %.*s @%dkHz", 
    2470                              (int)info.fmt.encoding_name.slen, 
    2471                              info.fmt.encoding_name.ptr, 
    2472                              info.fmt.clock_rate / 1000); 
    2473             pj_ansi_snprintf(rx_info, sizeof(rx_info), "pt=%d,", 
    2474                              info.fmt.pt); 
    2475             pj_ansi_snprintf(tx_info, sizeof(tx_info), "pt=%d, ptime=%d,", 
    2476                              info.tx_pt, 
    2477                              info.param->setting.frm_per_pkt* 
    2478                              info.param->info.frm_ptime); 
    2479         } else if (call_med->type == PJMEDIA_TYPE_VIDEO) { 
    2480             pjmedia_vid_stream *stream = call_med->strm.v.stream; 
    2481             pjmedia_vid_stream_info info; 
    2482  
    2483             pjmedia_vid_stream_get_stat(stream, &stat); 
    2484             has_stat = PJ_TRUE; 
    2485  
    2486             pjmedia_vid_stream_get_info(stream, &info); 
    2487             pj_ansi_snprintf(codec_info, sizeof(codec_info), " %.*s", 
    2488                              (int)info.codec_info.encoding_name.slen, 
    2489                              info.codec_info.encoding_name.ptr); 
    2490             if (call_med->dir & PJMEDIA_DIR_DECODING) { 
    2491                 pjmedia_video_format_detail *vfd; 
    2492                 vfd = pjmedia_format_get_video_format_detail( 
    2493                                         &info.codec_param->dec_fmt, PJ_TRUE); 
    2494                 pj_ansi_snprintf(rx_info, sizeof(rx_info), 
    2495                                  "pt=%d, size=%dx%d, fps=%.2f,", 
    2496                                  info.rx_pt, 
    2497                                  vfd->size.w, vfd->size.h, 
    2498                                  vfd->fps.num*1.0/vfd->fps.denum); 
    2499             } 
    2500             if (call_med->dir & PJMEDIA_DIR_ENCODING) { 
    2501                 pjmedia_video_format_detail *vfd; 
    2502                 vfd = pjmedia_format_get_video_format_detail( 
    2503                                         &info.codec_param->enc_fmt, PJ_TRUE); 
    2504                 pj_ansi_snprintf(tx_info, sizeof(tx_info), 
    2505                                  "pt=%d, size=%dx%d, fps=%.2f,", 
    2506                                  info.tx_pt, 
    2507                                  vfd->size.w, vfd->size.h, 
    2508                                  vfd->fps.num*1.0/vfd->fps.denum); 
    2509             } 
    2510         } else { 
    2511             has_stat = PJ_FALSE; 
    2512         } 
    2513  
    2514         len = pj_ansi_snprintf(p, end-p, 
    2515                   "%s  #%d %s%s, %s, peer=%s\n", 
    2516                   indent, 
    2517                   call_med->idx, 
    2518                   media_type_str, 
    2519                   codec_info, 
    2520                   dir_str, 
    2521                   rem_addr); 
    2522         if (len < 1 || len > end-p) { 
    2523             *p = '\0'; 
    2524             return; 
    2525         } 
    2526         p += len; 
    2527  
    2528         /* Get and ICE SRTP status */ 
    2529         if (call_med->tp) { 
    2530             pjmedia_transport_info tp_info; 
    2531  
    2532             pjmedia_transport_info_init(&tp_info); 
    2533             pjmedia_transport_get_info(call_med->tp, &tp_info); 
    2534             if (tp_info.specific_info_cnt > 0) { 
    2535                 unsigned j; 
    2536                 for (j = 0; j < tp_info.specific_info_cnt; ++j) { 
    2537                     if (tp_info.spc_info[j].type == PJMEDIA_TRANSPORT_TYPE_SRTP) 
    2538                     { 
    2539                         pjmedia_srtp_info *srtp_info = 
    2540                                     (pjmedia_srtp_info*) tp_info.spc_info[j].buffer; 
    2541  
    2542                         len = pj_ansi_snprintf(p, end-p, 
    2543                                                "   %s  SRTP status: %s Crypto-suite: %s", 
    2544                                                indent, 
    2545                                                (srtp_info->active?"Active":"Not active"), 
    2546                                                srtp_info->tx_policy.name.ptr); 
    2547                         if (len > 0 && len < end-p) { 
    2548                             p += len; 
    2549                             *p++ = '\n'; 
    2550                             *p = '\0'; 
    2551                         } 
    2552                     } else if (tp_info.spc_info[j].type==PJMEDIA_TRANSPORT_TYPE_ICE) { 
    2553                         const pjmedia_ice_transport_info *ii; 
    2554  
    2555                         ii = (const pjmedia_ice_transport_info*) 
    2556                              tp_info.spc_info[j].buffer; 
    2557  
    2558                         len = pj_ansi_snprintf(p, end-p, 
    2559                                                "   %s  ICE role: %s, state: %s, comp_cnt: %u", 
    2560                                                indent, 
    2561                                                pj_ice_sess_role_name(ii->role), 
    2562                                                pj_ice_strans_state_name(ii->sess_state), 
    2563                                                ii->comp_cnt); 
    2564                         if (len > 0 && len < end-p) { 
    2565                             p += len; 
    2566                             *p++ = '\n'; 
    2567                             *p = '\0'; 
    2568                         } 
    2569                     } 
    2570                 } 
    2571             } 
    2572         } 
    2573  
    2574  
    2575         if (has_stat) { 
    2576             len = dump_media_stat(indent, p, end-p, &stat, 
    2577                                   rx_info, tx_info); 
    2578             p += len; 
    2579         } 
    2580  
    2581 #if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0) 
    2582 #   define SAMPLES_TO_USEC(usec, samples, clock_rate) \ 
    2583         do { \ 
    2584             if (samples <= 4294) \ 
    2585                 usec = samples * 1000000 / clock_rate; \ 
    2586             else { \ 
    2587                 usec = samples * 1000 / clock_rate; \ 
    2588                 usec *= 1000; \ 
    2589             } \ 
    2590         } while(0) 
    2591  
    2592 #   define PRINT_VOIP_MTC_VAL(s, v) \ 
    2593         if (v == 127) \ 
    2594             sprintf(s, "(na)"); \ 
    2595         else \ 
    2596             sprintf(s, "%d", v) 
    2597  
    2598 #   define VALIDATE_PRINT_BUF() \ 
    2599         if (len < 1 || len > end-p) { *p = '\0'; return; } \ 
    2600         p += len; *p++ = '\n'; *p = '\0' 
    2601  
    2602  
    2603         if (call_med->type == PJMEDIA_TYPE_AUDIO) { 
    2604             pjmedia_stream_info info; 
    2605             char last_update[64]; 
    2606             char loss[16], dup[16]; 
    2607             char jitter[80]; 
    2608             char toh[80]; 
    2609             char plc[16], jba[16], jbr[16]; 
    2610             char signal_lvl[16], noise_lvl[16], rerl[16]; 
    2611             char r_factor[16], ext_r_factor[16], mos_lq[16], mos_cq[16]; 
    2612             pjmedia_rtcp_xr_stat xr_stat; 
    2613             unsigned clock_rate; 
    2614             pj_time_val now; 
    2615  
    2616             if (pjmedia_stream_get_stat_xr(call_med->strm.a.stream, 
    2617                                            &xr_stat) != PJ_SUCCESS) 
    2618             { 
    2619                 continue; 
    2620             } 
    2621  
    2622             if (pjmedia_stream_get_info(call_med->strm.a.stream, &info) 
    2623                     != PJ_SUCCESS) 
    2624             { 
    2625                 continue; 
    2626             } 
    2627  
    2628             clock_rate = info.fmt.clock_rate; 
    2629             pj_gettimeofday(&now); 
    2630  
    2631             len = pj_ansi_snprintf(p, end-p, "\n%s  Extended reports:", indent); 
    2632             VALIDATE_PRINT_BUF(); 
    2633  
    2634             /* Statistics Summary */ 
    2635             len = pj_ansi_snprintf(p, end-p, "%s   Statistics Summary", indent); 
    2636             VALIDATE_PRINT_BUF(); 
    2637  
    2638             if (xr_stat.rx.stat_sum.l) 
    2639                 sprintf(loss, "%d", xr_stat.rx.stat_sum.lost); 
    2640             else 
    2641                 sprintf(loss, "(na)"); 
    2642  
    2643             if (xr_stat.rx.stat_sum.d) 
    2644                 sprintf(dup, "%d", xr_stat.rx.stat_sum.dup); 
    2645             else 
    2646                 sprintf(dup, "(na)"); 
    2647  
    2648             if (xr_stat.rx.stat_sum.j) { 
    2649                 unsigned jmin, jmax, jmean, jdev; 
    2650  
    2651                 SAMPLES_TO_USEC(jmin, xr_stat.rx.stat_sum.jitter.min,  
    2652                                 clock_rate); 
    2653                 SAMPLES_TO_USEC(jmax, xr_stat.rx.stat_sum.jitter.max,  
    2654                                 clock_rate); 
    2655                 SAMPLES_TO_USEC(jmean, xr_stat.rx.stat_sum.jitter.mean,  
    2656                                 clock_rate); 
    2657                 SAMPLES_TO_USEC(jdev,  
    2658                                pj_math_stat_get_stddev(&xr_stat.rx.stat_sum.jitter), 
    2659                                clock_rate); 
    2660                 sprintf(jitter, "%7.3f %7.3f %7.3f %7.3f",  
    2661                         jmin/1000.0, jmean/1000.0, jmax/1000.0, jdev/1000.0); 
    2662             } else 
    2663                 sprintf(jitter, "(report not available)"); 
    2664  
    2665             if (xr_stat.rx.stat_sum.t) { 
    2666                 sprintf(toh, "%11d %11d %11d %11d",  
    2667                         xr_stat.rx.stat_sum.toh.min, 
    2668                         xr_stat.rx.stat_sum.toh.mean, 
    2669                         xr_stat.rx.stat_sum.toh.max, 
    2670                         pj_math_stat_get_stddev(&xr_stat.rx.stat_sum.toh)); 
    2671             } else 
    2672                 sprintf(toh, "(report not available)"); 
    2673  
    2674             if (xr_stat.rx.stat_sum.update.sec == 0) 
    2675                 strcpy(last_update, "never"); 
    2676             else { 
    2677                 pj_gettimeofday(&now); 
    2678                 PJ_TIME_VAL_SUB(now, xr_stat.rx.stat_sum.update); 
    2679                 sprintf(last_update, "%02ldh:%02ldm:%02ld.%03lds ago", 
    2680                         now.sec / 3600, 
    2681                         (now.sec % 3600) / 60, 
    2682                         now.sec % 60, 
    2683                         now.msec); 
    2684             } 
    2685  
    2686             len = pj_ansi_snprintf(p, end-p,  
    2687                     "%s     RX last update: %s\n" 
    2688                     "%s        begin seq=%d, end seq=%d\n" 
    2689                     "%s        pkt loss=%s, dup=%s\n" 
    2690                     "%s              (msec)    min     avg     max     dev\n" 
    2691                     "%s        jitter     : %s\n" 
    2692                     "%s        toh        : %s", 
    2693                     indent, last_update, 
    2694                     indent, 
    2695                     xr_stat.rx.stat_sum.begin_seq, xr_stat.rx.stat_sum.end_seq, 
    2696                     indent, loss, dup, 
    2697                     indent,  
    2698                     indent, jitter, 
    2699                     indent, toh 
    2700                     ); 
    2701             VALIDATE_PRINT_BUF(); 
    2702  
    2703             if (xr_stat.tx.stat_sum.l) 
    2704                 sprintf(loss, "%d", xr_stat.tx.stat_sum.lost); 
    2705             else 
    2706                 sprintf(loss, "(na)"); 
    2707  
    2708             if (xr_stat.tx.stat_sum.d) 
    2709                 sprintf(dup, "%d", xr_stat.tx.stat_sum.dup); 
    2710             else 
    2711                 sprintf(dup, "(na)"); 
    2712  
    2713             if (xr_stat.tx.stat_sum.j) { 
    2714                 unsigned jmin, jmax, jmean, jdev; 
    2715  
    2716                 SAMPLES_TO_USEC(jmin, xr_stat.tx.stat_sum.jitter.min,  
    2717                                 clock_rate); 
    2718                 SAMPLES_TO_USEC(jmax, xr_stat.tx.stat_sum.jitter.max,  
    2719                                 clock_rate); 
    2720                 SAMPLES_TO_USEC(jmean, xr_stat.tx.stat_sum.jitter.mean,  
    2721                                 clock_rate); 
    2722                 SAMPLES_TO_USEC(jdev,  
    2723                                pj_math_stat_get_stddev(&xr_stat.tx.stat_sum.jitter), 
    2724                                clock_rate); 
    2725                 sprintf(jitter, "%7.3f %7.3f %7.3f %7.3f",  
    2726                         jmin/1000.0, jmean/1000.0, jmax/1000.0, jdev/1000.0); 
    2727             } else 
    2728                 sprintf(jitter, "(report not available)"); 
    2729  
    2730             if (xr_stat.tx.stat_sum.t) { 
    2731                 sprintf(toh, "%11d %11d %11d %11d",  
    2732                         xr_stat.tx.stat_sum.toh.min, 
    2733                         xr_stat.tx.stat_sum.toh.mean, 
    2734                         xr_stat.tx.stat_sum.toh.max, 
    2735                         pj_math_stat_get_stddev(&xr_stat.rx.stat_sum.toh)); 
    2736             } else 
    2737                 sprintf(toh,    "(report not available)"); 
    2738  
    2739             if (xr_stat.tx.stat_sum.update.sec == 0) 
    2740                 strcpy(last_update, "never"); 
    2741             else { 
    2742                 pj_gettimeofday(&now); 
    2743                 PJ_TIME_VAL_SUB(now, xr_stat.tx.stat_sum.update); 
    2744                 sprintf(last_update, "%02ldh:%02ldm:%02ld.%03lds ago", 
    2745                         now.sec / 3600, 
    2746                         (now.sec % 3600) / 60, 
    2747                         now.sec % 60, 
    2748                         now.msec); 
    2749             } 
    2750  
    2751             len = pj_ansi_snprintf(p, end-p,  
    2752                     "%s     TX last update: %s\n" 
    2753                     "%s        begin seq=%d, end seq=%d\n" 
    2754                     "%s        pkt loss=%s, dup=%s\n" 
    2755                     "%s              (msec)    min     avg     max     dev\n" 
    2756                     "%s        jitter     : %s\n" 
    2757                     "%s        toh        : %s", 
    2758                     indent, last_update, 
    2759                     indent, 
    2760                     xr_stat.tx.stat_sum.begin_seq, xr_stat.tx.stat_sum.end_seq, 
    2761                     indent, loss, dup, 
    2762                     indent, 
    2763                     indent, jitter, 
    2764                     indent, toh 
    2765                     ); 
    2766             VALIDATE_PRINT_BUF(); 
    2767  
    2768  
    2769             /* VoIP Metrics */ 
    2770             len = pj_ansi_snprintf(p, end-p, "%s   VoIP Metrics", indent); 
    2771             VALIDATE_PRINT_BUF(); 
    2772  
    2773             PRINT_VOIP_MTC_VAL(signal_lvl, xr_stat.rx.voip_mtc.signal_lvl); 
    2774             PRINT_VOIP_MTC_VAL(noise_lvl, xr_stat.rx.voip_mtc.noise_lvl); 
    2775             PRINT_VOIP_MTC_VAL(rerl, xr_stat.rx.voip_mtc.rerl); 
    2776             PRINT_VOIP_MTC_VAL(r_factor, xr_stat.rx.voip_mtc.r_factor); 
    2777             PRINT_VOIP_MTC_VAL(ext_r_factor, xr_stat.rx.voip_mtc.ext_r_factor); 
    2778             PRINT_VOIP_MTC_VAL(mos_lq, xr_stat.rx.voip_mtc.mos_lq); 
    2779             PRINT_VOIP_MTC_VAL(mos_cq, xr_stat.rx.voip_mtc.mos_cq); 
    2780  
    2781             switch ((xr_stat.rx.voip_mtc.rx_config>>6) & 3) { 
    2782                 case PJMEDIA_RTCP_XR_PLC_DIS: 
    2783                     sprintf(plc, "DISABLED"); 
    2784                     break; 
    2785                 case PJMEDIA_RTCP_XR_PLC_ENH: 
    2786                     sprintf(plc, "ENHANCED"); 
    2787                     break; 
    2788                 case PJMEDIA_RTCP_XR_PLC_STD: 
    2789                     sprintf(plc, "STANDARD"); 
    2790                     break; 
    2791                 case PJMEDIA_RTCP_XR_PLC_UNK: 
    2792                 default: 
    2793                     sprintf(plc, "UNKNOWN"); 
    2794                     break; 
    2795             } 
    2796  
    2797             switch ((xr_stat.rx.voip_mtc.rx_config>>4) & 3) { 
    2798                 case PJMEDIA_RTCP_XR_JB_FIXED: 
    2799                     sprintf(jba, "FIXED"); 
    2800                     break; 
    2801                 case PJMEDIA_RTCP_XR_JB_ADAPTIVE: 
    2802                     sprintf(jba, "ADAPTIVE"); 
    2803                     break; 
    2804                 default: 
    2805                     sprintf(jba, "UNKNOWN"); 
    2806                     break; 
    2807             } 
    2808  
    2809             sprintf(jbr, "%d", xr_stat.rx.voip_mtc.rx_config & 0x0F); 
    2810  
    2811             if (xr_stat.rx.voip_mtc.update.sec == 0) 
    2812                 strcpy(last_update, "never"); 
    2813             else { 
    2814                 pj_gettimeofday(&now); 
    2815                 PJ_TIME_VAL_SUB(now, xr_stat.rx.voip_mtc.update); 
    2816                 sprintf(last_update, "%02ldh:%02ldm:%02ld.%03lds ago", 
    2817                         now.sec / 3600, 
    2818                         (now.sec % 3600) / 60, 
    2819                         now.sec % 60, 
    2820                         now.msec); 
    2821             } 
    2822  
    2823             len = pj_ansi_snprintf(p, end-p,  
    2824                     "%s     RX last update: %s\n" 
    2825                     "%s        packets    : loss rate=%d (%.2f%%), discard rate=%d (%.2f%%)\n" 
    2826                     "%s        burst      : density=%d (%.2f%%), duration=%d%s\n" 
    2827                     "%s        gap        : density=%d (%.2f%%), duration=%d%s\n" 
    2828                     "%s        delay      : round trip=%d%s, end system=%d%s\n" 
    2829                     "%s        level      : signal=%s%s, noise=%s%s, RERL=%s%s\n" 
    2830                     "%s        quality    : R factor=%s, ext R factor=%s\n" 
    2831                     "%s                     MOS LQ=%s, MOS CQ=%s\n" 
    2832                     "%s        config     : PLC=%s, JB=%s, JB rate=%s, Gmin=%d\n" 
    2833                     "%s        JB delay   : cur=%d%s, max=%d%s, abs max=%d%s", 
    2834                     indent, 
    2835                     last_update, 
    2836                     /* packets */ 
    2837                     indent, 
    2838                     xr_stat.rx.voip_mtc.loss_rate, xr_stat.rx.voip_mtc.loss_rate*100.0/256, 
    2839                     xr_stat.rx.voip_mtc.discard_rate, xr_stat.rx.voip_mtc.discard_rate*100.0/256, 
    2840                     /* burst */ 
    2841                     indent, 
    2842                     xr_stat.rx.voip_mtc.burst_den, xr_stat.rx.voip_mtc.burst_den*100.0/256, 
    2843                     xr_stat.rx.voip_mtc.burst_dur, "ms", 
    2844                     /* gap */ 
    2845                     indent, 
    2846                     xr_stat.rx.voip_mtc.gap_den, xr_stat.rx.voip_mtc.gap_den*100.0/256, 
    2847                     xr_stat.rx.voip_mtc.gap_dur, "ms", 
    2848                     /* delay */ 
    2849                     indent, 
    2850                     xr_stat.rx.voip_mtc.rnd_trip_delay, "ms", 
    2851                     xr_stat.rx.voip_mtc.end_sys_delay, "ms", 
    2852                     /* level */ 
    2853                     indent, 
    2854                     signal_lvl, "dB", 
    2855                     noise_lvl, "dB", 
    2856                     rerl, "", 
    2857                     /* quality */ 
    2858                     indent, 
    2859                     r_factor, ext_r_factor,  
    2860                     indent, 
    2861                     mos_lq, mos_cq, 
    2862                     /* config */ 
    2863                     indent, 
    2864                     plc, jba, jbr, xr_stat.rx.voip_mtc.gmin, 
    2865                     /* JB delay */ 
    2866                     indent, 
    2867                     xr_stat.rx.voip_mtc.jb_nom, "ms", 
    2868                     xr_stat.rx.voip_mtc.jb_max, "ms", 
    2869                     xr_stat.rx.voip_mtc.jb_abs_max, "ms" 
    2870                     ); 
    2871             VALIDATE_PRINT_BUF(); 
    2872  
    2873             PRINT_VOIP_MTC_VAL(signal_lvl, xr_stat.tx.voip_mtc.signal_lvl); 
    2874             PRINT_VOIP_MTC_VAL(noise_lvl, xr_stat.tx.voip_mtc.noise_lvl); 
    2875             PRINT_VOIP_MTC_VAL(rerl, xr_stat.tx.voip_mtc.rerl); 
    2876             PRINT_VOIP_MTC_VAL(r_factor, xr_stat.tx.voip_mtc.r_factor); 
    2877             PRINT_VOIP_MTC_VAL(ext_r_factor, xr_stat.tx.voip_mtc.ext_r_factor); 
    2878             PRINT_VOIP_MTC_VAL(mos_lq, xr_stat.tx.voip_mtc.mos_lq); 
    2879             PRINT_VOIP_MTC_VAL(mos_cq, xr_stat.tx.voip_mtc.mos_cq); 
    2880  
    2881             switch ((xr_stat.tx.voip_mtc.rx_config>>6) & 3) { 
    2882                 case PJMEDIA_RTCP_XR_PLC_DIS: 
    2883                     sprintf(plc, "DISABLED"); 
    2884                     break; 
    2885                 case PJMEDIA_RTCP_XR_PLC_ENH: 
    2886                     sprintf(plc, "ENHANCED"); 
    2887                     break; 
    2888                 case PJMEDIA_RTCP_XR_PLC_STD: 
    2889                     sprintf(plc, "STANDARD"); 
    2890                     break; 
    2891                 case PJMEDIA_RTCP_XR_PLC_UNK: 
    2892                 default: 
    2893                     sprintf(plc, "unknown"); 
    2894                     break; 
    2895             } 
    2896  
    2897             switch ((xr_stat.tx.voip_mtc.rx_config>>4) & 3) { 
    2898                 case PJMEDIA_RTCP_XR_JB_FIXED: 
    2899                     sprintf(jba, "FIXED"); 
    2900                     break; 
    2901                 case PJMEDIA_RTCP_XR_JB_ADAPTIVE: 
    2902                     sprintf(jba, "ADAPTIVE"); 
    2903                     break; 
    2904                 default: 
    2905                     sprintf(jba, "unknown"); 
    2906                     break; 
    2907             } 
    2908  
    2909             sprintf(jbr, "%d", xr_stat.tx.voip_mtc.rx_config & 0x0F); 
    2910  
    2911             if (xr_stat.tx.voip_mtc.update.sec == 0) 
    2912                 strcpy(last_update, "never"); 
    2913             else { 
    2914                 pj_gettimeofday(&now); 
    2915                 PJ_TIME_VAL_SUB(now, xr_stat.tx.voip_mtc.update); 
    2916                 sprintf(last_update, "%02ldh:%02ldm:%02ld.%03lds ago", 
    2917                         now.sec / 3600, 
    2918                         (now.sec % 3600) / 60, 
    2919                         now.sec % 60, 
    2920                         now.msec); 
    2921             } 
    2922  
    2923             len = pj_ansi_snprintf(p, end-p,  
    2924                     "%s     TX last update: %s\n" 
    2925                     "%s        packets    : loss rate=%d (%.2f%%), discard rate=%d (%.2f%%)\n" 
    2926                     "%s        burst      : density=%d (%.2f%%), duration=%d%s\n" 
    2927                     "%s        gap        : density=%d (%.2f%%), duration=%d%s\n" 
    2928                     "%s        delay      : round trip=%d%s, end system=%d%s\n" 
    2929                     "%s        level      : signal=%s%s, noise=%s%s, RERL=%s%s\n" 
    2930                     "%s        quality    : R factor=%s, ext R factor=%s\n" 
    2931                     "%s                     MOS LQ=%s, MOS CQ=%s\n" 
    2932                     "%s        config     : PLC=%s, JB=%s, JB rate=%s, Gmin=%d\n" 
    2933                     "%s        JB delay   : cur=%d%s, max=%d%s, abs max=%d%s", 
    2934                     indent, 
    2935                     last_update, 
    2936                     /* pakcets */ 
    2937                     indent, 
    2938                     xr_stat.tx.voip_mtc.loss_rate, xr_stat.tx.voip_mtc.loss_rate*100.0/256, 
    2939                     xr_stat.tx.voip_mtc.discard_rate, xr_stat.tx.voip_mtc.discard_rate*100.0/256, 
    2940                     /* burst */ 
    2941                     indent, 
    2942                     xr_stat.tx.voip_mtc.burst_den, xr_stat.tx.voip_mtc.burst_den*100.0/256, 
    2943                     xr_stat.tx.voip_mtc.burst_dur, "ms", 
    2944                     /* gap */ 
    2945                     indent, 
    2946                     xr_stat.tx.voip_mtc.gap_den, xr_stat.tx.voip_mtc.gap_den*100.0/256, 
    2947                     xr_stat.tx.voip_mtc.gap_dur, "ms", 
    2948                     /* delay */ 
    2949                     indent, 
    2950                     xr_stat.tx.voip_mtc.rnd_trip_delay, "ms", 
    2951                     xr_stat.tx.voip_mtc.end_sys_delay, "ms", 
    2952                     /* level */ 
    2953                     indent, 
    2954                     signal_lvl, "dB", 
    2955                     noise_lvl, "dB", 
    2956                     rerl, "", 
    2957                     /* quality */ 
    2958                     indent, 
    2959                     r_factor, ext_r_factor,  
    2960                     indent, 
    2961                     mos_lq, mos_cq, 
    2962                     /* config */ 
    2963                     indent, 
    2964                     plc, jba, jbr, xr_stat.tx.voip_mtc.gmin, 
    2965                     /* JB delay */ 
    2966                     indent, 
    2967                     xr_stat.tx.voip_mtc.jb_nom, "ms", 
    2968                     xr_stat.tx.voip_mtc.jb_max, "ms", 
    2969                     xr_stat.tx.voip_mtc.jb_abs_max, "ms" 
    2970                     ); 
    2971             VALIDATE_PRINT_BUF(); 
    2972  
    2973  
    2974             /* RTT delay (by receiver side) */ 
    2975             len = pj_ansi_snprintf(p, end-p,  
    2976                     "%s   RTT (from recv)      min     avg     max     last    dev", 
    2977                     indent); 
    2978             VALIDATE_PRINT_BUF(); 
    2979             len = pj_ansi_snprintf(p, end-p,  
    2980                     "%s     RTT msec      : %7.3f %7.3f %7.3f %7.3f %7.3f",  
    2981                     indent, 
    2982                     xr_stat.rtt.min / 1000.0, 
    2983                     xr_stat.rtt.mean / 1000.0, 
    2984                     xr_stat.rtt.max / 1000.0, 
    2985                     xr_stat.rtt.last / 1000.0, 
    2986                     pj_math_stat_get_stddev(&xr_stat.rtt) / 1000.0 
    2987                    ); 
    2988             VALIDATE_PRINT_BUF(); 
    2989         } /* if audio */; 
    2990 #endif 
    2991  
    2992     } 
    2993 } 
    2994  
    2995  
    2996 /* Print call info */ 
    2997 void print_call(const char *title, 
    2998                 int call_id,  
    2999                 char *buf, pj_size_t size) 
    3000 { 
    3001     int len; 
    3002     pjsip_inv_session *inv = pjsua_var.calls[call_id].inv; 
    3003     pjsip_dialog *dlg = inv->dlg; 
    3004     char userinfo[128]; 
    3005  
    3006     /* Dump invite sesion info. */ 
    3007  
    3008     len = pjsip_hdr_print_on(dlg->remote.info, userinfo, sizeof(userinfo)); 
    3009     if (len < 0) 
    3010         pj_ansi_strcpy(userinfo, "<--uri too long-->"); 
    3011     else 
    3012         userinfo[len] = '\0'; 
    3013      
    3014     len = pj_ansi_snprintf(buf, size, "%s[%s] %s", 
    3015                            title, 
    3016                            pjsip_inv_state_name(inv->state), 
    3017                            userinfo); 
    3018     if (len < 1 || len >= (int)size) { 
    3019         pj_ansi_strcpy(buf, "<--uri too long-->"); 
    3020         len = 18; 
    3021     } else 
    3022         buf[len] = '\0'; 
    3023 } 
    3024  
    3025  
    3026 /* 
    3027  * Dump call and media statistics to string. 
    3028  */ 
    3029 PJ_DEF(pj_status_t) pjsua_call_dump( pjsua_call_id call_id,  
    3030                                      pj_bool_t with_media,  
    3031                                      char *buffer,  
    3032                                      unsigned maxlen, 
    3033                                      const char *indent) 
    3034 { 
    3035     pjsua_call *call; 
    3036     pjsip_dialog *dlg; 
    3037     pj_time_val duration, res_delay, con_delay; 
    3038     char tmp[128]; 
    3039     char *p, *end; 
    3040     pj_status_t status; 
    3041     int len; 
    3042  
    3043     PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, 
    3044                      PJ_EINVAL); 
    3045  
    3046     status = acquire_call("pjsua_call_dump()", call_id, &call, &dlg); 
    3047     if (status != PJ_SUCCESS) 
    3048         return status; 
    3049  
    3050     *buffer = '\0'; 
    3051     p = buffer; 
    3052     end = buffer + maxlen; 
    3053     len = 0; 
    3054  
    3055     print_call(indent, call_id, tmp, sizeof(tmp)); 
    3056      
    3057     len = pj_ansi_strlen(tmp); 
    3058     pj_ansi_strcpy(buffer, tmp); 
    3059  
    3060     p += len; 
    3061     *p++ = '\r'; 
    3062     *p++ = '\n'; 
    3063  
    3064     /* Calculate call duration */ 
    3065     if (call->conn_time.sec != 0) { 
    3066         pj_gettimeofday(&duration); 
    3067         PJ_TIME_VAL_SUB(duration, call->conn_time); 
    3068         con_delay = call->conn_time; 
    3069         PJ_TIME_VAL_SUB(con_delay, call->start_time); 
    3070     } else { 
    3071         duration.sec = duration.msec = 0; 
    3072         con_delay.sec = con_delay.msec = 0; 
    3073     } 
    3074  
    3075     /* Calculate first response delay */ 
    3076     if (call->res_time.sec != 0) { 
    3077         res_delay = call->res_time; 
    3078         PJ_TIME_VAL_SUB(res_delay, call->start_time); 
    3079     } else { 
    3080         res_delay.sec = res_delay.msec = 0; 
    3081     } 
    3082  
    3083     /* Print duration */ 
    3084     len = pj_ansi_snprintf(p, end-p,  
    3085                            "%s  Call time: %02dh:%02dm:%02ds, " 
    3086                            "1st res in %d ms, conn in %dms", 
    3087                            indent, 
    3088                            (int)(duration.sec / 3600), 
    3089                            (int)((duration.sec % 3600)/60), 
    3090                            (int)(duration.sec % 60), 
    3091                            (int)PJ_TIME_VAL_MSEC(res_delay),  
    3092                            (int)PJ_TIME_VAL_MSEC(con_delay)); 
    3093      
    3094     if (len > 0 && len < end-p) { 
    3095         p += len; 
    3096         *p++ = '\n'; 
    3097         *p = '\0'; 
    3098     } 
    3099  
    3100     /* Dump session statistics */ 
    3101     if (with_media && pjsua_call_has_media(call_id)) 
    3102         dump_media_session(indent, p, end-p, call); 
    3103  
    3104     pjsip_dlg_dec_lock(dlg); 
    3105  
    3106     return PJ_SUCCESS; 
    3107 } 
    31082162 
    31092163/* Proto */ 
Note: See TracChangeset for help on using the changeset viewer.