Ignore:
Timestamp:
Aug 1, 2009 9:20:59 AM (15 years ago)
Author:
bennylp
Message:

Initial commit for ticket #929: Improve packet lost concealment (PLC) when handling burst of lost packets

WSOLA improvements:

  • Introduce fade-out and fade-in effect
  • Limit the number of continuous synthetic samples (only take effect when fading is used)
  • Export many settings as macros:
    • PJMEDIA_WSOLA_DELAY_MSEC (was HANNING_PTIME)
    • PJMEDIA_WSOLA_TEMPLATE_LENGTH_MSEC (was TEMPLATE_PTIME)
    • PJMEDIA_WSOLA_MAX_EXPAND_MSEC

PLC:

  • added compile time macro PJMEDIA_WSOLA_PLC_NO_FADING to disable fading (default enabled)

Stream:

  • fixed bug when stream is not PLC-ing subsequent packet loss (only the first)
  • also add maximum PLC limit just as precaution if PLC doesn't limit number of synthetic frames
  • unrelated: fixed warning about unused send_keep_alive() function

Delaybuf:

  • modified to NOT use fading in WSOLA since we don't expect it to generate many continuous synthetic frames
File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjmedia/src/pjmedia/wsola.c

    r2660 r2850  
    7171 
    7272/* Template size, in msec */ 
    73 #define TEMPLATE_PTIME  5 
     73#define TEMPLATE_PTIME  PJMEDIA_WSOLA_TEMPLATE_LENGTH_MSEC 
    7474 
    7575/* Hanning window size, in msec */ 
    76 #define HANNING_PTIME   5 
     76#define HANNING_PTIME   PJMEDIA_WSOLA_DELAY_MSEC 
    7777 
    7878/* Number of frames in erase buffer */ 
     
    8484/* Maximum distance from template for find_pitch() of expansion, in frames */ 
    8585#define EXP_MAX_DIST    HIST_CNT 
     86 
     87/* Duration of a continuous synthetic frames after which the volume  
     88 * of the synthetic frame will be set to zero with fading-out effect. 
     89 */ 
     90#define MAX_EXPAND_MSEC PJMEDIA_WSOLA_MAX_EXPAND_MSEC 
    8691 
    8792 
     
    132137 
    133138    pj_uint16_t          min_extra;         /* Minimum extra (const)        */ 
    134     pj_uint16_t          expand_cnt;        /* Consecutive expansion count  */ 
     139    unsigned             max_expand_cnt;    /* Max # of synthetic samples   */ 
     140    unsigned             fade_out_pos;      /* Last fade-out position       */ 
    135141    pj_uint16_t          expand_sr_min_dist;/* Minimum distance from template  
    136142                                               for find_pitch() on expansion 
     
    147153 
    148154    pj_timestamp         ts;                /* Running timestamp.           */ 
     155 
    149156}; 
    150157 
     
    433440#endif  /* PJ_HAS_FLOATING_POINT */ 
    434441 
     442/* Apply fade-in to the buffer. 
     443 *  - fade_cnt is the number of samples on which the volume 
     444 *       will go from zero to 100% 
     445 *  - fade_pos is current sample position within fade_cnt range. 
     446 *       It is zero for the first sample, so the first sample will 
     447 *       have zero volume. This value is increasing. 
     448 */ 
     449static void fade_in(pj_int16_t buf[], int count, 
     450                    int fade_in_pos, int fade_cnt) 
     451{ 
     452#if defined(PJ_HAS_FLOATING_POINT) && PJ_HAS_FLOATING_POINT!=0 
     453    float fade_pos = (float)fade_in_pos; 
     454#else 
     455    int fade_pos = fade_in_pos; 
     456#endif 
     457 
     458    if (fade_cnt - fade_pos < count) { 
     459        for (; fade_pos < fade_cnt; ++fade_pos, ++buf) { 
     460            *buf = (pj_int16_t)(*buf * fade_pos / fade_cnt); 
     461        } 
     462        /* Leave the remaining samples as is */ 
     463    } else { 
     464        pj_int16_t *end = buf + count; 
     465        for (; buf != end; ++fade_pos, ++buf) { 
     466            *buf = (pj_int16_t)(*buf * fade_pos / fade_cnt); 
     467        } 
     468    } 
     469} 
     470 
     471/* Apply fade-out to the buffer. */ 
     472static void wsola_fade_out(pjmedia_wsola *wsola,  
     473                           pj_int16_t buf[], int count) 
     474{ 
     475    pj_int16_t *end = buf + count; 
     476    int fade_cnt = wsola->max_expand_cnt; 
     477#if defined(PJ_HAS_FLOATING_POINT) && PJ_HAS_FLOATING_POINT!=0 
     478    float fade_pos = (float)wsola->fade_out_pos; 
     479#else 
     480    int fade_pos = wsola->fade_out_pos; 
     481#endif 
     482 
     483    if (wsola->fade_out_pos == 0) { 
     484        pjmedia_zero_samples(buf, count); 
     485    } else if (fade_pos < count) { 
     486        for (; fade_pos; --fade_pos, ++buf) { 
     487            *buf = (pj_int16_t)(*buf * fade_pos / fade_cnt); 
     488        } 
     489        if (buf != end) 
     490            pjmedia_zero_samples(buf, end - buf); 
     491        wsola->fade_out_pos = 0; 
     492    } else { 
     493        for (; buf != end; --fade_pos, ++buf) { 
     494            *buf = (pj_int16_t)(*buf * fade_pos / fade_cnt); 
     495        } 
     496        wsola->fade_out_pos -= count; 
     497    } 
     498} 
     499 
    435500 
    436501PJ_DEF(pj_status_t) pjmedia_wsola_create( pj_pool_t *pool,  
     
    456521    wsola->channel_count = (pj_uint16_t) channel_count; 
    457522    wsola->options = (pj_uint16_t) options; 
     523    wsola->max_expand_cnt = clock_rate * MAX_EXPAND_MSEC / 1000; 
     524    wsola->fade_out_pos = wsola->max_expand_cnt; 
    458525 
    459526    /* Create circular buffer */ 
     
    524591} 
    525592 
     593PJ_DEF(pj_status_t) pjmedia_wsola_set_max_expand(pjmedia_wsola *wsola, 
     594                                                  unsigned msec) 
     595{ 
     596    PJ_ASSERT_RETURN(wsola, PJ_EINVAL); 
     597    wsola->max_expand_cnt = msec * wsola->clock_rate / 1000; 
     598    return PJ_SUCCESS; 
     599} 
    526600 
    527601PJ_DEF(pj_status_t) pjmedia_wsola_reset( pjmedia_wsola *wsola, 
     
    534608    pjmedia_circ_buf_set_len(wsola->buf, wsola->hist_size + wsola->min_extra); 
    535609    pjmedia_zero_samples(wsola->buf->start, wsola->buf->len);  
     610    wsola->fade_out_pos = wsola->max_expand_cnt; 
    536611 
    537612    return PJ_SUCCESS; 
     
    683758 
    684759    /* Update vars */ 
    685     wsola->expand_cnt = 0; 
    686760    wsola->ts.u64 += wsola->samples_per_frame; 
    687761 
     
    692766        pj_int16_t *ola_left; 
    693767 
     768        /* Trim excessive len */ 
     769        if ((int)buf_len > wsola->hist_size + (wsola->min_extra<<1)) { 
     770            buf_len = wsola->hist_size + (wsola->min_extra<<1); 
     771            pjmedia_circ_buf_set_len(wsola->buf, buf_len); 
     772        } 
     773 
    694774        pjmedia_circ_buf_get_read_regions(wsola->buf, &reg1, &reg1_len,  
    695775                                          &reg2, &reg2_len); 
     
    698778               (unsigned)(wsola->hist_size + (wsola->min_extra<<1))); 
    699779 
     780        /* Continue applying fade out to the extra samples */ 
     781        if ((wsola->options & PJMEDIA_WSOLA_NO_FADING)==0) { 
     782            if (reg2_len == 0) { 
     783                wsola_fade_out(wsola, reg1 + reg1_len - (wsola->min_extra<<1), 
     784                               (wsola->min_extra<<1)); 
     785            } else if ((int)reg2_len >= (wsola->min_extra<<1)) { 
     786                wsola_fade_out(wsola, reg2 + reg2_len - (wsola->min_extra<<1), 
     787                               (wsola->min_extra<<1)); 
     788            } else { 
     789                unsigned tmp = (wsola->min_extra<<1) - reg2_len; 
     790                wsola_fade_out(wsola, reg1 + reg1_len - tmp, tmp); 
     791                wsola_fade_out(wsola, reg2, reg2_len); 
     792            } 
     793        } 
     794 
     795        /* Get the region in buffer to be merged with the frame */ 
    700796        if (reg2_len == 0) { 
    701797            ola_left = reg1 + reg1_len - wsola->min_extra; 
     
    711807        } 
    712808 
     809        /* Apply fade-in to the frame before merging */ 
     810        if ((wsola->options & PJMEDIA_WSOLA_NO_FADING)==0) { 
     811            unsigned count = wsola->min_extra; 
     812            int fade_in_pos; 
     813 
     814            /* Scale fade_in position based on last fade-out */ 
     815            fade_in_pos = wsola->fade_out_pos * count / 
     816                          wsola->max_expand_cnt; 
     817 
     818            /* Fade-in it */ 
     819            fade_in(frm, wsola->samples_per_frame, 
     820                    fade_in_pos, count); 
     821        } 
     822 
     823        /* Merge it */ 
    713824        overlapp_add_simple(frm, wsola->min_extra, ola_left, frm); 
    714825 
     826        /* Trim len */ 
    715827        buf_len -= wsola->min_extra; 
    716828        pjmedia_circ_buf_set_len(wsola->buf, buf_len); 
    717     } 
     829 
     830    } else if ((wsola->options & PJMEDIA_WSOLA_NO_FADING)==0 && 
     831               wsola->fade_out_pos != wsola->max_expand_cnt)  
     832    { 
     833        unsigned count = wsola->min_extra; 
     834        int fade_in_pos; 
     835 
     836        /* Fade out the remaining synthetic samples */ 
     837        if (buf_len > wsola->hist_size) { 
     838            pj_int16_t *reg1, *reg2; 
     839            unsigned reg1_len, reg2_len; 
     840 
     841            /* Number of samples to fade out */ 
     842            count = buf_len - wsola->hist_size; 
     843 
     844            pjmedia_circ_buf_get_read_regions(wsola->buf, &reg1, &reg1_len,  
     845                                              &reg2, &reg2_len); 
     846 
     847            CHECK_(pjmedia_circ_buf_get_len(wsola->buf) >=  
     848                   (unsigned)(wsola->hist_size + (wsola->min_extra<<1))); 
     849 
     850            /* Continue applying fade out to the extra samples */ 
     851            if (reg2_len == 0) { 
     852                wsola_fade_out(wsola, reg1 + reg1_len - count, count); 
     853            } else if ((int)reg2_len >= count) { 
     854                wsola_fade_out(wsola, reg2 + reg2_len - count, count); 
     855            } else { 
     856                unsigned tmp = count - reg2_len; 
     857                wsola_fade_out(wsola, reg1 + reg1_len - tmp, tmp); 
     858                wsola_fade_out(wsola, reg2, reg2_len); 
     859            } 
     860        } 
     861 
     862        /* Apply fade-in to the frame */ 
     863        count = wsola->min_extra; 
     864 
     865        /* Scale fade_in position based on last fade-out */ 
     866        fade_in_pos = wsola->fade_out_pos * count / 
     867                      wsola->max_expand_cnt; 
     868 
     869        /* Fade it in */ 
     870        fade_in(frm, wsola->samples_per_frame, 
     871                fade_in_pos, count); 
     872 
     873    } 
     874 
     875    wsola->fade_out_pos = wsola->max_expand_cnt; 
    718876 
    719877    status = pjmedia_circ_buf_write(wsola->buf, frm, wsola->samples_per_frame); 
     
    738896{ 
    739897    unsigned samples_len, samples_req; 
    740  
    741  
    742898    pj_status_t status = PJ_SUCCESS; 
    743899 
     
    758914        TRACE_((THIS_FILE, "Buf size after expanded = %d",  
    759915                pjmedia_circ_buf_get_len(wsola->buf))); 
    760         wsola->expand_cnt++; 
    761916    } 
    762917 
     
    769924 
    770925    pjmedia_circ_buf_adv_read_ptr(wsola->buf, wsola->samples_per_frame); 
     926 
     927    /* Apply fade-out to the frame */ 
     928    if ((wsola->options & PJMEDIA_WSOLA_NO_FADING)==0) { 
     929        wsola_fade_out(wsola, frm, wsola->samples_per_frame); 
     930    } 
    771931 
    772932    return PJ_SUCCESS; 
Note: See TracChangeset for help on using the changeset viewer.