Changeset 397


Ignore:
Timestamp:
Apr 9, 2006 10:42:51 AM (18 years ago)
Author:
bennylp
Message:

Added code in RTCP to handle PerformanceQueryCounter? bug on Win32

Location:
pjproject/trunk/pjmedia
Files:
3 edited

Legend:

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

    r390 r397  
    230230    pj_int32_t              transit;    /**< Rel transit time for prev pkt  */ 
    231231    pj_uint32_t             jitter;     /**< Scaled jitter                  */ 
     232    pj_time_val             tv_base;    /**< Base time, in seconds.         */ 
     233    pj_timestamp            ts_base;    /**< Base system timestamp.         */ 
    232234    pj_timestamp            ts_freq;    /**< System timestamp frequency.    */ 
    233235 
     
    260262 
    261263/** 
     264 * Utility function to retrieve current NTP timestamp. 
     265 * 
     266 * @param sess              RTCP session. 
     267 * @param ntp               NTP record. 
     268 * 
     269 * @return                  PJ_SUCCESS on success. 
     270 */ 
     271PJ_DEF(pj_status_t) pjmedia_rtcp_get_ntp_time(const pjmedia_rtcp_session *sess, 
     272                                              pjmedia_rtcp_ntp_rec *ntp); 
     273 
     274 
     275/** 
    262276 * Deinitialize RTCP session. 
    263277 * 
  • pjproject/trunk/pjmedia/src/pjmedia/rtcp.c

    r394 r397  
    3535#endif 
    3636 
     37 
     38 
    3739#if 0 
    3840#   define TRACE_(x)    PJ_LOG(3,x) 
     
    4143#endif 
    4244 
     45 
    4346/* 
    4447 * Get NTP time. 
    4548 */ 
    46 static void rtcp_get_ntp_time(const pjmedia_rtcp_session *sess,  
    47                               struct pjmedia_rtcp_ntp_rec *ntp) 
    48 { 
    49     pj_time_val tv; 
     49PJ_DEF(pj_status_t) pjmedia_rtcp_get_ntp_time(const pjmedia_rtcp_session *sess, 
     50                                              pjmedia_rtcp_ntp_rec *ntp) 
     51{ 
     52/* Seconds between 1900-01-01 to 1970-01-01 */ 
     53#define NTP_DIFF    ((70 * 365 + 17) * 86400UL) 
    5054    pj_timestamp ts; 
    51  
    52     pj_gettimeofday(&tv); 
    53     pj_get_timestamp(&ts); 
    54      
     55    pj_status_t status; 
     56 
     57    status = pj_get_timestamp(&ts); 
     58 
    5559    /* Fill up the high 32bit part */ 
    56     ntp->hi = tv.sec; 
    57      
    58     /* Calculate second fractions */ 
     60    ntp->hi = (pj_uint32_t)((ts.u64 - sess->ts_base.u64) / sess->ts_freq.u64) 
     61              + sess->tv_base.sec + NTP_DIFF; 
     62 
     63    /* Calculate seconds fractions */ 
    5964    ts.u64 %= sess->ts_freq.u64; 
     65    pj_assert(ts.u64 < sess->ts_freq.u64); 
    6066    ts.u64 = (ts.u64 << 32) / sess->ts_freq.u64; 
    6167 
    6268    /* Fill up the low 32bit part */ 
    6369    ntp->lo = ts.u32.lo; 
     70 
     71 
     72#if (defined(PJ_WIN32) && PJ_WIN32!=0) || \ 
     73    (defined(PJ_WIN32_WINCE) && PJ_WIN32_WINCE!=0) 
     74 
     75    /* On Win32, since we use QueryPerformanceCounter() as the backend 
     76     * timestamp API, we need to protect against this bug: 
     77     *   Performance counter value may unexpectedly leap forward 
     78     *   http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q274323 
     79     */ 
     80    { 
     81        /* 
     82         * Compare elapsed time reported by timestamp with actual elapsed  
     83         * time. If the difference is too excessive, then we use system 
     84         * time instead. 
     85         */ 
     86 
     87        /* MIN_DIFF needs to be large enough so that "normal" diff caused 
     88         * by system activity or context switch doesn't trigger the time 
     89         * correction. 
     90         */ 
     91        enum { MIN_DIFF = 400 }; 
     92 
     93        pj_time_val ts_time, elapsed, diff; 
     94 
     95        pj_gettimeofday(&elapsed); 
     96 
     97        ts_time.sec = ntp->hi - sess->tv_base.sec - NTP_DIFF; 
     98        ts_time.msec = (long)(ntp->lo * 1000.0 / 0xFFFFFFFF); 
     99 
     100        PJ_TIME_VAL_SUB(elapsed, sess->tv_base); 
     101 
     102        if (PJ_TIME_VAL_LT(ts_time, elapsed)) { 
     103            diff = elapsed; 
     104            PJ_TIME_VAL_SUB(diff, ts_time); 
     105        } else { 
     106            diff = ts_time; 
     107            PJ_TIME_VAL_SUB(diff, elapsed); 
     108        } 
     109 
     110        if (PJ_TIME_VAL_MSEC(diff) >= MIN_DIFF) { 
     111 
     112            TRACE_((THIS_FILE, "NTP timestamp corrected by %d ms", 
     113                    PJ_TIME_VAL_MSEC(diff))); 
     114 
     115 
     116            ntp->hi = elapsed.sec + sess->tv_base.sec + NTP_DIFF; 
     117            ntp->lo = (elapsed.msec * 65536 / 1000) << 16; 
     118        } 
     119 
     120    } 
     121#endif 
     122 
     123    return status; 
    64124} 
    65125 
     
    91151    rtcp_pkt->sr.ssrc = pj_htonl(ssrc); 
    92152     
    93     /* Get timestamp frequency */ 
     153    /* Get time and timestamp base and frequency */ 
     154    pj_gettimeofday(&sess->tv_base); 
     155    pj_get_timestamp(&sess->ts_base); 
    94156    pj_get_timestamp_freq(&sess->ts_freq); 
    95157 
     
    208270{ 
    209271    const struct pjmedia_rtcp_pkt *rtcp = pkt; 
     272    pj_uint32_t last_loss, jitter_samp, jitter; 
    210273 
    211274    /* Must at least contain SR */ 
     
    219282    pj_get_timestamp(&sess->rx_lsr_time); 
    220283 
    221     TRACE_((THIS_FILE, "Rx RTCP SR: ntp-ts=%p, time=%p",  
     284    TRACE_((THIS_FILE, "Rx RTCP SR: ntp_ts=%p",  
    222285            sess->rx_lsr, 
    223286            (pj_uint32_t)(sess->rx_lsr_time.u64*65536/sess->ts_freq.u64))); 
    224287 
    225     /* Calculate RTT if it has RR */ 
    226     if (size >= sizeof(pjmedia_rtcp_pkt)) { 
     288    /* Nothing more to do if this is an SR only RTCP packet */ 
     289    if (size < sizeof(pjmedia_rtcp_pkt)) 
     290        return; 
    227291         
    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; 
     292 
     293    last_loss = sess->stat.tx.loss; 
     294 
     295    /* Get packet loss */ 
     296    sess->stat.tx.loss = (rtcp->rr.total_lost_2 << 16) + 
     297                         (rtcp->rr.total_lost_1 << 8) + 
     298                          rtcp->rr.total_lost_0; 
     299     
     300    /* We can't calculate the exact loss period for TX, so just give the 
     301     * best estimation. 
     302     */ 
     303    if (sess->stat.tx.loss > last_loss) { 
     304        unsigned period; 
     305 
     306        /* Loss period in msec */ 
     307        period = (sess->stat.tx.loss - last_loss) * sess->pkt_size * 
     308                 1000 / sess->clock_rate; 
     309 
     310        /* Loss period in usec */ 
     311        period *= 1000; 
     312 
     313        if (sess->stat.tx.update_cnt==0||sess->stat.tx.loss_period.min==0) 
     314            sess->stat.tx.loss_period.min = period; 
     315        if (period < sess->stat.tx.loss_period.min) 
     316            sess->stat.tx.loss_period.min = period; 
     317        if (period > sess->stat.tx.loss_period.max) 
     318            sess->stat.tx.loss_period.max = period; 
     319 
     320        sess->stat.tx.loss_period.avg =  
     321            (sess->stat.tx.loss_period.avg*sess->stat.tx.update_cnt+period) 
     322            / (sess->stat.tx.update_cnt + 1); 
     323        sess->stat.tx.loss_period.last = period; 
     324    } 
     325 
     326    /* Get jitter value in usec */ 
     327    jitter_samp = pj_ntohl(rtcp->rr.jitter); 
     328    /* Calculate jitter in usec, avoiding overflows */ 
     329    if (jitter_samp <= 4294) 
     330        jitter = jitter_samp * 1000000 / sess->clock_rate; 
     331    else { 
     332        jitter = jitter_samp * 1000 / sess->clock_rate; 
     333        jitter *= 1000; 
     334    } 
     335 
     336    /* Update jitter statistics */ 
     337    if (sess->stat.tx.update_cnt == 0) 
     338        sess->stat.tx.jitter.min = jitter; 
     339    if (jitter < sess->stat.tx.jitter.min && jitter) 
     340        sess->stat.tx.jitter.min = jitter; 
     341    if (jitter > sess->stat.tx.jitter.max) 
     342        sess->stat.tx.jitter.max = jitter; 
     343    sess->stat.tx.jitter.avg =  
     344        (sess->stat.tx.jitter.avg * sess->stat.tx.update_cnt + jitter) / 
     345        (sess->stat.tx.update_cnt + 1); 
     346    sess->stat.tx.jitter.last = jitter; 
     347 
     348 
     349    /* Can only calculate if LSR and DLSR is present in RR */ 
     350    if (rtcp->rr.lsr && rtcp->rr.dlsr) { 
     351        pj_uint32_t lsr, now, dlsr; 
     352        pj_uint64_t eedelay; 
     353        pjmedia_rtcp_ntp_rec ntp; 
     354 
     355        /* LSR is the middle 32bit of NTP. It has 1/65536 second  
     356         * resolution  
     357         */ 
     358        lsr = pj_ntohl(rtcp->rr.lsr); 
     359 
     360        /* DLSR is delay since LSR, also in 1/65536 resolution */ 
     361        dlsr = pj_ntohl(rtcp->rr.dlsr); 
     362 
     363        /* Get current time, and convert to 1/65536 resolution */ 
     364        pjmedia_rtcp_get_ntp_time(sess, &ntp); 
     365        now = ((ntp.hi & 0xFFFF) << 16) + (ntp.lo >> 16); 
     366 
     367        /* End-to-end delay is (now-lsr-dlsr) */ 
     368        eedelay = now - lsr - dlsr; 
     369 
     370        /* Convert end to end delay to usec (keeping the calculation in 
     371         * 64bit space):: 
     372         *   sess->ee_delay = (eedelay * 1000) / 65536; 
     373         */ 
     374        if (eedelay < 4294) { 
     375            eedelay = (eedelay * 1000000) >> 16; 
     376        } else { 
     377            eedelay = (eedelay * 1000) >> 16; 
     378            eedelay *= 1000; 
     379        } 
     380 
     381        TRACE_((THIS_FILE, "Rx RTCP RR: lsr=%p, dlsr=%p (%d:%03dms), " 
     382                           "now=%p, rtt=%p", 
     383                lsr, dlsr, dlsr/65536, (dlsr%65536)*1000/65536, 
     384                now, (pj_uint32_t)eedelay)); 
    236385         
    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; 
     386        /* Only save calculation if "now" is greater than lsr, or 
     387         * otherwise rtt will be invalid  
     388         */ 
     389        if (now-dlsr >= lsr) { 
     390            unsigned rtt = (pj_uint32_t)eedelay; 
     391             
     392            TRACE_((THIS_FILE, "RTT is set to %d usec", rtt)); 
     393 
     394            if (rtt >= 1000000) { 
     395                pjmedia_rtcp_ntp_rec ntp2; 
     396                pj_thread_sleep(50); 
     397                pjmedia_rtcp_get_ntp_time(sess, &ntp2); 
     398                ntp2.lo = ntp2.lo; 
     399            } 
     400 
     401            if (sess->stat.rtt_update_cnt == 0) 
     402                sess->stat.rtt.min = rtt; 
     403 
     404            if (rtt < sess->stat.rtt.min && rtt) 
     405                sess->stat.rtt.min = rtt; 
     406            if (rtt > sess->stat.rtt.max) 
     407                sess->stat.rtt.max = rtt; 
     408 
     409            sess->stat.rtt.avg =  
     410                (sess->stat.rtt.avg * sess->stat.rtt_update_cnt + rtt) /  
     411                (sess->stat.rtt_update_cnt + 1); 
     412 
     413            sess->stat.rtt.last = rtt; 
     414            sess->stat.rtt_update_cnt++; 
     415 
     416        } else { 
     417            PJ_LOG(5, (THIS_FILE, "Internal NTP clock skew detected: " 
     418                                   "lsr=%p, now=%p, dlsr=%p (%d:%03dms), " 
     419                                   "diff=%d", 
     420                                   lsr, now, dlsr, dlsr/65536, 
     421                                   (dlsr%65536)*1000/65536, 
     422                                   dlsr-(now-lsr))); 
    261423        } 
    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  
    286         /* Can only calculate if LSR and DLSR is present in RR */ 
    287         if (rtcp->rr.lsr && rtcp->rr.dlsr) { 
    288             pj_uint32_t lsr, now, dlsr; 
    289             pj_uint64_t eedelay; 
    290             pjmedia_rtcp_ntp_rec ntp; 
    291  
    292             /* LSR is the middle 32bit of NTP. It has 1/65536 second  
    293              * resolution  
    294              */ 
    295             lsr = pj_ntohl(rtcp->rr.lsr); 
    296  
    297             /* DLSR is delay since LSR, also in 1/65536 resolution */ 
    298             dlsr = pj_ntohl(rtcp->rr.dlsr); 
    299  
    300             /* Get current time, and convert to 1/65536 resolution */ 
    301             rtcp_get_ntp_time(sess, &ntp); 
    302             now = ((ntp.hi & 0xFFFF) << 16) +  
    303                   (ntp.lo >> 16); 
    304  
    305             /* End-to-end delay is (now-lsr-dlsr) */ 
    306             eedelay = now - lsr - dlsr; 
    307  
    308             /* Convert end to end delay to usec (keeping the calculation in 
    309              * 64bit space):: 
    310              *   sess->ee_delay = (eedelay * 1000) / 65536; 
    311              */ 
    312             eedelay = (eedelay * 1000000) >> 16; 
    313  
    314             TRACE_((THIS_FILE, "Rx RTCP RR: lsr=%p, dlsr=%p (%d:%03dms), " 
    315                                "now=%p, rtt=%p", 
    316                     lsr, dlsr, dlsr/65536, (dlsr%65536)*1000/65536, 
    317                     now, (pj_uint32_t)eedelay)); 
    318              
    319             /* Only save calculation if "now" is greater than lsr, or 
    320              * otherwise rtt will be invalid  
    321              */ 
    322             if (now-dlsr >= lsr) { 
    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  
    340             } else { 
    341                 PJ_LOG(3, (THIS_FILE, "Internal NTP clock skew detected: " 
    342                                        "lsr=%p, now=%p, dlsr=%p (%d:%03dms), " 
    343                                        "diff=%d", 
    344                                        lsr, now, dlsr, dlsr/65536, 
    345                                        (dlsr%65536)*1000/65536, 
    346                                        dlsr-(now-lsr))); 
    347             } 
    348         } 
    349  
    350         pj_gettimeofday(&sess->stat.tx.update); 
    351         sess->stat.tx.update_cnt++; 
    352     } 
     424    } 
     425 
     426    pj_gettimeofday(&sess->stat.tx.update); 
     427    sess->stat.tx.update_cnt++; 
    353428} 
    354429 
     
    361436    pj_uint32_t jitter_samp, jitter; 
    362437    pjmedia_rtcp_pkt *rtcp_pkt = &sess->rtcp_pkt; 
     438    pj_timestamp ts_now; 
    363439    pjmedia_rtcp_ntp_rec ntp; 
    364440     
     
    417493     
    418494    /* Get current NTP time. */ 
    419     rtcp_get_ntp_time(sess, &ntp); 
     495    pj_get_timestamp(&ts_now); 
     496    pjmedia_rtcp_get_ntp_time(sess, &ntp); 
    420497     
    421498    /* Fill in NTP timestamp in SR. */ 
    422499    rtcp_pkt->sr.ntp_sec = pj_htonl(ntp.hi); 
    423500    rtcp_pkt->sr.ntp_frac = pj_htonl(ntp.lo); 
    424      
     501 
     502    TRACE_((THIS_FILE, "TX RTCP SR: ntp_ts=%p",  
     503                       ((ntp.hi & 0xFFFF) << 16) + ((ntp.lo & 0xFFFF0000)  
     504                            >> 16))); 
     505 
    425506    if (sess->rx_lsr_time.u64 == 0 || sess->rx_lsr == 0) { 
    426507        rtcp_pkt->rr.lsr = 0; 
     
    443524           DLSR is Delay since Last SR, in 1/65536 seconds. 
    444525         */ 
    445         pj_get_timestamp(&ts); 
     526        ts.u64 = ts_now.u64; 
    446527 
    447528        /* Convert interval to 1/65536 seconds value */ 
  • pjproject/trunk/pjmedia/src/pjmedia/stream.c

    r394 r397  
    3131#include <pj/os.h> 
    3232#include <pj/pool.h> 
     33#include <pj/rand.h> 
    3334#include <pj/sock_select.h> 
    3435#include <pj/string.h>      /* memcpy() */ 
Note: See TracChangeset for help on using the changeset viewer.