Ignore:
Timestamp:
Oct 24, 2011 9:28:13 AM (13 years ago)
Author:
ming
Message:

Re #1395: Backport of PJSIP 1.x branch into PJSIP 2.0 trunk

TODO: ticket #1268 (Option for automatic/manual sending of RTCP SDES/BYE for the stream) for video stream.

Location:
pjproject/trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk

  • pjproject/trunk/pjmedia/src/pjmedia/jbuf.c

    r3835 r3841  
    3333 
    3434 
    35 /* Minimal difference between JB size and 2*burst-level to perform  
    36  * JB shrinking.  
    37  */ 
    38 #define SAFE_SHRINKING_DIFF     1 
    39  
    40 /* Minimal gap (in ms) between JB shrinking */ 
    41 #define MIN_SHRINK_GAP_MSEC     200 
    42  
    4335/* Invalid sequence number, used as the initial value. */ 
    4436#define INVALID_OFFSET          -9999 
     
    5345 */ 
    5446#define INIT_CYCLE              10 
     47 
     48 
     49/* Minimal difference between JB size and 2*burst-level to perform  
     50 * JB shrinking in static discard algorithm.  
     51 */ 
     52#define STA_DISC_SAFE_SHRINKING_DIFF    1 
    5553 
    5654 
     
    8381 
    8482 
     83typedef void (*discard_algo)(pjmedia_jbuf *jb); 
     84static void jbuf_discard_static(pjmedia_jbuf *jb); 
     85static void jbuf_discard_progressive(pjmedia_jbuf *jb); 
     86 
     87 
    8588struct pjmedia_jbuf 
    8689{ 
     
    99102                                             calculation                    */ 
    100103    int             jb_min_shrink_gap;  /**< How often can we shrink        */ 
     104    discard_algo    jb_discard_algo;    /**< Discard algorithm              */ 
    101105 
    102106    /* Buffer */ 
     
    121125                                             continuously updated based on 
    122126                                             current frame burst level.     */ 
     127    pj_bool_t       jb_prefetching;     /**< flag if jbuf is prefetching.   */ 
    123128    int             jb_status;          /**< status is 'init' until the first  
    124129                                             'put' operation                */ 
    125130    int             jb_init_cycle_cnt;  /**< status is 'init' until the first  
    126131                                             'put' operation                */ 
    127     int             jb_last_del_seq;    /**< Seq # of last frame deleted    */ 
    128  
    129     int             jb_last_discard_seq;/**< Seq # of last frame discarded  */ 
     132 
     133    int             jb_discard_ref;     /**< Seq # of last frame deleted or 
     134                                             discarded                      */ 
     135    unsigned        jb_discard_dist;    /**< Distance from jb_discard_ref 
     136                                             to perform discard (in frm)    */ 
    130137 
    131138    /* Statistics */ 
     
    142149#define JB_STATUS_INITIALIZING  0 
    143150#define JB_STATUS_PROCESSING    1 
    144 #define JB_STATUS_PREFETCHING   2 
    145151 
    146152 
     
    452458    enum { MAX_DROPOUT = 3000 }; 
    453459 
    454     assert(frame_size <= framelist->frame_size); 
     460    PJ_ASSERT_RETURN(frame_size <= framelist->frame_size, PJ_EINVAL); 
    455461 
    456462    /* too late or sequence restart */ 
     
    508514        pj_memcpy(framelist->content + pos * framelist->frame_size, 
    509515                  frame, frame_size); 
    510         return PJ_SUCCESS; 
    511     } else { 
    512         /* frame is being discarded */ 
    513         framelist->discarded_num++; 
    514         return PJ_EIGNORED; 
    515     } 
    516 } 
    517  
     516    } 
     517 
     518    return PJ_SUCCESS; 
     519} 
     520 
     521 
     522static pj_status_t jb_framelist_discard(jb_framelist_t *framelist, 
     523                                        int index) 
     524{ 
     525    unsigned pos; 
     526 
     527    PJ_ASSERT_RETURN(index >= framelist->origin && 
     528                     index <  framelist->origin + (int)framelist->size, 
     529                     PJ_EINVAL); 
     530 
     531    /* Get the slot position */ 
     532    pos = (framelist->head + (index - framelist->origin)) % 
     533          framelist->max_count; 
     534 
     535    /* Discard the frame */ 
     536    framelist->frame_type[pos] = PJMEDIA_JB_DISCARDED_FRAME; 
     537    framelist->discarded_num++; 
     538 
     539    return PJ_SUCCESS; 
     540} 
    518541 
    519542 
     
    549572    jb->jb_max_prefetch  = max_count*4/5; 
    550573    jb->jb_max_count     = max_count; 
    551     jb->jb_min_shrink_gap= MIN_SHRINK_GAP_MSEC / ptime; 
     574    jb->jb_min_shrink_gap= PJMEDIA_JBUF_DISC_MIN_GAP / ptime; 
    552575    jb->jb_max_burst     = PJ_MAX(MAX_BURST_MSEC / ptime, max_count*3/4); 
    553     jb->jb_last_discard_seq = 0; 
    554576 
    555577    pj_math_stat_init(&jb->jb_delay); 
    556578    pj_math_stat_init(&jb->jb_burst); 
    557579 
     580    pjmedia_jbuf_set_discard(jb, PJMEDIA_JB_DISCARD_PROGRESSIVE); 
    558581    pjmedia_jbuf_reset(jb); 
    559582 
     
    590613{ 
    591614    PJ_ASSERT_RETURN(jb, PJ_EINVAL); 
    592     PJ_ASSERT_RETURN(min_prefetch < max_prefetch && 
     615    PJ_ASSERT_RETURN(min_prefetch <= max_prefetch && 
    593616                     prefetch <= max_prefetch && 
    594617                     max_prefetch <= jb->jb_max_count, 
     
    598621    jb->jb_min_prefetch = min_prefetch; 
    599622    jb->jb_max_prefetch = max_prefetch; 
     623 
     624    return PJ_SUCCESS; 
     625} 
     626 
     627 
     628PJ_DEF(pj_status_t) pjmedia_jbuf_set_discard( pjmedia_jbuf *jb, 
     629                                              pjmedia_jb_discard_algo algo) 
     630{ 
     631    PJ_ASSERT_RETURN(jb, PJ_EINVAL); 
     632    PJ_ASSERT_RETURN(algo >= PJMEDIA_JB_DISCARD_NONE && 
     633                     algo <= PJMEDIA_JB_DISCARD_PROGRESSIVE, 
     634                     PJ_EINVAL); 
     635 
     636    switch(algo) { 
     637    case PJMEDIA_JB_DISCARD_PROGRESSIVE: 
     638        jb->jb_discard_algo = &jbuf_discard_progressive; 
     639        break; 
     640    case PJMEDIA_JB_DISCARD_STATIC: 
     641        jb->jb_discard_algo = &jbuf_discard_static; 
     642        break; 
     643    default: 
     644        jb->jb_discard_algo = NULL; 
     645        break; 
     646    } 
    600647 
    601648    return PJ_SUCCESS; 
     
    611658    jb->jb_init_cycle_cnt= 0; 
    612659    jb->jb_max_hist_level= 0; 
     660    jb->jb_prefetching   = (jb->jb_prefetch != 0); 
     661    jb->jb_discard_dist  = 0; 
    613662 
    614663    jb_framelist_reset(&jb->jb_framelist); 
     
    622671    PJ_LOG(5, (jb->jb_name.ptr, "" 
    623672               "JB summary:\n" 
    624                "  size=%d prefetch=%d level=%d\n" 
     673               "  size=%d/eff=%d prefetch=%d level=%d\n" 
    625674               "  delay (min/max/avg/dev)=%d/%d/%d/%d ms\n" 
    626675               "  burst (min/max/avg/dev)=%d/%d/%d/%d frames\n" 
    627676               "  lost=%d discard=%d empty=%d", 
    628                jb->jb_framelist.size, jb->jb_prefetch, jb->jb_eff_level, 
     677               jb_framelist_size(&jb->jb_framelist),  
     678               jb_framelist_eff_size(&jb->jb_framelist),  
     679               jb->jb_prefetch, jb->jb_eff_level, 
    629680               jb->jb_delay.min, jb->jb_delay.max, jb->jb_delay.mean,  
    630681               pj_math_stat_get_stddev(&jb->jb_delay), 
     
    712763    } 
    713764} 
     765 
     766 
     767static void jbuf_discard_static(pjmedia_jbuf *jb) 
     768{ 
     769    /* These code is used for shortening the delay in the jitter buffer. 
     770     * It needs shrink only when there is possibility of drift. Drift 
     771     * detection is performed by inspecting the jitter buffer size, if 
     772     * its size is twice of current burst level, there can be drift. 
     773     * 
     774     * Moreover, normally drift level is quite low, so JB shouldn't need 
     775     * to shrink aggresively, it will shrink maximum one frame per  
     776     * PJMEDIA_JBUF_DISC_MIN_GAP ms. Theoritically, JB may handle drift level  
     777     * as much as = FRAME_PTIME/PJMEDIA_JBUF_DISC_MIN_GAP * 100% 
     778     * 
     779     * Whenever there is drift, where PUT > GET, this method will keep  
     780     * the latency (JB size) as much as twice of burst level. 
     781     */ 
     782 
     783    /* Shrinking due of drift will be implicitly done by progressive discard, 
     784     * so just disable it when progressive discard is active. 
     785     */ 
     786    int diff, burst_level; 
     787 
     788    burst_level = PJ_MAX(jb->jb_eff_level, jb->jb_level); 
     789    diff = jb_framelist_eff_size(&jb->jb_framelist) - burst_level*2; 
     790 
     791    if (diff >= STA_DISC_SAFE_SHRINKING_DIFF) { 
     792        int seq_origin; 
     793 
     794        /* Check and adjust jb_discard_ref, in case there was  
     795         * seq restart  
     796         */ 
     797        seq_origin = jb_framelist_origin(&jb->jb_framelist); 
     798        if (seq_origin < jb->jb_discard_ref) 
     799            jb->jb_discard_ref = seq_origin; 
     800 
     801        if (seq_origin - jb->jb_discard_ref >= jb->jb_min_shrink_gap) 
     802        { 
     803            /* Shrink slowly, one frame per cycle */ 
     804            diff = 1; 
     805 
     806            /* Drop frame(s)! */ 
     807            diff = jb_framelist_remove_head(&jb->jb_framelist, diff); 
     808            jb->jb_discard_ref = jb_framelist_origin(&jb->jb_framelist); 
     809            jb->jb_discard += diff; 
     810 
     811            TRACE__((jb->jb_name.ptr,  
     812                     "JB shrinking %d frame(s), cur size=%d", diff, 
     813                     jb_framelist_eff_size(&jb->jb_framelist))); 
     814        } 
     815    } 
     816} 
     817 
     818 
     819static void jbuf_discard_progressive(pjmedia_jbuf *jb) 
     820{ 
     821    unsigned cur_size, burst_level, overflow, T, discard_dist; 
     822    int last_seq; 
     823 
     824    /* Should be done in PUT operation */ 
     825    if (jb->jb_last_op != JB_OP_PUT) 
     826        return; 
     827 
     828    /* Check if latency is longer than burst */ 
     829    cur_size = jb_framelist_eff_size(&jb->jb_framelist); 
     830    burst_level = PJ_MAX(jb->jb_eff_level, jb->jb_level); 
     831    if (cur_size <= burst_level) { 
     832        /* Reset any scheduled discard */ 
     833        jb->jb_discard_dist = 0; 
     834        return; 
     835    } 
     836 
     837    /* Estimate discard duration needed for adjusting latency */ 
     838    if (burst_level <= PJMEDIA_JBUF_PRO_DISC_MIN_BURST) 
     839        T = PJMEDIA_JBUF_PRO_DISC_T1; 
     840    else if (burst_level >= PJMEDIA_JBUF_PRO_DISC_MAX_BURST) 
     841        T = PJMEDIA_JBUF_PRO_DISC_T2; 
     842    else 
     843        T = PJMEDIA_JBUF_PRO_DISC_T1 +  
     844            (PJMEDIA_JBUF_PRO_DISC_T2 - PJMEDIA_JBUF_PRO_DISC_T1) * 
     845            (burst_level - PJMEDIA_JBUF_PRO_DISC_MIN_BURST) / 
     846            (PJMEDIA_JBUF_PRO_DISC_MAX_BURST-PJMEDIA_JBUF_PRO_DISC_MIN_BURST); 
     847 
     848    /* Calculate current discard distance */ 
     849    overflow = cur_size - burst_level; 
     850    discard_dist = T / overflow / jb->jb_frame_ptime; 
     851 
     852    /* Get last seq number in the JB */ 
     853    last_seq = jb_framelist_origin(&jb->jb_framelist) + 
     854               jb_framelist_size(&jb->jb_framelist) - 1; 
     855 
     856    /* Setup new discard schedule if none, otherwise, update the existing 
     857     * discard schedule (can be delayed or accelerated). 
     858     */ 
     859    if (jb->jb_discard_dist == 0) { 
     860        /* Setup new discard schedule */ 
     861        jb->jb_discard_ref = last_seq; 
     862    } else if (last_seq < jb->jb_discard_ref) { 
     863        /* Seq restarted, update discard reference */ 
     864        jb->jb_discard_ref = last_seq; 
     865    } 
     866    jb->jb_discard_dist = PJ_MAX(jb->jb_min_shrink_gap, (int)discard_dist); 
     867 
     868    /* Check if we need to discard now */ 
     869    if (last_seq >= (jb->jb_discard_ref + (int)jb->jb_discard_dist)) { 
     870        int discard_seq; 
     871         
     872        discard_seq = jb->jb_discard_ref + jb->jb_discard_dist; 
     873        if (discard_seq < jb_framelist_origin(&jb->jb_framelist)) 
     874            discard_seq = jb_framelist_origin(&jb->jb_framelist); 
     875 
     876        jb_framelist_discard(&jb->jb_framelist, discard_seq); 
     877 
     878        TRACE__((jb->jb_name.ptr,  
     879                "Discard #%d: ref=#%d dist=%d orig=%d size=%d/%d " 
     880                "burst=%d/%d", 
     881                discard_seq, 
     882                jb->jb_discard_ref, 
     883                jb->jb_discard_dist, 
     884                jb_framelist_origin(&jb->jb_framelist), 
     885                cur_size, 
     886                jb_framelist_size(&jb->jb_framelist), 
     887                jb->jb_eff_level, 
     888                burst_level)); 
     889 
     890        /* Update discard reference */ 
     891        jb->jb_discard_ref = discard_seq; 
     892    } 
     893} 
     894     
    714895 
    715896PJ_INLINE(void) jbuf_update(pjmedia_jbuf *jb, int oper) 
     
    748929    } 
    749930 
    750     /* These code is used for shortening the delay in the jitter buffer. 
    751      * It needs shrink only when there is possibility of drift. Drift 
    752      * detection is performed by inspecting the jitter buffer size, if 
    753      * its size is twice of current burst level, there can be drift. 
    754      * 
    755      * Moreover, normally drift level is quite low, so JB shouldn't need 
    756      * to shrink aggresively, it will shrink maximum one frame per  
    757      * MIN_SHRINK_GAP_MSEC ms. Theoritically, JB may handle drift level  
    758      * as much as = FRAME_PTIME/MIN_SHRINK_GAP_MSEC * 100% 
    759      * 
    760      * Whenever there is drift, where PUT > GET, this method will keep  
    761      * the latency (JB size) as much as twice of burst level. 
    762      */ 
    763  
    764     /* Shrinking due of drift will be implicitly done by progressive discard, 
    765      * so just disable it when progressive discard is active. 
    766      */ 
    767 #if !PROGRESSIVE_DISCARD 
    768  
    769     if (jb->jb_status != JB_STATUS_PROCESSING) 
    770         return; 
    771  
    772     { 
    773         int diff, burst_level; 
    774  
    775         burst_level = PJ_MAX(jb->jb_eff_level, jb->jb_level); 
    776         diff = jb_framelist_eff_size(&jb->jb_framelist) - burst_level*2; 
    777  
    778         if (diff >= SAFE_SHRINKING_DIFF) { 
    779             int seq_origin; 
    780  
    781             /* Check and adjust jb_last_del_seq, in case there was  
    782              * seq restart  
    783              */ 
    784             seq_origin = jb_framelist_origin(&jb->jb_framelist); 
    785             if (seq_origin < jb->jb_last_del_seq) 
    786                 jb->jb_last_del_seq = seq_origin; 
    787  
    788             if (seq_origin - jb->jb_last_del_seq >= jb->jb_min_shrink_gap) 
    789             { 
    790                 /* Shrink slowly, one frame per cycle */ 
    791                 diff = 1; 
    792  
    793                 /* Drop frame(s)! */ 
    794                 diff = jb_framelist_remove_head(&jb->jb_framelist, diff); 
    795                 jb->jb_last_del_seq = jb_framelist_origin(&jb->jb_framelist); 
    796                 jb->jb_discard += diff; 
    797  
    798                 TRACE__((jb->jb_name.ptr,  
    799                          "JB shrinking %d frame(s), cur size=%d", diff, 
    800                          jb_framelist_eff_size(&jb->jb_framelist))); 
    801             } 
    802         } 
    803     } 
    804  
    805 #endif /* !PROGRESSIVE_DISCARD */ 
    806  
     931    /* Call discard algorithm */ 
     932    if (jb->jb_status == JB_STATUS_PROCESSING && jb->jb_discard_algo) { 
     933        (*jb->jb_discard_algo)(jb); 
     934    } 
    807935} 
    808936 
     
    835963{ 
    836964    pj_size_t min_frame_size; 
    837     int new_size, cur_size, frame_type = PJMEDIA_JB_NORMAL_FRAME; 
     965    int new_size, cur_size; 
    838966    pj_status_t status; 
    839967 
    840968    cur_size = jb_framelist_eff_size(&jb->jb_framelist); 
    841  
    842 #if PROGRESSIVE_DISCARD 
    843     { 
    844         unsigned interval, seq_delta; 
    845         unsigned burst_level, burst_factor; 
    846  
    847         /* Calculating discard interval (aggressiveness) based on 
    848          * (current size / burst level). 
    849          */ 
    850         if (jb->jb_status == JB_STATUS_PROCESSING) { 
    851             burst_level = PJ_MAX(jb->jb_eff_level, jb->jb_level); 
    852             burst_factor = cur_size / burst_level; 
    853             /* Tolerate small spikes */ 
    854             if ((burst_level <= 5) && (burst_factor < 3)) 
    855                 burst_factor = 0; 
    856         } else { 
    857             burst_factor = 0; 
    858         } 
    859  
    860         switch (burst_factor) { 
    861         case 0: 
    862             interval = 0; 
    863             break; 
    864         case 1: 
    865             interval = 7; 
    866             break; 
    867         case 2: 
    868             interval = 5; 
    869             break; 
    870         default: 
    871             interval = 4; 
    872             break; 
    873         } 
    874  
    875         /* Do the math now to see if we should discard this packet. 
    876          * Calculate the distance from the last sequence 
    877          * discarded. If negative, then this is an out of 
    878          * order frame so just proceed with discard. Else 
    879          * see if the delta is at least the intervals worth away 
    880          * from the last frame discarded. 
    881          */ 
    882         seq_delta = (pj_uint16_t)(frame_seq - jb->jb_last_discard_seq); 
    883         if ((0 != interval) && (seq_delta >= interval)) { 
    884             frame_type = PJMEDIA_JB_DISCARDED_FRAME; 
    885             jb->jb_last_discard_seq = frame_seq; 
    886  
    887             TRACE__((jb->jb_name.ptr,  
    888                     "Discarding frame #%d: eff=%d disc=%d orig:%d" 
    889                     " seq_delta:%d", 
    890                     frame_seq, 
    891                     cur_size, 
    892                     jb_framelist_size(&jb->jb_framelist) - cur_size, 
    893                     jb_framelist_origin(&jb->jb_framelist), 
    894                     (int)seq_delta)); 
    895         } 
    896     } 
    897 #endif /* PROGRESSIVE_DISCARD */ 
    898      
    899969 
    900970    /* Attempt to store the frame */ 
    901971    min_frame_size = PJ_MIN(frame_size, jb->jb_frame_size); 
    902972    status = jb_framelist_put_at(&jb->jb_framelist, frame_seq, frame, 
    903                                  min_frame_size, bit_info, ts, frame_type); 
     973                                 min_frame_size, bit_info, ts, 
     974                                 PJMEDIA_JB_NORMAL_FRAME); 
    904975     
    905976    /* Jitter buffer is full, remove some older frames */ 
     
    908979        unsigned removed; 
    909980 
    910         /* When progressive discard activated, just remove as few as possible 
    911          * just to make this frame in. 
    912          */ 
    913 #if PROGRESSIVE_DISCARD 
    914         /* The cases of seq-jump, out-of-order, and seq restart should have 
     981        /* Remove as few as possible just to make this frame in. Note that 
     982         * the cases of seq-jump, out-of-order, and seq restart should have 
    915983         * been handled/normalized by previous call of jb_framelist_put_at(). 
    916984         * So we're confident about 'distance' value here. 
     
    919987                   jb->jb_max_count + 1; 
    920988        pj_assert(distance > 0); 
    921 #else 
    922         distance = PJ_MAX(jb->jb_max_count/4, 1); 
    923 #endif 
     989 
    924990        removed = jb_framelist_remove_head(&jb->jb_framelist, distance); 
    925991        status = jb_framelist_put_at(&jb->jb_framelist, frame_seq, frame, 
    926                                      min_frame_size, bit_info, ts, frame_type); 
     992                                     min_frame_size, bit_info, ts, 
     993                                     PJMEDIA_JB_NORMAL_FRAME); 
    927994 
    928995        jb->jb_discard += removed; 
     
    9371004 
    9381005    if (status == PJ_SUCCESS) { 
    939         if (jb->jb_status == JB_STATUS_PREFETCHING) { 
     1006        if (jb->jb_prefetching) { 
    9401007            TRACE__((jb->jb_name.ptr, "PUT prefetch_cnt=%d/%d",  
    9411008                     new_size, jb->jb_prefetch)); 
    9421009            if (new_size >= jb->jb_prefetch) 
    943                 jb->jb_status = JB_STATUS_PROCESSING; 
     1010                jb->jb_prefetching = PJ_FALSE; 
    9441011        } 
    9451012        jb->jb_level += (new_size > cur_size ? new_size-cur_size : 1); 
     
    9841051                                     int *seq) 
    9851052{ 
    986     if (jb->jb_status == JB_STATUS_PREFETCHING) { 
     1053    if (jb->jb_prefetching) { 
    9871054 
    9881055        /* Can't return frame because jitter buffer is filling up 
     
    10311098            /* Jitter buffer is empty */ 
    10321099            if (jb->jb_prefetch) 
    1033                 jb->jb_status = JB_STATUS_PREFETCHING; 
     1100                jb->jb_prefetching = PJ_TRUE; 
    10341101 
    10351102            //pj_bzero(frame, jb->jb_frame_size); 
Note: See TracChangeset for help on using the changeset viewer.