Ignore:
Timestamp:
Feb 29, 2008 5:19:42 PM (12 years ago)
Author:
bennylp
Message:

Ticket #438: Workaround for frame bursts from audio devices: added wsola in delaybuf, and put delaybuf in the bridge

File:
1 edited

Legend:

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

    r1716 r1833  
    2020#include <pjmedia/delaybuf.h> 
    2121#include <pjmedia/errno.h> 
     22#include <pjmedia/wsola.h> 
    2223#include <pj/assert.h> 
     24#include <pj/lock.h> 
    2325#include <pj/log.h> 
    2426#include <pj/pool.h> 
    2527 
     28 
     29#if 0 
     30#   define TRACE__(x) PJ_LOG(3,x) 
     31#else 
     32#   define TRACE__(x) 
     33#endif 
     34 
     35 
     36/* Type of states of delay buffer */ 
    2637enum state 
    2738{ 
     
    3142}; 
    3243 
     44/* Type of operation of delay buffer */ 
    3345enum OP 
    3446{ 
     
    3850}; 
    3951 
    40 /* The following macros represent cycles of test. */ 
    41 /* Since there are two operations performed (get & put), */ 
    42 /* these macros value must be minimum 2 and should be even number */ 
     52/* The following macros represent cycles of test. Since there are two 
     53 * operations performed (get & put), these macros minimum value must be 2  
     54 * and should be even number. 
     55 */ 
    4356#define WAITING_COUNT   4 
    4457#define LEARN_COUNT     16 
    4558 
    46 /* Number of buffers to add to learnt level for additional stability */ 
     59/* Number of buffers to add to learnt level for additional stability 
     60 * Please note that wsola_discard() needs minimum 3 frames, so max buffer  
     61 * count should be minimally 3, setting SAFE_MARGIN to 2 will guarantees  
     62 * this. 
     63 */ 
    4764#define SAFE_MARGIN     2 
    4865 
     
    6784struct pjmedia_delay_buf 
    6885{ 
    69     char         obj_name[PJ_MAX_OBJ_NAME]; 
    70  
    71     pj_int16_t  *frame_buf; 
    72     unsigned     put_pos; 
    73     unsigned     get_pos; 
    74     unsigned     buf_cnt; 
    75  
    76     unsigned     samples_per_frame; 
    77     unsigned     max_cnt; 
    78     enum state   state; 
     86    char             obj_name[PJ_MAX_OBJ_NAME]; 
     87 
     88    pj_lock_t       *lock;              /**< Lock object.                    */ 
     89 
     90    pj_int16_t      *frame_buf; 
     91    enum state       state;             /**< State of delay buffer           */ 
     92    unsigned         samples_per_frame; /**< Number of samples in one frame  */ 
     93    unsigned         max_frames;        /**< Buffer allocated, in frames     */ 
     94 
     95    unsigned         put_pos;           /**< Position for put op, in samples */ 
     96    unsigned         get_pos;           /**< Position for get op, in samples */ 
     97    unsigned         buf_cnt;           /**< Number of buffered samples      */ 
     98    unsigned         max_cnt;           /**< Max number of buffered samples  */ 
    7999 
    80100    struct { 
    81         unsigned level; 
     101        unsigned     level;             /**< Burst level storage on learning */ 
    82102    } op[2]; 
    83  
    84     enum OP      last_op; 
    85     unsigned     max_level; 
    86     unsigned     state_count; 
     103    enum OP          last_op;           /**< Last op (GET or PUT) of learning*/ 
     104    unsigned         state_count;       /**< Counter of op cycles of learning*/ 
     105 
     106    unsigned         max_level;         /**< Learning result: burst level    */ 
     107 
     108    pjmedia_wsola   *wsola;             /**< Drift handler                   */ 
    87109}; 
    88110 
    89111PJ_DEF(pj_status_t) pjmedia_delay_buf_create( pj_pool_t *pool, 
    90112                                              const char *name, 
     113                                              unsigned clock_rate, 
    91114                                              unsigned samples_per_frame, 
    92                                               unsigned max_cnt, 
     115                                              unsigned max_frames, 
    93116                                              int delay, 
     117                                              unsigned options, 
    94118                                              pjmedia_delay_buf **p_b) 
    95119{ 
    96120    pjmedia_delay_buf *b; 
    97  
    98     PJ_ASSERT_RETURN(pool && samples_per_frame && max_cnt && p_b, PJ_EINVAL); 
     121    pj_status_t status; 
     122 
     123    PJ_ASSERT_RETURN(pool && samples_per_frame && max_frames && p_b, PJ_EINVAL); 
     124    PJ_ASSERT_RETURN((int)max_frames >= delay, PJ_EINVAL); 
     125    PJ_ASSERT_RETURN(options==0, PJ_EINVAL); 
     126 
     127    PJ_UNUSED_ARG(options); 
    99128 
    100129    if (!name) { 
     
    105134 
    106135    pj_ansi_strncpy(b->obj_name, name, PJ_MAX_OBJ_NAME-1); 
     136    b->samples_per_frame = samples_per_frame; 
     137    b->max_frames = max_frames; 
     138 
     139    status = pj_lock_create_recursive_mutex(pool, b->obj_name,  
     140                                            &b->lock); 
     141    if (status != PJ_SUCCESS) 
     142        return status; 
     143 
    107144    b->frame_buf = (pj_int16_t*) 
    108                    pj_pool_zalloc(pool, samples_per_frame * max_cnt *  
    109                                          sizeof(pj_int16_t)); 
    110     b->samples_per_frame = samples_per_frame; 
    111     b->max_cnt = max_cnt; 
     145                   pj_pool_zalloc(pool, samples_per_frame * max_frames *  
     146                                  sizeof(pj_int16_t)); 
    112147 
    113148    if (delay >= 0) { 
    114         PJ_ASSERT_RETURN(delay <= (int)max_cnt, PJ_EINVAL); 
     149        if (delay == 0) 
     150            delay = 1; 
    115151        b->max_level = delay; 
     152        b->max_cnt = delay * samples_per_frame; 
    116153        b->state = STATE_RUNNING; 
    117154    } else { 
     155        b->max_cnt = max_frames * samples_per_frame; 
    118156        b->last_op = OP_UNDEFINED; 
    119157        b->state = STATE_WAITING; 
    120         b->buf_cnt = 0; 
    121     } 
     158    } 
     159 
     160    status = pjmedia_wsola_create(pool, clock_rate, samples_per_frame,  
     161                                  PJMEDIA_WSOLA_NO_PLC, &b->wsola); 
     162    if (status != PJ_SUCCESS) 
     163        return status; 
    122164 
    123165    *p_b = b; 
    124166 
    125     PJ_LOG(5,(b->obj_name,"Delay buffer created")); 
     167    TRACE__((b->obj_name,"Delay buffer created")); 
    126168 
    127169    return PJ_SUCCESS; 
     170} 
     171 
     172PJ_DEF(pj_status_t) pjmedia_delay_buf_destroy(pjmedia_delay_buf *b) 
     173{ 
     174    pj_status_t status; 
     175 
     176    PJ_ASSERT_RETURN(b, PJ_EINVAL); 
     177 
     178    pj_lock_acquire(b->lock); 
     179 
     180    status = pjmedia_wsola_destroy(b->wsola); 
     181    if (status == PJ_SUCCESS) 
     182        b->wsola = NULL; 
     183 
     184    pj_lock_release(b->lock); 
     185    pj_lock_destroy(b->lock); 
     186    b->lock = NULL; 
     187 
     188    return status; 
     189} 
     190 
     191/* This function will erase samples from delay buffer. 
     192 * The number of erased samples is guaranteed to be >= erase_cnt. 
     193 */ 
     194static void shrink_buffer(pjmedia_delay_buf *b, unsigned erase_cnt) 
     195{ 
     196    unsigned buf1len; 
     197    unsigned buf2len; 
     198    pj_status_t status; 
     199 
     200    pj_assert(b && erase_cnt); 
     201 
     202    if (b->get_pos < b->put_pos) { 
     203        /* sssss .. sssss 
     204         *  ^          ^ 
     205         *  G          P 
     206         */ 
     207        buf1len = b->put_pos - b->get_pos; 
     208        buf2len = 0; 
     209    } else { 
     210        /* sssss .. sssss 
     211         *  ^ ^ 
     212         *  P G 
     213         */ 
     214        buf1len = b->max_cnt - b->get_pos; 
     215        buf2len = b->put_pos; 
     216    } 
     217 
     218    /* Consistency checking */ 
     219    pj_assert((buf1len + buf2len) == b->buf_cnt); 
     220 
     221    if (buf1len != 0) 
     222        status = pjmedia_wsola_discard(b->wsola,  
     223                                       &b->frame_buf[b->get_pos], buf1len, 
     224                                       b->frame_buf, buf2len, 
     225                                       &erase_cnt); 
     226    else 
     227        status = pjmedia_wsola_discard(b->wsola,  
     228                                       b->frame_buf, buf2len, 
     229                                       NULL, 0, 
     230                                       &erase_cnt); 
     231 
     232    if ((status == PJ_SUCCESS) && (erase_cnt > 0)) { 
     233        /* WSOLA discard will shrink only the second buffer, but it may 
     234         * also shrink first buffer if second buffer is 'destroyed', so 
     235         * it is safe to just set the new put_pos. 
     236         */ 
     237        if (b->put_pos >= erase_cnt) 
     238            b->put_pos -= erase_cnt; 
     239        else 
     240            b->put_pos = b->max_cnt - (erase_cnt - b->put_pos); 
     241 
     242        b->buf_cnt -= erase_cnt; 
     243 
     244        PJ_LOG(5,(b->obj_name,"Successfully shrinking %d samples, " 
     245                  "buf_cnt=%d", erase_cnt, b->buf_cnt)); 
     246    } 
     247 
     248    /* Shrinking failed or erased count is less than requested, 
     249     * delaybuf needs to drop eldest samples, this is bad since the voice 
     250     * samples may not have smooth transition. 
     251     */ 
     252    if (b->buf_cnt + b->samples_per_frame > b->max_cnt) { 
     253        erase_cnt = b->buf_cnt + b->samples_per_frame - b->max_cnt; 
     254 
     255        b->buf_cnt -= erase_cnt; 
     256 
     257        /* Shift get_pos forward */ 
     258        b->get_pos = (b->get_pos + erase_cnt) % b->max_cnt; 
     259 
     260        PJ_LOG(4,(b->obj_name,"Shrinking failed or insufficient, dropping" 
     261                  " %d eldest samples, buf_cnt=%d", erase_cnt, b->buf_cnt)); 
     262    } 
     263} 
     264 
     265static void set_max_cnt(pjmedia_delay_buf *b, unsigned new_max_cnt) 
     266{ 
     267    unsigned old_max_cnt = b->max_cnt; 
     268 
     269    /* nothing to adjust */ 
     270    if (old_max_cnt == new_max_cnt) 
     271        return; 
     272 
     273    /* For now, only support shrinking */ 
     274    pj_assert(old_max_cnt > new_max_cnt); 
     275 
     276    shrink_buffer(b, old_max_cnt - new_max_cnt); 
     277 
     278    /* Adjust buffer to accomodate the new max_cnt so the samples is secured. 
     279     * This is done by make get_pos = 0  
     280     */ 
     281    if (b->get_pos <= b->put_pos) { 
     282        /* sssss .. sssss 
     283         *   ^         ^ 
     284         *   G         P 
     285         */ 
     286        /* Consistency checking */ 
     287        pj_assert((b->put_pos - b->get_pos) <= new_max_cnt); 
     288        pj_assert((b->put_pos - b->get_pos) == b->buf_cnt); 
     289 
     290        pjmedia_move_samples(b->frame_buf, &b->frame_buf[b->get_pos],  
     291                             b->get_pos); 
     292        b->put_pos -= b->get_pos; 
     293        b->get_pos = 0; 
     294    } else { 
     295        /* sssss .. sssss 
     296         *          ^  ^ 
     297         *          P  G 
     298         */ 
     299        unsigned d = old_max_cnt - b->get_pos; 
     300 
     301        /* Consistency checking */ 
     302        pj_assert((b->get_pos - b->put_pos) >= (old_max_cnt - new_max_cnt)); 
     303 
     304        /* Make get_pos = 0, shift right the leftmost block first */ 
     305        pjmedia_move_samples(&b->frame_buf[d], b->frame_buf, d); 
     306        pjmedia_copy_samples(b->frame_buf, &b->frame_buf[b->get_pos], d); 
     307        b->put_pos += d; 
     308        b->get_pos = 0; 
     309    } 
     310 
     311    b->max_cnt = new_max_cnt; 
    128312} 
    129313 
     
    158342                b->max_level += SAFE_MARGIN; 
    159343                 
    160                 PJ_LOG(5,(b->obj_name,"Delay buffer start running, level=%u", 
    161                     b->max_level)); 
    162  
    163344                /* buffer not enough! */ 
    164                 if (b->max_level > b->max_cnt) { 
    165                     b->max_level = b->max_cnt; 
    166                     PJ_LOG(2,(b->obj_name,"Delay buffer %s learning result " \ 
    167                         "exceeds the maximum delay allowed", 
    168                         b->max_level)); 
     345                if (b->max_level > b->max_frames) { 
     346                    PJ_LOG(4,(b->obj_name,"Delay buffer learning result (%d)" 
     347                              " exceeds the maximum delay allowed (%d)", 
     348                              b->max_level, 
     349                              b->max_frames)); 
     350 
     351                    b->max_level = b->max_frames; 
    169352                } 
    170353 
     354                /* we need to set new max_cnt & adjust buffer */ 
     355                set_max_cnt(b, b->max_level * b->samples_per_frame); 
     356 
    171357                b->state = STATE_RUNNING; 
     358 
     359                PJ_LOG(4,(b->obj_name,"Delay buffer start running, level=%u", 
     360                          b->max_level)); 
    172361            } 
    173362        } 
     
    182371                                           pj_int16_t frame[]) 
    183372{ 
     373    pj_status_t status; 
     374 
     375    PJ_ASSERT_RETURN(b && frame, PJ_EINVAL); 
     376 
     377    pj_lock_acquire(b->lock); 
     378 
    184379    update(b, OP_PUT); 
    185380     
    186     if (b->state != STATE_RUNNING) 
    187         return PJ_EPENDING; 
    188  
    189     pj_memcpy(&b->frame_buf[b->put_pos * b->samples_per_frame], frame,  
    190         b->samples_per_frame*sizeof(pj_int16_t)); 
    191  
    192     /* overflow case */ 
    193     if (b->put_pos == b->get_pos && b->buf_cnt) { 
    194         if (++b->get_pos == b->max_level) 
    195             b->get_pos = 0; 
    196  
    197         b->put_pos = b->get_pos; 
    198  
    199         PJ_LOG(5,(b->obj_name,"Warning: buffer overflow")); 
    200  
    201         return PJ_ETOOMANY; 
    202     } 
    203  
    204     ++b->buf_cnt; 
    205  
    206     if (++b->put_pos == b->max_level) 
    207         b->put_pos = 0; 
    208  
     381    status = pjmedia_wsola_save(b->wsola, frame, PJ_FALSE); 
     382    if (status != PJ_SUCCESS) { 
     383        pj_lock_release(b->lock); 
     384        return status; 
     385    } 
     386 
     387    /* Overflow checking */ 
     388    if (b->buf_cnt + b->samples_per_frame > b->max_cnt) 
     389    { 
     390        /* shrink one frame or just the diff? */ 
     391        //unsigned erase_cnt = b->samples_per_frame; 
     392        unsigned erase_cnt = b->buf_cnt + b->samples_per_frame - b->max_cnt; 
     393 
     394        shrink_buffer(b, erase_cnt); 
     395    } 
     396 
     397    /* put the frame on put_pos */ 
     398    if (b->put_pos + b->samples_per_frame <= b->max_cnt) { 
     399        pjmedia_copy_samples(&b->frame_buf[b->put_pos], frame,  
     400                             b->samples_per_frame); 
     401    } else { 
     402        int remainder = b->put_pos + b->samples_per_frame - b->max_cnt; 
     403 
     404        pjmedia_copy_samples(&b->frame_buf[b->put_pos], frame,  
     405                             b->samples_per_frame - remainder); 
     406        pjmedia_copy_samples(&b->frame_buf[0],  
     407                             &frame[b->samples_per_frame - remainder],  
     408                             remainder); 
     409    } 
     410 
     411    /* Update put_pos & buf_cnt */ 
     412    b->put_pos = (b->put_pos + b->samples_per_frame) % b->max_cnt; 
     413    b->buf_cnt += b->samples_per_frame; 
     414 
     415    pj_lock_release(b->lock); 
    209416    return PJ_SUCCESS; 
    210417} 
    211418 
    212 PJ_DEF(pj_status_t) pjmedia_delay_buf_get(pjmedia_delay_buf *b, 
     419PJ_DEF(pj_status_t) pjmedia_delay_buf_get( pjmedia_delay_buf *b, 
    213420                                           pj_int16_t frame[]) 
    214421{ 
     422    pj_status_t status; 
     423 
     424    PJ_ASSERT_RETURN(b && frame, PJ_EINVAL); 
     425 
     426    pj_lock_acquire(b->lock); 
     427 
    215428    update(b, OP_GET); 
    216429 
    217     if (b->state != STATE_RUNNING || !b->buf_cnt) { 
    218         if (b->state == STATE_RUNNING) 
    219             PJ_LOG(5,(b->obj_name,"Warning: delay buffer empty")); 
    220  
    221         pj_bzero(frame, b->samples_per_frame*sizeof(pj_int16_t)); 
    222         return PJ_EPENDING; 
    223     } 
    224  
    225     pj_memcpy(frame, &b->frame_buf[b->get_pos * b->samples_per_frame], 
    226         b->samples_per_frame*sizeof(pj_int16_t)); 
    227  
    228     if (++b->get_pos == b->max_level) 
    229         b->get_pos = 0; 
    230  
    231     --b->buf_cnt; 
     430    /* Starvation checking */ 
     431    if (b->buf_cnt < b->samples_per_frame) { 
     432 
     433        PJ_LOG(5,(b->obj_name,"Underflow, buf_cnt=%d, will generate 1 frame", 
     434                  b->buf_cnt)); 
     435 
     436        status = pjmedia_wsola_generate(b->wsola, frame); 
     437 
     438        if (status == PJ_SUCCESS) { 
     439            TRACE__((b->obj_name,"Successfully generate 1 frame")); 
     440            if (b->buf_cnt == 0) { 
     441                pj_lock_release(b->lock); 
     442                return PJ_SUCCESS; 
     443            } 
     444 
     445            /* Put generated frame into buffer */ 
     446            if (b->put_pos + b->samples_per_frame <= b->max_cnt) { 
     447                pjmedia_copy_samples(&b->frame_buf[b->put_pos], frame,  
     448                                     b->samples_per_frame); 
     449            } else { 
     450                int remainder = b->put_pos + b->samples_per_frame - b->max_cnt; 
     451 
     452                pjmedia_copy_samples(&b->frame_buf[b->put_pos], &frame[0],  
     453                                     b->samples_per_frame - remainder); 
     454                pjmedia_copy_samples(&b->frame_buf[0],  
     455                                     &frame[b->samples_per_frame - remainder],  
     456                                     remainder); 
     457            } 
     458         
     459            b->put_pos = (b->put_pos + b->samples_per_frame) % b->max_cnt; 
     460            b->buf_cnt += b->samples_per_frame; 
     461 
     462        } else { 
     463            /* Give all what delay buffer has, then pad zeroes */ 
     464            PJ_LOG(4,(b->obj_name,"Error generating frame, status=%d",  
     465                      status)); 
     466 
     467            pjmedia_copy_samples(frame, &b->frame_buf[b->get_pos], b->buf_cnt); 
     468            pjmedia_zero_samples(&frame[b->buf_cnt],  
     469                                 b->samples_per_frame - b->buf_cnt); 
     470            b->get_pos += b->buf_cnt; 
     471            b->buf_cnt = 0; 
     472 
     473            /* Consistency checking */ 
     474            pj_assert(b->get_pos == b->put_pos); 
     475 
     476            pj_lock_release(b->lock); 
     477 
     478            return PJ_SUCCESS; 
     479        } 
     480    } 
     481 
     482    pjmedia_copy_samples(frame, &b->frame_buf[b->get_pos], 
     483                         b->samples_per_frame); 
     484 
     485    b->get_pos = (b->get_pos + b->samples_per_frame) % b->max_cnt; 
     486    b->buf_cnt -= b->samples_per_frame; 
     487 
     488    pj_lock_release(b->lock); 
    232489 
    233490    return PJ_SUCCESS; 
    234491} 
    235492 
    236 PJ_DECL(pj_status_t) pjmedia_delay_buf_learn(pjmedia_delay_buf *b) 
     493PJ_DEF(pj_status_t) pjmedia_delay_buf_learn(pjmedia_delay_buf *b) 
    237494{ 
    238495    PJ_ASSERT_RETURN(b, PJ_EINVAL); 
     496 
     497    pj_lock_acquire(b->lock); 
    239498 
    240499    b->last_op = OP_UNDEFINED; 
     
    243502    b->state_count = 0; 
    244503    b->max_level = 0; 
     504    b->max_cnt = b->max_frames * b->samples_per_frame; 
     505 
     506    pjmedia_delay_buf_reset(b); 
     507 
     508    pj_lock_release(b->lock); 
     509 
     510    PJ_LOG(5,(b->obj_name,"Delay buffer start learning")); 
     511 
     512    return PJ_SUCCESS; 
     513} 
     514 
     515PJ_DEF(pj_status_t) pjmedia_delay_buf_reset(pjmedia_delay_buf *b) 
     516{ 
     517    PJ_ASSERT_RETURN(b, PJ_EINVAL); 
     518 
     519    pj_lock_acquire(b->lock); 
    245520 
    246521    /* clean up buffer */ 
    247522    b->buf_cnt = 0; 
    248523    b->put_pos = b->get_pos = 0; 
    249  
    250     PJ_LOG(5,(b->obj_name,"Delay buffer start learning")); 
     524    pjmedia_wsola_reset(b->wsola, 0); 
     525 
     526    pj_lock_release(b->lock); 
     527 
     528    PJ_LOG(5,(b->obj_name,"Delay buffer resetted")); 
    251529 
    252530    return PJ_SUCCESS; 
    253531} 
     532 
Note: See TracChangeset for help on using the changeset viewer.