Changeset 390


Ignore:
Timestamp:
Apr 6, 2006 7:29:03 PM (18 years ago)
Author:
bennylp
Message:

Integrate (stream) quality monitoring into RTCP framework, and update all RTCP clients accordingly

Location:
pjproject/trunk
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjmedia/include/pjmedia/rtcp.h

    r385 r390  
    147147 
    148148/** 
     149 * Unidirectional RTP stream statistics. 
     150 */ 
     151struct pjmedia_rtcp_stream_stat 
     152{ 
     153    pj_time_val     update;     /**< Time of last update.                   */ 
     154    unsigned        update_cnt; /**< Number of updates (to calculate avg)   */ 
     155    pj_uint32_t     pkt;        /**< Total number of packets                */ 
     156    pj_uint32_t     bytes;      /**< Total number of payload/bytes          */ 
     157    unsigned        discard;    /**< Number of discarded packets.           */ 
     158    unsigned        loss;       /**< Number of packets lost                 */ 
     159    unsigned        reorder;    /**< Number of out of order packets         */ 
     160    unsigned        dup;        /**< Number of duplicates packets           */ 
     161 
     162    struct { 
     163        unsigned    min;        /**< Minimum loss period (in usec)          */ 
     164        unsigned    avg;        /**< Average loss period (in usec)          */ 
     165        unsigned    max;        /**< Maximum loss period (in usec)          */ 
     166        unsigned    last;       /**< Last loss period (in usec)             */ 
     167    } loss_period;              /**< Lost period history.                   */ 
     168 
     169    struct { 
     170        unsigned    burst:1;    /**< Burst/sequential packet lost detected  */ 
     171        unsigned    random:1;   /**< Random packet lost detected.           */ 
     172    } loss_type;                /**< Types of loss detected.                */ 
     173 
     174    struct { 
     175        unsigned    min;        /**< Minimum jitter (in usec)               */ 
     176        unsigned    avg;        /**< Average jitter (in usec)               */ 
     177        unsigned    max;        /**< Maximum jitter (in usec)               */ 
     178        unsigned    last;       /**< Last jitter (in usec)                  */ 
     179    } jitter;                   /**< Jitter history.                        */ 
     180}; 
     181 
     182 
     183/** 
     184 * @see pjmedia_rtcp_stream_stat 
     185 */ 
     186typedef struct pjmedia_rtcp_stream_stat pjmedia_rtcp_stream_stat; 
     187 
     188 
     189 
     190/** 
     191 * Bidirectional RTP stream statistics. 
     192 */ 
     193struct pjmedia_rtcp_stat 
     194{ 
     195    pjmedia_rtcp_stream_stat    tx; /**< Encoder stream statistics.         */ 
     196    pjmedia_rtcp_stream_stat    rx; /**< Decoder stream statistics.         */ 
     197     
     198    struct { 
     199        unsigned    min;            /**< Minimum round-trip delay (in usec) */ 
     200        unsigned    avg;            /**< Average round-trip delay (in usec) */ 
     201        unsigned    max;            /**< Maximum round-trip delay (in usec) */ 
     202        unsigned    last;           /**< Last round-trip delay (in usec)    */ 
     203    } rtt;                          /**< Round trip delay history.          */ 
     204 
     205    unsigned        rtt_update_cnt; /**< Nb of times rtt is updated.        */ 
     206}; 
     207 
     208 
     209/** 
     210 * @see pjmedia_rtcp_stat 
     211 */ 
     212typedef struct pjmedia_rtcp_stat pjmedia_rtcp_stat; 
     213 
     214 
     215/** 
    149216 * RTCP session is used to monitor the RTP session of one endpoint. There 
    150217 * should only be one RTCP session for a bidirectional RTP streams. 
     
    157224 
    158225    unsigned                clock_rate; /**< Clock rate of the stream       */ 
     226    unsigned                pkt_size;   /**< Avg pkt size, in samples.      */ 
    159227    pj_uint32_t             received;   /**< # pkt received                 */ 
    160228    pj_uint32_t             exp_prior;  /**< # pkt expected at last interval*/ 
     
    167235    pj_timestamp            rx_lsr_time;/**< Time when last SR is received  */ 
    168236    pj_uint32_t             peer_ssrc;  /**< Peer SSRC                      */ 
    169     unsigned                rtt_us;     /**< End-to-end delay, in usec.     */ 
     237     
     238    pjmedia_rtcp_stat       stat;       /**< Bidirectional stream stat.     */ 
    170239}; 
    171240 
     
    179248 * Initialize RTCP session. 
    180249 * 
    181  * @param session   The session 
    182  * @param ssrc      The SSRC used in to identify the session. 
     250 * @param session           The session 
     251 * @param clock_rate        Codec clock rate in samples per second. 
     252 * @param samples_per_frame Average number of samples per frame. 
     253 * @param ssrc              The SSRC used in to identify the session. 
    183254 */ 
    184255PJ_DECL(void) pjmedia_rtcp_init( pjmedia_rtcp_session *session,  
    185256                                 unsigned clock_rate, 
     257                                 unsigned samples_per_frame, 
    186258                                 pj_uint32_t ssrc ); 
    187259 
     
    202274 * @param seq       The RTP packet sequence number, in host byte order. 
    203275 * @param ts        The RTP packet timestamp, in host byte order. 
     276 * @param payload   Size of the payload. 
    204277 */ 
    205278PJ_DECL(void) pjmedia_rtcp_rx_rtp( pjmedia_rtcp_session *session,  
    206                                    pj_uint16_t seq,  
    207                                    pj_uint32_t ts ); 
     279                                   unsigned seq,  
     280                                   unsigned ts, 
     281                                   unsigned payload); 
    208282 
    209283 
     
    217291 */ 
    218292PJ_DECL(void) pjmedia_rtcp_tx_rtp( pjmedia_rtcp_session *session,  
    219                                    pj_uint16_t ptsize ); 
     293                                   unsigned ptsize ); 
    220294 
    221295 
  • pjproject/trunk/pjmedia/include/pjmedia/rtp.h

    r214 r390  
    181181 
    182182/** 
     183 * This structure is used to receive additional information about the 
     184 * state of incoming RTP packet. 
     185 */ 
     186struct pjmedia_rtp_status 
     187{ 
     188    union { 
     189        struct flag { 
     190            int bad:1;      /**< General flag to indicate that sequence is 
     191                                 bad, and application should not process 
     192                                 this packet. More information will be given 
     193                                 in other flags.                            */ 
     194            int badpt:1;    /**< Bad payload type.                          */ 
     195            int dup:1;      /**< Indicates duplicate packet                 */ 
     196            int outorder:1; /**< Indicates out of order packet              */ 
     197            int probation:1;/**< Indicates that session is in probation 
     198                                 until more packets are received.           */ 
     199            int restart:1;  /**< Indicates that sequence number has made 
     200                                 a large jump, and internal base sequence 
     201                                 number has been adjusted.                  */ 
     202        } flag;             /**< Status flags.                              */ 
     203 
     204        pj_uint16_t value;  /**< Status value, to conveniently address all 
     205                                 flags.                                     */ 
     206 
     207    } status;               /**< Status information union.                  */ 
     208 
     209    pj_uint16_t diff;       /**< Sequence number difference from previous 
     210                                 packet. Normally the value should be 1.     
     211                                 Value greater than one may indicate packet 
     212                                 loss. If packet with lower sequence is 
     213                                 received, the value will be set to zero. 
     214                                 If base sequence has been restarted, the 
     215                                 value will be one.                         */ 
     216}; 
     217 
     218/** 
     219 * @see pjmedia_rtp_status 
     220 */ 
     221typedef struct pjmedia_rtp_status pjmedia_rtp_status; 
     222 
     223 
     224/** 
    183225 * This function will initialize the RTP session according to given parameters. 
    184226 * 
     
    242284 * @param ses       The session. 
    243285 * @param hdr       The RTP header of the incoming packet. 
    244  * 
    245  * @return          PJ_SUCCESS if the packet is valid and can be processed,  
    246  *                  otherwise will return the appropriate status code. 
    247  */ 
    248 PJ_DECL(pj_status_t) pjmedia_rtp_session_update( pjmedia_rtp_session *ses,  
    249                                                  const pjmedia_rtp_hdr *hdr); 
     286 * @param seq_st    Optional structure to receive the status of the RTP packet 
     287 *                  processing. 
     288 */ 
     289PJ_DECL(void) pjmedia_rtp_session_update( pjmedia_rtp_session *ses,  
     290                                          const pjmedia_rtp_hdr *hdr, 
     291                                          pjmedia_rtp_status *seq_st); 
    250292 
    251293 
     
    266308 
    267309/**  
    268  * Internal function to restart the sequence number control, shared by RTCP  
    269  * implementation.  
    270  * 
    271  * @param seq_ctrl  The sequence control instance. 
    272  * @param seq       Sequence number to restart. 
    273  */ 
    274 void pjmedia_rtp_seq_restart(pjmedia_rtp_seq_session *seq_ctrl,  
    275                              pj_uint16_t seq); 
    276  
    277 /**  
    278310 * Internal function update sequence control, shared by RTCP implementation. 
    279311 * 
    280  * @param seq_ctrl  The sequence control instance. 
    281  * @param seq       Sequence number to update. 
    282  * 
    283  * @return          PJ_SUCCESS if the sequence number can be accepted. 
    284  */ 
    285 pj_status_t pjmedia_rtp_seq_update(pjmedia_rtp_seq_session *seq_ctrl,  
    286                                    pj_uint16_t seq); 
     312 * @param seq_ctrl      The sequence control instance. 
     313 * @param seq           Sequence number to update. 
     314 * @param seq_status    Optional structure to receive additional information  
     315 *                      about the packet. 
     316 */ 
     317void pjmedia_rtp_seq_update( pjmedia_rtp_seq_session *seq_ctrl,  
     318                             pj_uint16_t seq, 
     319                             pjmedia_rtp_status *seq_status); 
    287320 
    288321/** 
  • pjproject/trunk/pjmedia/include/pjmedia/session.h

    r374 r390  
    218218PJ_DECL(pj_status_t) pjmedia_session_get_stream_stat(pjmedia_session *session, 
    219219                                                     unsigned index, 
    220                                                      pjmedia_stream_stat *sta); 
     220                                                     pjmedia_rtcp_stat *stat); 
    221221 
    222222/** 
  • pjproject/trunk/pjmedia/include/pjmedia/stream.h

    r290 r390  
    3030#include <pjmedia/endpoint.h> 
    3131#include <pjmedia/port.h> 
     32#include <pjmedia/rtcp.h> 
    3233#include <pj/sock.h> 
    3334 
     
    8384 
    8485/** 
    85  * Individual channel statistic. 
    86  */ 
    87 struct pjmedia_channel_stat 
    88 { 
    89     pj_uint32_t pkt;        /**< Total number of packets.                   */ 
    90     pj_uint32_t bytes;      /**< Total number of bytes, including RTP hdr.  */ 
    91     pj_uint32_t lost;       /**< Total number of packet lost                */ 
    92 }; 
    93  
    94 /** 
    95  * Stream statistic. 
    96  */ 
    97 struct pjmedia_stream_stat 
    98 { 
    99     pjmedia_channel_stat    enc;    /**< Encoder statistics.                */ 
    100     pjmedia_channel_stat    dec;    /**< Decoder statistics.                */ 
    101 }; 
    102  
    103  
    104  
    105 /** 
    10686 * Create a media stream based on the specified stream parameter. 
    10787 * All channels in the stream initially will be inactive. 
     
    165145 */ 
    166146PJ_DECL(pj_status_t) pjmedia_stream_get_stat( const pjmedia_stream *stream, 
    167                                               pjmedia_stream_stat *stat); 
     147                                              pjmedia_rtcp_stat *stat); 
    168148 
    169149/** 
  • pjproject/trunk/pjmedia/src/pjmedia/rtcp.c

    r389 r390  
    4444 * Get NTP time. 
    4545 */ 
    46 static void rtcp_get_ntp_time(const pjmedia_rtcp_session *s,  
     46static void rtcp_get_ntp_time(const pjmedia_rtcp_session *sess,  
    4747                              struct pjmedia_rtcp_ntp_rec *ntp) 
    4848{ 
     
    5757     
    5858    /* Calculate second fractions */ 
    59     ts.u64 %= s->ts_freq.u64; 
    60     ts.u64 = (ts.u64 << 32) / s->ts_freq.u64; 
     59    ts.u64 %= sess->ts_freq.u64; 
     60    ts.u64 = (ts.u64 << 32) / sess->ts_freq.u64; 
    6161 
    6262    /* Fill up the low 32bit part */ 
     
    6565 
    6666 
    67 PJ_DEF(void) pjmedia_rtcp_init(pjmedia_rtcp_session *s,  
     67PJ_DEF(void) pjmedia_rtcp_init(pjmedia_rtcp_session *sess,  
    6868                               unsigned clock_rate, 
     69                               unsigned samples_per_frame, 
    6970                               pj_uint32_t ssrc) 
    7071{ 
    71     pjmedia_rtcp_pkt *rtcp_pkt = &s->rtcp_pkt; 
     72    pjmedia_rtcp_pkt *rtcp_pkt = &sess->rtcp_pkt; 
    7273     
    7374    pj_memset(rtcp_pkt, 0, sizeof(pjmedia_rtcp_pkt)); 
    7475     
    7576    /* Set clock rate */ 
    76     s->clock_rate = clock_rate; 
     77    sess->clock_rate = clock_rate; 
     78    sess->pkt_size = samples_per_frame; 
    7779 
    7880    /* Init time */ 
    79     s->rx_lsr = 0; 
    80     s->rx_lsr_time.u64 = 0; 
     81    sess->rx_lsr = 0; 
     82    sess->rx_lsr_time.u64 = 0; 
    8183     
    8284    /* Init common RTCP header */ 
     
    9092     
    9193    /* Get timestamp frequency */ 
    92     pj_get_timestamp_freq(&s->ts_freq); 
     94    pj_get_timestamp_freq(&sess->ts_freq); 
    9395 
    9496    /* RR will be initialized on receipt of the first RTP packet. */ 
     
    9698 
    9799 
    98 PJ_DEF(void) pjmedia_rtcp_fini(pjmedia_rtcp_session *session) 
     100PJ_DEF(void) pjmedia_rtcp_fini(pjmedia_rtcp_session *sess) 
    99101{ 
    100102    /* Nothing to do. */ 
    101     PJ_UNUSED_ARG(session); 
    102 } 
    103  
    104 static void rtcp_init_seq(pjmedia_rtcp_session *s, pj_uint16_t  seq) 
    105 { 
    106     s->received = 0; 
    107     s->exp_prior = 0; 
    108     s->rx_prior = 0; 
    109     s->transit = 0; 
    110     s->jitter = 0; 
    111  
    112     pjmedia_rtp_seq_restart(&s->seq_ctrl, seq); 
    113 } 
    114  
    115 PJ_DEF(void) pjmedia_rtcp_rx_rtp(pjmedia_rtcp_session *s,  
    116                                  pj_uint16_t seq,  
    117                                  pj_uint32_t rtp_ts) 
     103    PJ_UNUSED_ARG(sess); 
     104} 
     105 
     106static void rtcp_init_seq(pjmedia_rtcp_session *sess) 
     107{ 
     108    sess->received = 0; 
     109    sess->exp_prior = 0; 
     110    sess->rx_prior = 0; 
     111    sess->transit = 0; 
     112    sess->jitter = 0; 
     113} 
     114 
     115PJ_DEF(void) pjmedia_rtcp_rx_rtp(pjmedia_rtcp_session *sess,  
     116                                 unsigned seq,  
     117                                 unsigned rtp_ts, 
     118                                 unsigned payload) 
    118119{    
    119120    pj_timestamp ts; 
    120121    pj_uint32_t arrival; 
    121122    pj_int32_t transit; 
    122     int status; 
    123  
    124     /* Update sequence numbers (received, lost, etc). */ 
    125     status = pjmedia_rtp_seq_update(&s->seq_ctrl, seq); 
    126     if (status == PJMEDIA_RTP_ESESSRESTART) { 
    127         rtcp_init_seq(s, seq); 
    128         status = 0; 
    129     } 
    130      
    131     if (status != 0) 
     123    pjmedia_rtp_status seq_st; 
     124    unsigned last_seq; 
     125 
     126    sess->stat.rx.pkt++; 
     127    sess->stat.rx.bytes += payload; 
     128 
     129    /* Update sequence numbers. */ 
     130    last_seq = sess->seq_ctrl.max_seq; 
     131    pjmedia_rtp_seq_update(&sess->seq_ctrl, (pj_uint16_t)seq, &seq_st); 
     132    if (seq_st.status.flag.restart) { 
     133        rtcp_init_seq(sess); 
     134    } 
     135     
     136    if (seq_st.status.flag.dup) 
     137        sess->stat.rx.dup++; 
     138    if (seq_st.status.flag.outorder) 
     139        sess->stat.rx.reorder++; 
     140 
     141    if (seq_st.status.flag.bad) { 
     142        sess->stat.rx.discard++; 
    132143        return; 
    133  
    134     ++s->received; 
     144    } 
     145 
     146 
     147    /* Only mark "good" packets */ 
     148    ++sess->received; 
     149 
    135150 
    136151    /* 
     
    140155    /* Get arrival time and convert timestamp to samples */ 
    141156    pj_get_timestamp(&ts); 
    142     ts.u64 = ts.u64 * s->clock_rate / s->ts_freq.u64; 
     157    ts.u64 = ts.u64 * sess->clock_rate / sess->ts_freq.u64; 
    143158    arrival = ts.u32.lo; 
    144159 
    145160    transit = arrival - rtp_ts; 
    146161     
    147     if (s->transit == 0) { 
    148         s->transit = transit; 
     162    /* Ignore the first N packets as they normally have bad jitter 
     163     * due to other threads working to establish the call 
     164     */ 
     165    if (sess->transit == 0 || sess->received < 25 ) { 
     166        sess->transit = transit; 
     167        sess->stat.rx.jitter.min = 2000; 
    149168    } else { 
    150169        pj_int32_t d; 
    151          
    152         d = transit - s->transit; 
    153         s->transit = transit; 
     170        pj_uint32_t jitter; 
     171         
     172        d = transit - sess->transit; 
     173        sess->transit = transit; 
    154174        if (d < 0)  
    155175            d = -d; 
    156176         
    157         s->jitter += d - ((s->jitter + 8) >> 4); 
    158     } 
    159 } 
    160  
    161 PJ_DEF(void) pjmedia_rtcp_tx_rtp(pjmedia_rtcp_session *s,  
    162                                  pj_uint16_t  bytes_payload_size) 
    163 { 
    164     pjmedia_rtcp_pkt *rtcp_pkt = &s->rtcp_pkt; 
    165  
    166     /* Update number of packets */ 
    167     rtcp_pkt->sr.sender_pcount =  
    168         pj_htonl( pj_ntohl(rtcp_pkt->sr.sender_pcount) + 1); 
    169  
    170     /* Update number of bytes */ 
    171     rtcp_pkt->sr.sender_bcount =  
    172         pj_htonl( pj_ntohl(rtcp_pkt->sr.sender_bcount) + bytes_payload_size ); 
    173 } 
    174  
    175  
    176 PJ_DEF(void) pjmedia_rtcp_rx_rtcp( pjmedia_rtcp_session *session, 
     177        sess->jitter += d - ((sess->jitter + 8) >> 4); 
     178 
     179        /* Get jitter in usec */ 
     180        if (d < 4294) 
     181            jitter = d * 1000000 / sess->clock_rate; 
     182        else { 
     183            jitter = d * 1000 / sess->clock_rate; 
     184            jitter *= 1000; 
     185        } 
     186 
     187        /* Update jitter stat */ 
     188        if (jitter < sess->stat.rx.jitter.min) 
     189            sess->stat.rx.jitter.min = jitter; 
     190        if (jitter > sess->stat.rx.jitter.max) 
     191            sess->stat.rx.jitter.max = jitter; 
     192        sess->stat.rx.jitter.last = jitter; 
     193    } 
     194} 
     195 
     196PJ_DEF(void) pjmedia_rtcp_tx_rtp(pjmedia_rtcp_session *sess,  
     197                                 unsigned bytes_payload_size) 
     198{ 
     199    /* Update statistics */ 
     200    sess->stat.tx.pkt++; 
     201    sess->stat.tx.bytes += bytes_payload_size; 
     202} 
     203 
     204 
     205PJ_DEF(void) pjmedia_rtcp_rx_rtcp( pjmedia_rtcp_session *sess, 
    177206                                   const void *pkt, 
    178207                                   pj_size_t size) 
     
    184213 
    185214    /* Save LSR from NTP timestamp of RTCP packet */ 
    186     session->rx_lsr = ((pj_ntohl(rtcp->sr.ntp_sec) & 0x0000FFFF) << 16) |  
    187                         ((pj_ntohl(rtcp->sr.ntp_frac) >> 16) & 0xFFFF); 
     215    sess->rx_lsr = ((pj_ntohl(rtcp->sr.ntp_sec) & 0x0000FFFF) << 16) |  
     216                  ((pj_ntohl(rtcp->sr.ntp_frac) >> 16) & 0xFFFF); 
    188217 
    189218    /* Calculate SR arrival time for DLSR */ 
    190     pj_get_timestamp(&session->rx_lsr_time); 
     219    pj_get_timestamp(&sess->rx_lsr_time); 
    191220 
    192221    TRACE_((THIS_FILE, "Rx RTCP SR: ntp-ts=%p, time=%p",  
    193             session->rx_lsr, 
    194             (pj_uint32_t)(session->rx_lsr_time.u64*65536/session->ts_freq.u64))); 
     222            sess->rx_lsr, 
     223            (pj_uint32_t)(sess->rx_lsr_time.u64*65536/sess->ts_freq.u64))); 
    195224 
    196225    /* Calculate RTT if it has RR */ 
    197226    if (size >= sizeof(pjmedia_rtcp_pkt)) { 
    198227         
     228        pj_uint32_t last_loss, jitter_samp, jitter; 
     229 
     230        last_loss = sess->stat.tx.loss; 
     231 
     232        /* Get packet loss */ 
     233        sess->stat.tx.loss = (rtcp->rr.total_lost_2 << 16) + 
     234                             (rtcp->rr.total_lost_1 << 8) + 
     235                              rtcp->rr.total_lost_0; 
     236         
     237        /* We can't calculate the exact loss period for TX, so just give the 
     238         * best estimation. 
     239         */ 
     240        if (sess->stat.tx.loss > last_loss) { 
     241            unsigned period; 
     242 
     243            /* Loss period in msec */ 
     244            period = (sess->stat.tx.loss - last_loss) * sess->pkt_size * 
     245                     1000 / sess->clock_rate; 
     246 
     247            /* Loss period in usec */ 
     248            period *= 1000; 
     249 
     250            if (sess->stat.tx.update_cnt==0||sess->stat.tx.loss_period.min==0) 
     251                sess->stat.tx.loss_period.min = period; 
     252            if (period < sess->stat.tx.loss_period.min) 
     253                sess->stat.tx.loss_period.min = period; 
     254            if (period > sess->stat.tx.loss_period.max) 
     255                sess->stat.tx.loss_period.max = period; 
     256 
     257            sess->stat.tx.loss_period.avg =  
     258                (sess->stat.tx.loss_period.avg*sess->stat.tx.update_cnt+period) 
     259                / (sess->stat.tx.update_cnt + 1); 
     260            sess->stat.tx.loss_period.last = period; 
     261        } 
     262 
     263        /* Get jitter value in usec */ 
     264        jitter_samp = pj_ntohl(rtcp->rr.jitter); 
     265        /* Calculate jitter in usec, avoiding overflows */ 
     266        if (jitter_samp <= 4294) 
     267            jitter = jitter_samp * 1000000 / sess->clock_rate; 
     268        else { 
     269            jitter = jitter_samp * 1000 / sess->clock_rate; 
     270            jitter *= 1000; 
     271        } 
     272 
     273        /* Update jitter statistics */ 
     274        if (sess->stat.tx.update_cnt == 0) 
     275            sess->stat.tx.jitter.min = jitter; 
     276        if (jitter < sess->stat.tx.jitter.min && jitter) 
     277            sess->stat.tx.jitter.min = jitter; 
     278        if (jitter > sess->stat.tx.jitter.max) 
     279            sess->stat.tx.jitter.max = jitter; 
     280        sess->stat.tx.jitter.avg =  
     281            (sess->stat.tx.jitter.avg * sess->stat.tx.update_cnt + jitter) / 
     282            (sess->stat.tx.update_cnt + 1); 
     283        sess->stat.tx.jitter.last = jitter; 
     284 
     285 
    199286        /* Can only calculate if LSR and DLSR is present in RR */ 
    200287        if (rtcp->rr.lsr && rtcp->rr.dlsr) { 
     
    212299 
    213300            /* Get current time, and convert to 1/65536 resolution */ 
    214             rtcp_get_ntp_time(session, &ntp); 
     301            rtcp_get_ntp_time(sess, &ntp); 
    215302            now = ((ntp.hi & 0xFFFF) << 16) +  
    216303                  (ntp.lo >> 16); 
     
    221308            /* Convert end to end delay to usec (keeping the calculation in 
    222309             * 64bit space):: 
    223              *   session->ee_delay = (eedelay * 1000) / 65536; 
     310             *   sess->ee_delay = (eedelay * 1000) / 65536; 
    224311             */ 
    225312            eedelay = (eedelay * 1000000) >> 16; 
     
    234321             */ 
    235322            if (now-dlsr >= lsr) { 
    236                 session->rtt_us = (pj_uint32_t)eedelay; 
     323                unsigned rtt = (pj_uint32_t)eedelay; 
     324                 
     325                if (sess->stat.rtt_update_cnt == 0) 
     326                    sess->stat.rtt.min = rtt; 
     327 
     328                if (rtt < sess->stat.rtt.min && rtt) 
     329                    sess->stat.rtt.min = rtt; 
     330                if (rtt > sess->stat.rtt.max) 
     331                    sess->stat.rtt.max = rtt; 
     332 
     333                sess->stat.rtt.avg =  
     334                    (sess->stat.rtt.avg * sess->stat.rtt_update_cnt + rtt) /  
     335                    (sess->stat.rtt_update_cnt + 1); 
     336 
     337                sess->stat.rtt.last = rtt; 
     338                sess->stat.rtt_update_cnt++; 
     339 
    237340            } else { 
    238                 PJ_LOG(3, (THIS_FILE, "Internal NTP clock skew detected")); 
     341                PJ_LOG(3, (THIS_FILE, "Internal NTP clock skew detected: " 
     342                                       "lsr=%p, now=%p, dlsr=%p (%d:%03dms)", 
     343                                       lsr, now, dlsr, dlsr/65536, 
     344                                       (dlsr%65536)*1000/65536)); 
    239345            } 
    240346        } 
    241     } 
    242 } 
    243  
    244  
    245 static void rtcp_build_rtcp(pjmedia_rtcp_session *s,  
    246                             pj_uint32_t receiver_ssrc) 
    247 {    
    248     pj_uint32_t expected; 
    249     pj_uint32_t u32; 
    250     pj_uint32_t expected_interval, received_interval, lost_interval; 
    251     pjmedia_rtcp_pkt *rtcp_pkt = &s->rtcp_pkt; 
     347 
     348        pj_gettimeofday(&sess->stat.tx.update); 
     349        sess->stat.tx.update_cnt++; 
     350    } 
     351} 
     352 
     353 
     354PJ_DEF(void) pjmedia_rtcp_build_rtcp(pjmedia_rtcp_session *sess,  
     355                                     pjmedia_rtcp_pkt **ret_p_pkt,  
     356                                     int *len) 
     357{ 
     358    pj_uint32_t expected, expected_interval, received_interval, lost_interval; 
     359    pj_uint32_t jitter_samp, jitter; 
     360    pjmedia_rtcp_pkt *rtcp_pkt = &sess->rtcp_pkt; 
     361    pjmedia_rtcp_ntp_rec ntp; 
     362     
     363    /* Packet count */ 
     364    rtcp_pkt->sr.sender_pcount = pj_htonl(sess->stat.tx.pkt); 
     365 
     366    /* Octets count */ 
     367    rtcp_pkt->sr.sender_bcount = pj_htonl(sess->stat.tx.bytes); 
    252368     
    253369    /* SSRC and last_seq */ 
    254     rtcp_pkt->rr.ssrc = pj_htonl(receiver_ssrc); 
    255     rtcp_pkt->rr.last_seq = (s->seq_ctrl.cycles & 0xFFFF0000L); 
    256     rtcp_pkt->rr.last_seq += s->seq_ctrl.max_seq; 
     370    rtcp_pkt->rr.ssrc = pj_htonl(sess->peer_ssrc); 
     371    rtcp_pkt->rr.last_seq = (sess->seq_ctrl.cycles & 0xFFFF0000L); 
     372    rtcp_pkt->rr.last_seq += sess->seq_ctrl.max_seq; 
    257373    rtcp_pkt->rr.last_seq = pj_htonl(rtcp_pkt->rr.last_seq); 
    258374 
     375 
    259376    /* Jitter */ 
    260     rtcp_pkt->rr.jitter = pj_htonl(s->jitter >> 4); 
     377    jitter_samp = (sess->jitter >> 4); 
     378    rtcp_pkt->rr.jitter = pj_htonl(jitter_samp); 
     379     
     380    /* Calculate jitter in usec, avoiding overflows */ 
     381    if (jitter_samp <= 4294) 
     382        jitter = jitter_samp * 1000000 / sess->clock_rate; 
     383    else { 
     384        jitter = jitter_samp * 1000 / sess->clock_rate; 
     385        jitter *= 1000; 
     386    } 
     387 
     388    /* Update jitter statistics */ 
     389    sess->stat.rx.jitter.avg =  
     390        (sess->stat.rx.jitter.avg * sess->stat.rx.update_cnt + jitter) / 
     391        (sess->stat.rx.update_cnt + 1); 
    261392     
    262393    /* Total lost. */ 
    263     expected = pj_ntohl(rtcp_pkt->rr.last_seq) - s->seq_ctrl.base_seq; 
    264     if (expected >= s->received) 
    265         u32 = expected - s->received; 
    266     else 
    267         u32 = 0; 
    268     rtcp_pkt->rr.total_lost_2 = (u32 >> 16) & 0x00FF; 
    269     rtcp_pkt->rr.total_lost_1 = (u32 >> 8) & 0x00FF; 
    270     rtcp_pkt->rr.total_lost_0 = u32 & 0x00FF; 
     394    expected = pj_ntohl(rtcp_pkt->rr.last_seq) - sess->seq_ctrl.base_seq; 
     395    if (expected >= sess->received) 
     396        sess->stat.rx.loss = expected - sess->received; 
     397    rtcp_pkt->rr.total_lost_2 = (sess->stat.rx.loss >> 16) & 0xFF; 
     398    rtcp_pkt->rr.total_lost_1 = (sess->stat.rx.loss >> 8) & 0xFF; 
     399    rtcp_pkt->rr.total_lost_0 = (sess->stat.rx.loss & 0xFF); 
    271400 
    272401    /* Fraction lost calculation */ 
    273     expected_interval = expected - s->exp_prior; 
    274     s->exp_prior = expected; 
    275      
    276     received_interval = s->received - s->rx_prior; 
    277     s->rx_prior = s->received; 
     402    expected_interval = expected - sess->exp_prior; 
     403    sess->exp_prior = expected; 
     404     
     405    received_interval = sess->received - sess->rx_prior; 
     406    sess->rx_prior = sess->received; 
    278407     
    279408    lost_interval = expected_interval - received_interval; 
     
    284413        rtcp_pkt->rr.fract_lost = (lost_interval << 8) / expected_interval; 
    285414    } 
    286 } 
    287  
    288 PJ_DEF(void) pjmedia_rtcp_build_rtcp(pjmedia_rtcp_session *session,  
    289                                      pjmedia_rtcp_pkt **ret_p_pkt,  
    290                                      int *len) 
    291 { 
    292     pjmedia_rtcp_pkt *rtcp_pkt = &session->rtcp_pkt; 
    293     pjmedia_rtcp_ntp_rec ntp; 
    294      
    295     rtcp_build_rtcp(session, session->peer_ssrc); 
    296415     
    297416    /* Get current NTP time. */ 
    298     rtcp_get_ntp_time(session, &ntp); 
     417    rtcp_get_ntp_time(sess, &ntp); 
    299418     
    300419    /* Fill in NTP timestamp in SR. */ 
     
    302421    rtcp_pkt->sr.ntp_frac = pj_htonl(ntp.lo); 
    303422     
    304     if (session->rx_lsr_time.u64 == 0 || session->rx_lsr == 0) { 
     423    if (sess->rx_lsr_time.u64 == 0 || sess->rx_lsr == 0) { 
    305424        rtcp_pkt->rr.lsr = 0; 
    306425        rtcp_pkt->rr.dlsr = 0; 
    307426    } else { 
    308427        pj_timestamp ts; 
    309         pj_uint32_t lsr = session->rx_lsr; 
    310         pj_uint64_t lsr_time = session->rx_lsr_time.u64; 
     428        pj_uint32_t lsr = sess->rx_lsr; 
     429        pj_uint64_t lsr_time = sess->rx_lsr_time.u64; 
    311430        pj_uint32_t dlsr; 
    312431         
    313432        /* Convert LSR time to 1/65536 seconds resolution */ 
    314         lsr_time = (lsr_time << 16) / session->ts_freq.u64; 
     433        lsr_time = (lsr_time << 16) / sess->ts_freq.u64; 
    315434 
    316435        /* Fill in LSR. 
     
    325444 
    326445        /* Convert interval to 1/65536 seconds value */ 
    327         ts.u64 = (ts.u64 << 16) / session->ts_freq.u64; 
     446        ts.u64 = (ts.u64 << 16) / sess->ts_freq.u64; 
    328447 
    329448        /* Get DLSR */ 
     
    341460    } 
    342461     
     462    /* Update counter */ 
     463    pj_gettimeofday(&sess->stat.rx.update); 
     464    sess->stat.rx.update_cnt++; 
     465 
    343466 
    344467    /* Return pointer. */ 
  • pjproject/trunk/pjmedia/src/pjmedia/rtp.c

    r223 r390  
    3535#define MIN_SEQUENTIAL  ((pj_int16_t)2) 
    3636 
     37static void pjmedia_rtp_seq_restart(pjmedia_rtp_seq_session *seq_ctrl,  
     38                                    pj_uint16_t seq); 
     39 
    3740 
    3841PJ_DEF(pj_status_t) pjmedia_rtp_session_init( pjmedia_rtp_session *ses, 
     
    162165 
    163166 
    164 PJ_DEF(pj_status_t) pjmedia_rtp_session_update( pjmedia_rtp_session *ses, const pjmedia_rtp_hdr *hdr) 
    165 { 
    166     int status; 
     167PJ_DEF(void) pjmedia_rtp_session_update( pjmedia_rtp_session *ses,  
     168                                         const pjmedia_rtp_hdr *hdr, 
     169                                         pjmedia_rtp_status *p_seq_st) 
     170{ 
     171    pjmedia_rtp_status seq_st; 
    167172 
    168173    /* Check SSRC. */ 
     
    176181    */ 
    177182 
     183    /* Init status */ 
     184    seq_st.status.value = 0; 
     185    seq_st.diff = 0; 
     186 
    178187    /* Check payload type. */ 
    179188    if (hdr->pt != ses->out_pt) { 
    180         PJ_LOG(4, (THIS_FILE, "pjmedia_rtp_session_update: ses=%p, invalid payload type %d (!=%d)", 
     189        PJ_LOG(4, (THIS_FILE,  
     190                   "pjmedia_rtp_session_update: ses=%p, invalid payload " 
     191                   "type %d (expecting %d)", 
    181192                   ses, hdr->pt, ses->out_pt)); 
    182         return PJMEDIA_RTP_EINPT; 
     193        if (p_seq_st) { 
     194            p_seq_st->status.flag.bad = 1; 
     195            p_seq_st->status.flag.badpt = 1; 
     196        } 
     197        return; 
    183198    } 
    184199 
     
    188203 
    189204    /* Check sequence number to see if remote session has been restarted. */ 
    190     status = pjmedia_rtp_seq_update( &ses->seq_ctrl, pj_ntohs(hdr->seq)); 
    191     if (status == PJMEDIA_RTP_ESESSRESTART) { 
    192         pjmedia_rtp_seq_restart( &ses->seq_ctrl, pj_ntohs(hdr->seq)); 
     205    pjmedia_rtp_seq_update( &ses->seq_ctrl, pj_ntohs(hdr->seq), &seq_st); 
     206    if (seq_st.status.flag.restart) { 
    193207        ++ses->received; 
    194     } else if (status == 0 || status == PJMEDIA_RTP_ESESSPROBATION) { 
     208 
     209    } else if (!seq_st.status.flag.bad) { 
    195210        ++ses->received; 
    196211    } 
    197212 
    198  
    199     return status; 
    200 } 
    201  
    202  
    203 void pjmedia_rtp_seq_restart(pjmedia_rtp_seq_session *sctrl, pj_uint16_t seq) 
    204 { 
    205     sctrl->base_seq = seq; 
    206     sctrl->max_seq = seq; 
    207     sctrl->bad_seq = RTP_SEQ_MOD + 1; 
    208     sctrl->cycles = 0; 
    209 } 
    210  
    211  
    212 void pjmedia_rtp_seq_init(pjmedia_rtp_seq_session *sctrl, pj_uint16_t seq) 
    213 { 
    214     pjmedia_rtp_seq_restart(sctrl, seq); 
    215  
    216     sctrl->max_seq = (pj_uint16_t) (seq - 1); 
    217     sctrl->probation = MIN_SEQUENTIAL; 
    218 } 
    219  
    220  
    221 pj_status_t pjmedia_rtp_seq_update(pjmedia_rtp_seq_session *sctrl,  
    222                                    pj_uint16_t seq) 
    223 { 
    224     pj_uint16_t udelta = (pj_uint16_t) (seq - sctrl->max_seq); 
     213    if (p_seq_st) { 
     214        p_seq_st->status.value = seq_st.status.value; 
     215        p_seq_st->diff = seq_st.diff; 
     216    } 
     217} 
     218 
     219 
     220void pjmedia_rtp_seq_restart(pjmedia_rtp_seq_session *sess, pj_uint16_t seq) 
     221{ 
     222    sess->base_seq = seq; 
     223    sess->max_seq = seq; 
     224    sess->bad_seq = RTP_SEQ_MOD + 1; 
     225    sess->cycles = 0; 
     226} 
     227 
     228 
     229void pjmedia_rtp_seq_init(pjmedia_rtp_seq_session *sess, pj_uint16_t seq) 
     230{ 
     231    pjmedia_rtp_seq_restart(sess, seq); 
     232 
     233    sess->max_seq = (pj_uint16_t) (seq - 1); 
     234    sess->probation = MIN_SEQUENTIAL; 
     235} 
     236 
     237 
     238void pjmedia_rtp_seq_update( pjmedia_rtp_seq_session *sess,  
     239                             pj_uint16_t seq, 
     240                             pjmedia_rtp_status *seq_status) 
     241{ 
     242    pj_uint16_t udelta = (pj_uint16_t) (seq - sess->max_seq); 
     243    pjmedia_rtp_status st; 
    225244     
     245    /* Init status */ 
     246    st.status.value = 0; 
     247    st.diff = 0; 
     248 
    226249    /* 
    227250     * Source is not valid until MIN_SEQUENTIAL packets with 
    228251     * sequential sequence numbers have been received. 
    229252     */ 
    230     if (sctrl->probation) { 
    231         /* packet is in sequence */ 
    232         if (seq == sctrl->max_seq+ 1) { 
    233             sctrl->probation--; 
    234             sctrl->max_seq = seq; 
    235             if (sctrl->probation == 0) { 
    236                 return PJMEDIA_RTP_ESESSRESTART; 
     253    if (sess->probation) { 
     254 
     255        st.status.flag.probation = 1; 
     256         
     257        if (seq == sess->max_seq+ 1) { 
     258            /* packet is in sequence */ 
     259            st.diff = 1; 
     260            sess->probation--; 
     261            sess->max_seq = seq; 
     262            if (sess->probation == 0) { 
     263                st.status.flag.probation = 0; 
    237264            } 
    238265        } else { 
    239             sctrl->probation = MIN_SEQUENTIAL - 1; 
    240             sctrl->max_seq = seq; 
     266 
     267            st.diff = 0; 
     268 
     269            st.status.flag.bad = 1; 
     270            if (seq == sess->max_seq) 
     271                st.status.flag.dup = 1; 
     272            else 
     273                st.status.flag.outorder = 1; 
     274 
     275            sess->probation = MIN_SEQUENTIAL - 1; 
     276            sess->max_seq = seq; 
    241277        } 
    242         return PJMEDIA_RTP_ESESSPROBATION; 
     278 
     279 
     280    } else if (udelta == 0) { 
     281 
     282        st.status.flag.dup = 1; 
    243283 
    244284    } else if (udelta < MAX_DROPOUT) { 
    245285        /* in order, with permissible gap */ 
    246         if (seq < sctrl->max_seq) { 
     286        if (seq < sess->max_seq) { 
    247287            /* Sequence number wrapped - count another 64K cycle. */ 
    248             sctrl->cycles += RTP_SEQ_MOD; 
     288            sess->cycles += RTP_SEQ_MOD; 
    249289        } 
    250         sctrl->max_seq = seq; 
     290        sess->max_seq = seq; 
     291 
     292        st.diff = udelta; 
    251293 
    252294    } else if (udelta <= (RTP_SEQ_MOD - MAX_MISORDER)) { 
    253295        /* the sequence number made a very large jump */ 
    254         if (seq == sctrl->bad_seq) { 
     296        if (seq == sess->bad_seq) { 
    255297            /* 
    256298             * Two sequential packets -- assume that the other side 
     
    258300             * (i.e., pretend this was the first packet). 
    259301             */ 
    260             return PJMEDIA_RTP_ESESSRESTART; 
     302            pjmedia_rtp_seq_restart(sess, seq); 
     303            st.status.flag.restart = 1; 
     304            st.status.flag.probation = 1; 
     305            st.diff = 1; 
    261306        } 
    262307        else { 
    263             sctrl->bad_seq = (seq + 1) & (RTP_SEQ_MOD-1); 
    264             return PJMEDIA_RTP_EBADSEQ; 
     308            sess->bad_seq = (seq + 1) & (RTP_SEQ_MOD-1); 
     309            st.status.flag.bad = 1; 
     310            st.status.flag.outorder = 1; 
    265311        } 
    266312    } else { 
    267         /* duplicate or reordered packet */ 
     313        /* old duplicate or reordered packet. 
     314         * Not necessarily bad packet (?) 
     315         */ 
     316        st.status.flag.outorder = 1; 
    268317    } 
    269318     
    270     return PJ_SUCCESS; 
    271 } 
    272  
    273  
     319 
     320    if (seq_status) { 
     321        seq_status->diff = st.diff; 
     322        seq_status->status.value = st.status.value; 
     323    } 
     324} 
     325 
     326 
  • pjproject/trunk/pjmedia/src/pjmedia/session.c

    r374 r390  
    526526PJ_DEF(pj_status_t) pjmedia_session_get_stream_stat( pjmedia_session *session, 
    527527                                                     unsigned index, 
    528                                                      pjmedia_stream_stat *stat) 
     528                                                     pjmedia_rtcp_stat *stat) 
    529529{ 
    530530    PJ_ASSERT_RETURN(session && stat && index < session->stream_cnt,  
  • pjproject/trunk/pjmedia/src/pjmedia/stream.c

    r381 r390  
    3838#define ERRLEVEL                        1 
    3939#define TRACE_(expr)                    stream_perror expr 
    40  
     40#define TRC_(expr)                      PJ_LOG(4,expr) 
    4141#define PJMEDIA_MAX_FRAME_DURATION_MS   200 
    4242#define PJMEDIA_MAX_BUFFER_SIZE_MS      2000 
     
    4444#define PJMEDIA_DTMF_DURATION           1600    /* in timestamp */ 
    4545#define PJMEDIA_RTP_NAT_PROBATION_CNT   10 
     46#define PJMEDIA_RTCP_INTERVAL           5       /* seconds      */ 
    4647 
    4748 
     
    8889 
    8990    pjmedia_dir              dir;           /**< Stream direction.          */ 
    90     pjmedia_stream_stat      stat;          /**< Stream statistics.         */ 
    9191    void                    *user_data;     /**< User data.                 */ 
    9292 
     
    111111    pj_ioqueue_key_t        *rtcp_key;      /**< RTCP ioqueue key.          */ 
    112112    pj_ioqueue_op_key_t      rtcp_op_key;   /**< The pending read op key.   */ 
    113  
     113    pj_size_t                rtcp_pkt_size; /**< Size of RTCP packet buf.   */ 
     114    char                     rtcp_pkt[512]; /**< RTCP packet buffer.        */ 
     115    pj_uint32_t              rtcp_tx_time;  /**< RTCP tx time in timestamp  */ 
     116    int                      rtcp_addrlen;  /**< Address length.            */ 
    114117 
    115118    /* RFC 2833 DTMF transmission queue: */ 
     
    270273    struct pjmedia_frame frame_out; 
    271274    int ts_len; 
     275    pj_bool_t has_tx; 
    272276    void *rtphdr; 
    273277    int rtphdrlen; 
     
    279283    /* Init frame_out buffer. */ 
    280284    frame_out.buf = ((char*)channel->out_pkt) + sizeof(pjmedia_rtp_hdr); 
     285 
     286    /* Make compiler happy */ 
     287    frame_out.size = 0; 
    281288 
    282289    /* If we have DTMF digits in the queue, transmit the digits.  
     
    285292    if (stream->tx_dtmf_count) { 
    286293 
     294        has_tx = PJ_TRUE; 
    287295        create_dtmf_payload(stream, &frame_out); 
    288296 
     
    297305        unsigned max_size; 
    298306 
     307        has_tx = PJ_TRUE; 
    299308        max_size = channel->out_pkt_size - sizeof(pjmedia_rtp_hdr); 
    300309        status = stream->codec->op->encode( stream->codec, frame,  
     
    317326 
    318327        /* Just update RTP session's timestamp. */ 
     328        has_tx = PJ_FALSE; 
    319329        status = pjmedia_rtp_encode_rtp( &channel->rtp,  
    320330                                         0, 0,  
     
    322332                                         (const void**)&rtphdr,  
    323333                                         &rtphdrlen); 
    324         return PJ_SUCCESS; 
    325  
    326     } 
    327  
    328     if (status != 0) { 
     334 
     335    } 
     336 
     337    if (status != PJ_SUCCESS) { 
    329338        TRACE_((THIS_FILE, "RTP encode_rtp() error", status)); 
    330339        return status; 
    331340    } 
     341 
     342    /* Check if this is the time to transmit RTCP packet */ 
     343    if (stream->rtcp_tx_time == 0) { 
     344        stream->rtcp_tx_time = pj_ntohl(channel->rtp.out_hdr.ts) + 
     345                               PJMEDIA_RTCP_INTERVAL *  
     346                               stream->port.info.sample_rate; 
     347    } else if (pj_ntohl(channel->rtp.out_hdr.ts) >= stream->rtcp_tx_time) { 
     348         
     349        pjmedia_rtcp_pkt *rtcp_pkt; 
     350        pj_ssize_t size; 
     351        int len; 
     352 
     353        pjmedia_rtcp_build_rtcp(&stream->rtcp, &rtcp_pkt, &len); 
     354        size = len; 
     355        status = pj_sock_sendto(stream->skinfo.rtcp_sock, rtcp_pkt, &size, 0, 
     356                                &stream->rem_rtcp_addr,  
     357                                sizeof(stream->rem_rtcp_addr)); 
     358        if (status != PJ_SUCCESS) { 
     359            ; 
     360        } 
     361         
     362        stream->rtcp_tx_time = pj_ntohl(channel->rtp.out_hdr.ts) + 
     363                               PJMEDIA_RTCP_INTERVAL *  
     364                               stream->port.info.sample_rate; 
     365    } 
     366 
     367    /* Do nothing if we have nothing to transmit */ 
     368    if (!has_tx) 
     369        return PJ_SUCCESS; 
    332370 
    333371    if (rtphdrlen != sizeof(pjmedia_rtp_hdr)) { 
    334372        /* We don't support RTP with extended header yet. */ 
    335373        PJ_TODO(SUPPORT_SENDING_RTP_WITH_EXTENDED_HEADER); 
    336         //TRACE_((THIS_FILE, "Unsupported extended RTP header for transmission")); 
    337         return 0; 
     374        return PJ_SUCCESS; 
    338375    } 
    339376 
     
    342379    /* Send. */ 
    343380    sent = frame_out.size+sizeof(pjmedia_rtp_hdr); 
    344     status = pj_sock_sendto(stream->skinfo.rtp_sock, channel->out_pkt, &sent, 0,  
    345                             &stream->rem_rtp_addr, sizeof(stream->rem_rtp_addr)); 
     381    status = pj_sock_sendto(stream->skinfo.rtp_sock, channel->out_pkt,  
     382                            &sent, 0, &stream->rem_rtp_addr,  
     383                            sizeof(stream->rem_rtp_addr)); 
    346384    if (status != PJ_SUCCESS) 
    347385        return status; 
    348386 
    349387    /* Update stat */ 
    350     stream->stat.enc.pkt++; 
    351     stream->stat.enc.bytes += frame_out.size+sizeof(pjmedia_rtp_hdr); 
     388    pjmedia_rtcp_tx_rtp(&stream->rtcp, frame_out.size); 
    352389 
    353390    return PJ_SUCCESS; 
     
    460497        const void *payload; 
    461498        unsigned payloadlen; 
     499        pjmedia_rtp_status seq_st; 
    462500 
    463501        /* Go straight to read next packet if bytes_read == 0. 
     
    477515 
    478516 
     517        /* Inform RTCP session */ 
     518        pjmedia_rtcp_rx_rtp(&stream->rtcp, pj_ntohs(hdr->seq), 
     519                            pj_ntohl(hdr->ts), payloadlen); 
     520 
    479521        /* Handle incoming DTMF. */ 
    480522        if (hdr->pt == stream->rx_event_pt) { 
     
    487529         * the incoming packet. 
    488530         */ 
    489         status = pjmedia_rtp_session_update(&channel->rtp, hdr); 
    490         if (status != 0 &&  
    491             status != PJMEDIA_RTP_ESESSPROBATION &&  
    492             status != PJMEDIA_RTP_ESESSRESTART)  
    493         { 
    494             TRACE_((THIS_FILE, "RTP session_update error (details follows)",  
    495                     status)); 
    496             PJ_LOG(4,(THIS_FILE,"RTP packet detail: pt=%d, seq=%d", 
    497                       hdr->pt, pj_ntohs(hdr->seq))); 
     531        pjmedia_rtp_session_update(&channel->rtp, hdr, &seq_st); 
     532        if (seq_st.status.flag.bad) { 
     533            TRC_  ((THIS_FILE,  
     534                    "RTP session_update error: badpt=%d, dup=%d, outorder=%d, " 
     535                    "probation=%d, restart=%d",  
     536                    seq_st.status.flag.badpt, 
     537                    seq_st.status.flag.dup, 
     538                    seq_st.status.flag.outorder, 
     539                    seq_st.status.flag.probation, 
     540                    seq_st.status.flag.restart)); 
    498541            goto read_next_packet; 
    499542        } 
    500  
    501  
    502         /* Update the RTCP session. */ 
    503         pjmedia_rtcp_rx_rtp(&stream->rtcp, pj_ntohs(hdr->seq),  
    504                             pj_ntohl(hdr->ts)); 
    505  
    506  
    507         /* Update stat */ 
    508         stream->stat.dec.pkt++; 
    509         stream->stat.dec.bytes += bytes_read; 
    510543 
    511544 
     
    572605                        pj_ssize_t bytes_read) 
    573606{ 
    574     PJ_UNUSED_ARG(key); 
     607    pjmedia_stream *stream = pj_ioqueue_get_user_data(key); 
     608    pj_status_t status; 
     609 
    575610    PJ_UNUSED_ARG(op_key); 
    576     PJ_UNUSED_ARG(bytes_read); 
     611 
     612    do { 
     613        if (bytes_read > 0) { 
     614            pjmedia_rtcp_rx_rtcp(&stream->rtcp, stream->rtcp_pkt,  
     615                                 bytes_read); 
     616        } 
     617 
     618        bytes_read = stream->rtcp_pkt_size; 
     619        stream->rtcp_addrlen = sizeof(stream->rem_rtcp_addr); 
     620        status = pj_ioqueue_recvfrom( stream->rtcp_key, 
     621                                      &stream->rtcp_op_key, 
     622                                      stream->rtcp_pkt, 
     623                                      &bytes_read, 0, 
     624                                      &stream->rem_rtcp_addr, 
     625                                      &stream->rtcp_addrlen); 
     626 
     627    } while (status == PJ_SUCCESS); 
     628 
     629    if (status != PJ_SUCCESS && status != PJ_EPENDING) { 
     630        char errmsg[PJ_ERR_MSG_SIZE]; 
     631 
     632        pj_strerror(status, errmsg, sizeof(errmsg)); 
     633        PJ_LOG(4,(THIS_FILE, "Error reading RTCP packet: %s [status=%d]", 
     634                             errmsg, status)); 
     635    } 
     636 
    577637} 
    578638 
     
    659719    pjmedia_codec_param codec_param; 
    660720    pj_ioqueue_callback ioqueue_cb; 
     721    pj_uint16_t rtcp_port; 
    661722    pj_status_t status; 
    662723 
     
    691752    stream->skinfo = info->sock_info; 
    692753    stream->rem_rtp_addr = info->rem_addr; 
     754    rtcp_port = (pj_uint16_t) (pj_ntohs(info->rem_addr.sin_port)+1); 
     755    stream->rem_rtcp_addr = stream->rem_rtp_addr; 
     756    stream->rem_rtcp_addr.sin_port = pj_htons(rtcp_port); 
    693757    stream->tx_event_pt = info->tx_event_pt; 
    694758    stream->rx_event_pt = info->rx_event_pt; 
    695759    stream->last_dtmf = -1; 
    696  
    697  
    698     PJ_TODO(INITIALIZE_RTCP_REMOTE_ADDRESS); 
    699760 
    700761    /* Create mutex to protect jitter buffer: */ 
     
    739800    /* Init RTCP session: */ 
    740801 
    741     pjmedia_rtcp_init(&stream->rtcp, info->fmt.sample_rate, info->ssrc); 
     802    pjmedia_rtcp_init(&stream->rtcp, info->fmt.sample_rate,  
     803                      stream->port.info.samples_per_frame,  
     804                      info->ssrc); 
    742805 
    743806 
     
    800863    pj_ioqueue_op_key_init(&stream->rtcp_op_key, sizeof(stream->rtcp_op_key)); 
    801864 
     865    stream->rtcp_pkt_size = sizeof(stream->rtcp_pkt); 
     866 
    802867    /* Bootstrap the first recvfrom() operation. */ 
    803868    on_rx_rtcp( stream->rtcp_key, &stream->rtcp_op_key, 0); 
     
    901966 */ 
    902967PJ_DEF(pj_status_t) pjmedia_stream_get_stat( const pjmedia_stream *stream, 
    903                                              pjmedia_stream_stat *stat) 
     968                                             pjmedia_rtcp_stat *stat) 
    904969{ 
    905970    PJ_ASSERT_RETURN(stream && stat, PJ_EINVAL); 
    906971 
    907     pj_memcpy(stat, &stream->stat, sizeof(pjmedia_stream_stat)); 
    908  
     972    pj_memcpy(stat, &stream->rtcp.stat, sizeof(pjmedia_rtcp_stat)); 
    909973    return PJ_SUCCESS; 
    910974} 
  • pjproject/trunk/pjsip-apps/src/samples/siprtp.c

    r389 r390  
    5252 
    5353 
    54 /* Unidirectional media stat: */ 
    55 struct stream_stat 
    56 { 
    57     pj_uint32_t     pkt, payload; 
    58     pj_uint32_t     discard, reorder; 
    59     unsigned        loss_min, loss_avg, loss_max; 
    60     char           *loss_type; 
    61     unsigned        jitter_min_us, jitter_avg_us, jitter_max_us; 
    62     unsigned        rtcp_cnt; 
    63 }; 
    64  
    65  
    6654/* A bidirectional media stream */ 
    6755struct media_stream 
     
    8876    /* RTCP stats: */ 
    8977    pjmedia_rtcp_session rtcp;              /* incoming RTCP session.   */ 
    90     pjmedia_rtcp_pkt     rem_rtcp;          /* received RTCP stat.      */ 
    91  
    92     /* More stats: */ 
    93     struct stream_stat   rx_stat;           /* incoming stream stat     */ 
    94     struct stream_stat   tx_stat;           /* outgoing stream stat.    */ 
    9578 
    9679    /* Thread: */ 
     
    10741057            } 
    10751058 
    1076             ++strm->rx_stat.pkt; 
    1077             strm->rx_stat.payload += (size - 12); 
    10781059 
    10791060            /* Decode RTP packet. */ 
     
    10841065            if (status != PJ_SUCCESS) { 
    10851066                app_perror(THIS_FILE, "RTP decode error", status); 
    1086                 strm->rx_stat.discard++; 
    10871067                continue; 
    10881068            } 
    10891069 
    1090             /* Update RTP session */ 
    1091             status = pjmedia_rtp_session_update(&strm->in_sess, hdr); 
    1092             if (status != PJ_SUCCESS &&  
    1093                 status != PJMEDIA_RTP_ESESSPROBATION &&  
    1094                 status != PJMEDIA_RTP_ESESSRESTART)  
    1095             { 
    1096                 app_perror(THIS_FILE, "RTP update error", status); 
    1097                 PJ_LOG(3,(THIS_FILE,"RTP packet detail: pt=%d, seq=%d", 
    1098                           hdr->pt, pj_ntohs(hdr->seq))); 
    1099                 strm->rx_stat.discard++; 
    1100                 continue; 
    1101             } 
    1102  
    11031070            /* Update the RTCP session. */ 
    11041071            pjmedia_rtcp_rx_rtp(&strm->rtcp, pj_ntohs(hdr->seq), 
    1105                                 pj_ntohl(hdr->ts)); 
    1106  
     1072                                pj_ntohl(hdr->ts), payload_len); 
     1073 
     1074            /* Update RTP session */ 
     1075            pjmedia_rtp_session_update(&strm->in_sess, hdr, NULL); 
    11071076        }  
    11081077         
     
    11191088            if (status != PJ_SUCCESS) 
    11201089                app_perror(THIS_FILE, "Error receiving RTCP packet", status); 
    1121             else { 
    1122                 if (size != sizeof(strm->rem_rtcp)) { 
    1123                     PJ_LOG(3,(THIS_FILE, "Error: RTCP packet size mismatch " 
    1124                                          "(recv %d bytes, expecting %d)", 
    1125                                          size, sizeof(strm->rem_rtcp))); 
    1126                     status = -1; 
    1127                 } else { 
    1128                     pj_memcpy(&strm->rem_rtcp, packet, size); 
    1129                     status = PJ_SUCCESS; 
    1130  
    1131                     /* Report receipt of RTCP to RTCP session */ 
    1132                     pjmedia_rtcp_rx_rtcp(&strm->rtcp, packet, size); 
    1133                 } 
    1134             } 
    1135  
    1136             if (status == PJ_SUCCESS) { 
    1137                 /* Process RTCP stats */ 
    1138                 unsigned jitter; 
    1139                  
    1140                 jitter = (unsigned)(pj_ntohl(strm->rem_rtcp.rr.jitter) *  
    1141                                     1000000.0 / strm->clock_rate); 
    1142                 if (jitter < strm->tx_stat.jitter_min_us) 
    1143                     strm->tx_stat.jitter_min_us = jitter; 
    1144                 if (jitter > strm->tx_stat.jitter_max_us) 
    1145                     strm->tx_stat.jitter_max_us = jitter; 
    1146                 strm->tx_stat.jitter_avg_us =  
    1147                         (strm->tx_stat.jitter_avg_us * strm->tx_stat.rtcp_cnt + 
    1148                          jitter) / (strm->tx_stat.rtcp_cnt + 1); 
    1149  
    1150                 strm->tx_stat.rtcp_cnt++; 
    1151             } 
     1090            else 
     1091                pjmedia_rtcp_rx_rtcp(&strm->rtcp, packet, size); 
    11521092        } 
    11531093 
     
    11941134            /* Schedule next send */ 
    11951135            next_rtp.u64 += (msec_interval * freq.u64 / 1000); 
    1196  
    1197             /* Update stats */ 
    1198             strm->tx_stat.pkt++; 
    1199             strm->tx_stat.payload += strm->bytes_per_frame; 
    12001136        } 
    12011137 
     
    12291165            } 
    12301166             
    1231  
    1232             /* Process RTCP stats */ 
    1233             { 
    1234                 unsigned jitter; 
    1235                  
    1236                 jitter = (unsigned) (pj_ntohl(rtcp_pkt->rr.jitter) *  
    1237                                      1000000.0 / strm->clock_rate); 
    1238                 if (jitter < strm->rx_stat.jitter_min_us) 
    1239                     strm->rx_stat.jitter_min_us = jitter; 
    1240                 if (jitter > strm->rx_stat.jitter_max_us) 
    1241                     strm->rx_stat.jitter_max_us = jitter; 
    1242                 strm->rx_stat.jitter_avg_us =  
    1243                         (strm->rx_stat.jitter_avg_us * strm->rx_stat.rtcp_cnt + 
    1244                          jitter) / (strm->rx_stat.rtcp_cnt + 1); 
    1245  
    1246                 strm->rx_stat.rtcp_cnt++; 
    1247             } 
    1248  
     1167            /* Schedule next send */ 
    12491168            next_rtcp.u64 += (freq.u64 * RTCP_INTERVAL); 
    12501169        } 
     
    13191238                             pj_rand()); 
    13201239    pjmedia_rtp_session_init(&audio->in_sess, audio->si.fmt.pt, 0); 
    1321     pjmedia_rtcp_init(&audio->rtcp, audio->clock_rate, 0); 
    1322  
    1323  
    1324     /* Clear media statistics */ 
    1325     pj_memset(&audio->rx_stat, 0, sizeof(audio->rx_stat)); 
    1326     pj_memset(&audio->tx_stat, 0, sizeof(audio->tx_stat)); 
     1240    pjmedia_rtcp_init(&audio->rtcp, audio->clock_rate,  
     1241                      audio->samples_per_frame, 0); 
     1242 
    13271243 
    13281244 
     
    14111327    struct media_stream *audio = &call->media[0]; 
    14121328    char userinfo[128]; 
    1413     char duration[80]; 
     1329    char duration[80], last_update[80]; 
    14141330    char bps[16], ipbps[16], packets[16], bytes[16], ipbytes[16]; 
    1415     pj_uint32_t total_loss; 
    1416  
     1331    pj_time_val now; 
     1332 
     1333    pj_gettimeofday(&now); 
    14171334 
    14181335    /* Print duration */ 
    14191336    if (inv->state >= PJSIP_INV_STATE_CONFIRMED) { 
    1420         pj_time_val now; 
    1421  
    1422         pj_gettimeofday(&now); 
     1337 
    14231338        PJ_TIME_VAL_SUB(now, call->connect_time); 
    14241339 
     
    14891404        good_number(ipbps, (audio->bytes_per_frame+32) * audio->clock_rate / audio->samples_per_frame)); 
    14901405 
    1491     total_loss = (audio->rtcp.rtcp_pkt.rr.total_lost_2 << 16) + 
    1492                  (audio->rtcp.rtcp_pkt.rr.total_lost_1 << 8) + 
    1493                  audio->rtcp.rtcp_pkt.rr.total_lost_0; 
    1494  
    1495     printf("              RX total %s packets %sB received (%sB +IP hdr)%s\n" 
    1496            "                 pkt discards=%d (%3.1f%%), loss=%d (%3.1f%%), reorder=%d (%3.1f%%)%s\n" 
    1497            "                 loss period min=%dms, avg=%dms, max=%dms%s\n" 
    1498            "                 jitter min=%5.3fms, avg=%5.3fms, max=%5.3fms, curr=%5.3f ms%s\n", 
    1499            good_number(packets, audio->rx_stat.pkt), 
    1500            good_number(bytes, audio->rx_stat.payload), 
    1501            good_number(ipbytes, audio->rx_stat.payload + audio->rx_stat.pkt * 32), 
     1406    if (audio->rtcp.stat.rx.update_cnt == 0) 
     1407        strcpy(last_update, "never"); 
     1408    else { 
     1409        pj_gettimeofday(&now); 
     1410        PJ_TIME_VAL_SUB(now, audio->rtcp.stat.rx.update); 
     1411        sprintf(last_update, "%02dh:%02dm:%02d.%03ds ago", 
     1412                now.sec / 3600, 
     1413                (now.sec % 3600) / 60, 
     1414                now.sec % 60, 
     1415                now.msec); 
     1416    } 
     1417 
     1418    printf("              RX stat last update: %s\n" 
     1419           "                 total %s packets %sB received (%sB +IP hdr)%s\n" 
     1420           "                 pkt loss=%d (%3.1f%%), dup=%d (%3.1f%%), reorder=%d (%3.1f%%)%s\n" 
     1421           "                 loss period min=%5.3fms, avg=%5.3fms, max=%5.3fms, last=%5.3f%s\n" 
     1422           "                 jitter min=%5.3fms, avg=%5.3fms, max=%5.3fms, last=%5.3fms%s\n", 
     1423           last_update, 
     1424           good_number(packets, audio->rtcp.stat.rx.pkt), 
     1425           good_number(bytes, audio->rtcp.stat.rx.bytes), 
     1426           good_number(ipbytes, audio->rtcp.stat.rx.bytes + audio->rtcp.stat.rx.pkt * 32), 
    15021427           "", 
    1503            audio->rx_stat.discard,  
    1504            audio->rx_stat.discard * 100.0 / audio->rx_stat.pkt, 
    1505            total_loss, 
    1506            total_loss * 100.0 / audio->rx_stat.pkt, 
    1507            0, 0.0, 
     1428           audio->rtcp.stat.rx.loss, 
     1429           audio->rtcp.stat.rx.loss * 100.0 / audio->rtcp.stat.rx.pkt, 
     1430           audio->rtcp.stat.rx.dup,  
     1431           audio->rtcp.stat.rx.dup * 100.0 / audio->rtcp.stat.rx.pkt, 
     1432           audio->rtcp.stat.rx.reorder,  
     1433           audio->rtcp.stat.rx.reorder * 100.0 / audio->rtcp.stat.rx.pkt, 
    15081434           "", 
    1509            -1, -1, -1,  
     1435           audio->rtcp.stat.rx.loss_period.min / 1000.0,  
     1436           audio->rtcp.stat.rx.loss_period.avg / 1000.0,  
     1437           audio->rtcp.stat.rx.loss_period.max / 1000.0, 
     1438           audio->rtcp.stat.rx.loss_period.last / 1000.0, 
    15101439           "", 
    1511            (audio->rx_stat.rtcp_cnt? audio->rx_stat.jitter_min_us/1000.0 : -1.), 
    1512            (audio->rx_stat.rtcp_cnt? audio->rx_stat.jitter_avg_us/1000.0 : -1.), 
    1513            (audio->rx_stat.rtcp_cnt? audio->rx_stat.jitter_max_us/1000.0 : -1.), 
    1514            (audio->rx_stat.rtcp_cnt? pj_ntohl(audio->rtcp.rtcp_pkt.rr.jitter)*1000.0/audio->clock_rate : -1.), 
     1440           audio->rtcp.stat.rx.jitter.min / 1000.0, 
     1441           audio->rtcp.stat.rx.jitter.avg / 1000.0, 
     1442           audio->rtcp.stat.rx.jitter.max / 1000.0, 
     1443           audio->rtcp.stat.rx.jitter.last / 1000.0, 
    15151444           "" 
    15161445           ); 
    15171446 
    15181447 
    1519     total_loss = (audio->rem_rtcp.rr.total_lost_2 << 16) + 
    1520                  (audio->rem_rtcp.rr.total_lost_1 << 8) + 
    1521                   audio->rem_rtcp.rr.total_lost_0; 
    1522  
    1523     printf("              TX total %s packets %sB sent (%sB +IP hdr)%s\n" 
    1524            "                 pkt discards=%d (%3.1f%%), loss=%d (%3.1f%%), reorder=%d (%3.1f%%)%s\n" 
    1525            "                 loss period min=%dms, avg=%dms, max=%dms%s\n" 
    1526            "                 jitter min=%5.3fms, avg=%5.3fms, max=%5.3fms, curr=%5.3f ms%s\n", 
    1527            good_number(packets, audio->tx_stat.pkt), 
    1528            good_number(bytes, audio->tx_stat.payload), 
    1529            good_number(ipbytes, audio->tx_stat.payload + audio->tx_stat.pkt * 32), 
     1448    if (audio->rtcp.stat.tx.update_cnt == 0) 
     1449        strcpy(last_update, "never"); 
     1450    else { 
     1451        pj_gettimeofday(&now); 
     1452        PJ_TIME_VAL_SUB(now, audio->rtcp.stat.tx.update); 
     1453        sprintf(last_update, "%02dh:%02dm:%02d.%03ds ago", 
     1454                now.sec / 3600, 
     1455                (now.sec % 3600) / 60, 
     1456                now.sec % 60, 
     1457                now.msec); 
     1458    } 
     1459 
     1460    printf("              TX stat last update: %s\n" 
     1461           "                 total %s packets %sB received (%sB +IP hdr)%s\n" 
     1462           "                 pkt loss=%d (%3.1f%%), dup=%d (%3.1f%%), reorder=%d (%3.1f%%)%s\n" 
     1463           "                 loss period min=%5.3fms, avg=%5.3fms, max=%5.3fms, last=%5.3f%s\n" 
     1464           "                 jitter min=%5.3fms, avg=%5.3fms, max=%5.3fms, last=%5.3fms%s\n", 
     1465           last_update, 
     1466           good_number(packets, audio->rtcp.stat.tx.pkt), 
     1467           good_number(bytes, audio->rtcp.stat.tx.bytes), 
     1468           good_number(ipbytes, audio->rtcp.stat.tx.bytes + audio->rtcp.stat.tx.pkt * 32), 
    15301469           "", 
    1531            audio->tx_stat.discard,  
    1532            audio->tx_stat.discard * 100.0 / audio->tx_stat.pkt, 
    1533            total_loss, 
    1534            total_loss * 100.0 / audio->tx_stat.pkt, 
    1535            0, 0.0, 
     1470           audio->rtcp.stat.tx.loss, 
     1471           audio->rtcp.stat.tx.loss * 100.0 / audio->rtcp.stat.tx.pkt, 
     1472           audio->rtcp.stat.tx.dup,  
     1473           audio->rtcp.stat.tx.dup * 100.0 / audio->rtcp.stat.tx.pkt, 
     1474           audio->rtcp.stat.tx.reorder,  
     1475           audio->rtcp.stat.tx.reorder * 100.0 / audio->rtcp.stat.tx.pkt, 
    15361476           "", 
    1537            -1, -1, -1,  
     1477           audio->rtcp.stat.tx.loss_period.min / 1000.0,  
     1478           audio->rtcp.stat.tx.loss_period.avg / 1000.0,  
     1479           audio->rtcp.stat.tx.loss_period.max / 1000.0, 
     1480           audio->rtcp.stat.tx.loss_period.last / 1000.0, 
    15381481           "", 
    1539            (audio->tx_stat.rtcp_cnt? audio->tx_stat.jitter_min_us/1000.0 : -1.), 
    1540            (audio->tx_stat.rtcp_cnt? audio->tx_stat.jitter_avg_us/1000.0 : -1.), 
    1541            (audio->tx_stat.rtcp_cnt? audio->tx_stat.jitter_max_us/1000.0 : -1.), 
    1542            (audio->tx_stat.rtcp_cnt? pj_ntohl(audio->rem_rtcp.rr.jitter)*1000.0/audio->clock_rate : -1.), 
     1482           audio->rtcp.stat.tx.jitter.min / 1000.0, 
     1483           audio->rtcp.stat.tx.jitter.avg / 1000.0, 
     1484           audio->rtcp.stat.tx.jitter.max / 1000.0, 
     1485           audio->rtcp.stat.tx.jitter.last / 1000.0, 
    15431486           "" 
    15441487           ); 
    15451488 
    1546     printf("              End to end delay: %5.3f ms\n",  
    1547            audio->rtcp.rtt_us / 1000.0); 
     1489 
     1490    printf("             RTT min=%5.3fms, avg=%5.3fms, max=%5.3fms, last=%5.3fms%s\n",  
     1491           audio->rtcp.stat.rtt.min / 1000.0, 
     1492           audio->rtcp.stat.rtt.avg / 1000.0, 
     1493           audio->rtcp.stat.rtt.max / 1000.0, 
     1494           audio->rtcp.stat.rtt.last / 1000.0, 
     1495           "" 
     1496           ); 
    15481497 
    15491498} 
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_settings.c

    r360 r390  
    648648 
    649649    for (i=0; i<info.stream_cnt; ++i) { 
    650         pjmedia_stream_stat strm_stat; 
     650        pjmedia_rtcp_stat stat; 
    651651        const char *rem_addr; 
    652652        int rem_port; 
    653653        const char *dir; 
    654         char stxpkt[10], stxoct[10], srxpkt[10], srxoct[10]; 
    655  
    656         pjmedia_session_get_stream_stat(session, i, &strm_stat); 
     654        char last_update[40]; 
     655        char packets[16], bytes[16], ipbytes[16]; 
     656        pj_time_val now; 
     657 
     658        pjmedia_session_get_stream_stat(session, i, &stat); 
    657659        rem_addr = pj_inet_ntoa(info.stream_info[i].rem_addr.sin_addr); 
    658660        rem_port = pj_ntohs(info.stream_info[i].rem_addr.sin_port); 
     
    677679                  dir, 
    678680                  rem_addr, rem_port)); 
     681 
     682        if (stat.rx.update_cnt == 0) 
     683            strcpy(last_update, "never"); 
     684        else { 
     685            pj_gettimeofday(&now); 
     686            PJ_TIME_VAL_SUB(now, stat.rx.update); 
     687            sprintf(last_update, "%02dh:%02dm:%02d.%03ds ago", 
     688                    now.sec / 3600, 
     689                    (now.sec % 3600) / 60, 
     690                    now.sec % 60, 
     691                    now.msec); 
     692        } 
     693 
    679694        PJ_LOG(3,(THIS_FILE,  
    680                   "%s tx{pt=%d,pkt=%s,oct=%s} rx{pt=%d,pkt=%s,oct=%s}", 
    681                   "                 ", 
    682                   info.stream_info[i].tx_pt, 
    683                   good_number(stxpkt, strm_stat.enc.pkt),  
    684                   good_number(stxoct, strm_stat.enc.bytes), 
    685                   info.stream_info[i].fmt.pt, 
    686                   good_number(srxpkt, strm_stat.dec.pkt),  
    687                   good_number(srxoct, strm_stat.dec.bytes))); 
     695               "                  RX pt=%d, stat last update: %s\n" 
     696               "                     total %s packets %sB received (%sB +IP hdr)%s\n" 
     697               "                     pkt loss=%d (%3.1f%%), dup=%d (%3.1f%%), reorder=%d (%3.1f%%)%s\n" 
     698               "                           (msec)    min     avg     max     last\n" 
     699               "                     loss period: %7.3f %7.3f %7.3f %7.3f%s\n" 
     700               "                     jitter     : %7.3f %7.3f %7.3f %7.3f%s", 
     701               info.stream_info[i].fmt.pt, 
     702               last_update, 
     703               good_number(packets, stat.rx.pkt), 
     704               good_number(bytes, stat.rx.bytes), 
     705               good_number(ipbytes, stat.rx.bytes + stat.rx.pkt * 32), 
     706               "", 
     707               stat.rx.loss, 
     708               stat.rx.loss * 100.0 / stat.rx.pkt, 
     709               stat.rx.dup,  
     710               stat.rx.dup * 100.0 / stat.rx.pkt, 
     711               stat.rx.reorder,  
     712               stat.rx.reorder * 100.0 / stat.rx.pkt, 
     713               "", 
     714               stat.rx.loss_period.min / 1000.0,  
     715               stat.rx.loss_period.avg / 1000.0,  
     716               stat.rx.loss_period.max / 1000.0, 
     717               stat.rx.loss_period.last / 1000.0, 
     718               "", 
     719               stat.rx.jitter.min / 1000.0, 
     720               stat.rx.jitter.avg / 1000.0, 
     721               stat.rx.jitter.max / 1000.0, 
     722               stat.rx.jitter.last / 1000.0, 
     723               "" 
     724               )); 
     725 
     726 
     727        if (stat.tx.update_cnt == 0) 
     728            strcpy(last_update, "never"); 
     729        else { 
     730            pj_gettimeofday(&now); 
     731            PJ_TIME_VAL_SUB(now, stat.tx.update); 
     732            sprintf(last_update, "%02dh:%02dm:%02d.%03ds ago", 
     733                    now.sec / 3600, 
     734                    (now.sec % 3600) / 60, 
     735                    now.sec % 60, 
     736                    now.msec); 
     737        } 
     738 
     739        PJ_LOG(3,(THIS_FILE, 
     740               "                  TX pt=%d, stat last update: %s\n" 
     741               "                     total %s packets %sB received (%sB +IP hdr)%s\n" 
     742               "                     pkt loss=%d (%3.1f%%), dup=%d (%3.1f%%), reorder=%d (%3.1f%%)%s\n" 
     743               "                           (msec)    min     avg     max     last\n" 
     744               "                     loss period: %7.3f %7.3f %7.3f %7.3f%s\n" 
     745               "                     jitter     : %7.3f %7.3f %7.3f %7.3f%s", 
     746               info.stream_info[i].tx_pt, 
     747               last_update, 
     748               good_number(packets, stat.tx.pkt), 
     749               good_number(bytes, stat.tx.bytes), 
     750               good_number(ipbytes, stat.tx.bytes + stat.tx.pkt * 32), 
     751               "", 
     752               stat.tx.loss, 
     753               stat.tx.loss * 100.0 / stat.tx.pkt, 
     754               stat.tx.dup,  
     755               stat.tx.dup * 100.0 / stat.tx.pkt, 
     756               stat.tx.reorder,  
     757               stat.tx.reorder * 100.0 / stat.tx.pkt, 
     758               "", 
     759               stat.tx.loss_period.min / 1000.0,  
     760               stat.tx.loss_period.avg / 1000.0,  
     761               stat.tx.loss_period.max / 1000.0, 
     762               stat.tx.loss_period.last / 1000.0, 
     763               "", 
     764               stat.tx.jitter.min / 1000.0, 
     765               stat.tx.jitter.avg / 1000.0, 
     766               stat.tx.jitter.max / 1000.0, 
     767               stat.tx.jitter.last / 1000.0, 
     768               "" 
     769               )); 
     770 
     771 
     772        PJ_LOG(3,(THIS_FILE, 
     773               "                 RTT msec       : %7.3f %7.3f %7.3f %7.3f%s",  
     774               stat.rtt.min / 1000.0, 
     775               stat.rtt.avg / 1000.0, 
     776               stat.rtt.max / 1000.0, 
     777               stat.rtt.last / 1000.0, 
     778               "" 
     779               )); 
    688780 
    689781    } 
     
    713805 
    714806    /* Dump all invite sessions: */ 
    715     if (detail) { 
    716         PJ_LOG(3,(THIS_FILE, "Dumping invite sessions:")); 
    717  
    718         if (pjsua.call_cnt == 0) { 
    719  
    720             PJ_LOG(3,(THIS_FILE, "  - no sessions -")); 
    721  
    722         } else { 
    723             int i; 
    724  
    725             for (i=0; i<pjsua.max_calls; ++i) { 
    726  
    727                 if (pjsua.calls[i].inv == NULL) 
    728                     continue; 
    729  
    730                 print_call("  ", i, buf, sizeof(buf)); 
    731                 PJ_LOG(3,(THIS_FILE, "%s", buf)); 
    732  
    733                 if (pjsua.calls[i].session) 
    734                     dump_media_session(pjsua.calls[i].session); 
    735             } 
     807    PJ_LOG(3,(THIS_FILE, "Dumping invite sessions:")); 
     808 
     809    if (pjsua.call_cnt == 0) { 
     810 
     811        PJ_LOG(3,(THIS_FILE, "  - no sessions -")); 
     812 
     813    } else { 
     814        int i; 
     815 
     816        for (i=0; i<pjsua.max_calls; ++i) { 
     817 
     818            if (pjsua.calls[i].inv == NULL) 
     819                continue; 
     820 
     821            print_call("  ", i, buf, sizeof(buf)); 
     822            PJ_LOG(3,(THIS_FILE, "%s", buf)); 
     823 
     824            if (pjsua.calls[i].session) 
     825                dump_media_session(pjsua.calls[i].session); 
    736826        } 
    737827    } 
Note: See TracChangeset for help on using the changeset viewer.