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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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. */ 
Note: See TracChangeset for help on using the changeset viewer.