Ticket #438: ticket438.2.patch

File ticket438.2.patch, 24.2 KB (added by nanang, 17 years ago)
  • pjmedia/include/pjmedia/delaybuf.h

     
    6666 *                          from. 
    6767 * @param name              Optional name for the buffer for log  
    6868 *                          identification. 
     69 * @param clock_rate        Number of samples processed per second. 
    6970 * @param samples_per_frame Number of samples per frame. 
    70  * @param max_cnt           Maximum number of delay to be accommodated, 
     71 * @param max_frames        Maximum number of delay to be accommodated, 
    7172 *                          in number of frames. 
    7273 * @param delay             The delay to be applied, in number of frames. 
    73  *                          If the value is -1, the delay buffer will 
     74 *                          If the value is -1 or 0, the delay buffer will 
    7475 *                          learn about the delay automatically. If 
    7576 *                          the value is greater than zero, then this 
    7677 *                          value will be used and no learning will be 
     
    8384 */ 
    8485PJ_DECL(pj_status_t) pjmedia_delay_buf_create(pj_pool_t *pool, 
    8586                                              const char *name, 
     87                                              unsigned clock_rate, 
    8688                                              unsigned samples_per_frame, 
    87                                               unsigned max_cnt, 
     89                                              unsigned max_frames, 
    8890                                              int delay, 
    8991                                              pjmedia_delay_buf **p_b); 
    9092 
     
    131133 */ 
    132134PJ_DECL(pj_status_t) pjmedia_delay_buf_learn(pjmedia_delay_buf *b); 
    133135 
     136/** 
     137 * Reset delay buffer. This will clear the buffer's content. But keep 
     138 * the learning result. 
     139 * 
     140 * @param b                 The delay buffer. 
     141 * 
     142 * @return                  PJ_SUCCESS on success or the appropriate error. 
     143 */ 
     144PJ_DECL(pj_status_t) pjmedia_delay_buf_reset(pjmedia_delay_buf *b); 
    134145 
     146/** 
     147 * Destroy delay buffer. 
     148 * 
     149 * @param b         Delay buffer session. 
     150 * 
     151 * @return          PJ_SUCCESS normally. 
     152 */ 
     153PJ_DECL(pj_status_t) pjmedia_delay_buf_destroy(pjmedia_delay_buf *b); 
     154 
     155 
    135156PJ_END_DECL 
    136157 
    137158 
  • pjmedia/src/pjmedia/delaybuf.c

     
    1919 
    2020#include <pjmedia/delaybuf.h> 
    2121#include <pjmedia/errno.h> 
     22#include <pjmedia/wsola.h> 
    2223#include <pj/assert.h> 
    2324#include <pj/log.h> 
    2425#include <pj/pool.h> 
    2526 
     27 
     28#if 1 
     29#   define TRACE__(x) PJ_LOG(3,x) 
     30#else 
     31#   define TRACE__(x) 
     32#endif 
     33 
     34 
     35/* Type of states of delay buffer */ 
    2636enum state 
    2737{ 
    2838    STATE_WAITING, 
     
    3040    STATE_RUNNING 
    3141}; 
    3242 
     43/* Type of operation of delay buffer */ 
    3344enum OP 
    3445{ 
    3546    OP_PUT, 
     
    3748    OP_UNDEFINED 
    3849}; 
    3950 
    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 */ 
     51/* The following macros represent cycles of test. Since there are two 
     52 * operations performed (get & put), these macros minimum value must be 2  
     53 * and should be even number. 
     54 */ 
    4355#define WAITING_COUNT   4 
    4456#define LEARN_COUNT     16 
    4557 
    46 /* Number of buffers to add to learnt level for additional stability */ 
     58/* Number of buffers to add to learnt level for additional stability 
     59 * Please note that WSOLA discard needs minimum 3 frames, so max buffer count 
     60 * should be minimally 3, setting SAFE_MARGIN to 2 will guarantees this. 
     61 */ 
    4762#define SAFE_MARGIN     2 
    4863 
    4964/* 
     
    6681 
    6782struct pjmedia_delay_buf 
    6883{ 
    69     char         obj_name[PJ_MAX_OBJ_NAME]; 
     84    char             obj_name[PJ_MAX_OBJ_NAME]; 
    7085 
    71     pj_int16_t  *frame_buf; 
    72     unsigned     put_pos; 
    73     unsigned     get_pos; 
    74     unsigned     buf_cnt; 
     86    pj_int16_t      *frame_buf; 
     87    enum state       state;             /**< State of delay buffer           */ 
     88    unsigned         samples_per_frame; /**< Number of samples for one frame */ 
     89    unsigned         max_frames;        /**< Buffer allocated, in frames     */ 
    7590 
    76     unsigned     samples_per_frame; 
    77     unsigned     max_cnt; 
    78     enum state   state; 
     91    unsigned         put_pos;           /**< Position for put op, in samples */ 
     92    unsigned         get_pos;           /**< Position for get op, in samples */ 
     93    unsigned         buf_cnt;           /**< Number of buffered samples      */ 
     94    unsigned         max_cnt;           /**< Max number of buffered samples  */ 
    7995 
    8096    struct { 
    81         unsigned level; 
     97        unsigned     level;             /**< Burst level storage of learning */ 
    8298    } op[2]; 
     99    enum OP          last_op;           /**< Last op (GET or PUT) of learning*/ 
     100    unsigned         state_count;       /**< Counter of op cycles of learning*/ 
    83101 
    84     enum OP      last_op; 
    85     unsigned     max_level; 
    86     unsigned     state_count; 
     102    unsigned         max_level;         /**< Learning result: burst level    */ 
     103 
     104    pjmedia_wsola   *wsola;             /**< Drift handler                   */ 
    87105}; 
    88106 
    89107PJ_DEF(pj_status_t) pjmedia_delay_buf_create( pj_pool_t *pool, 
    90108                                              const char *name, 
     109                                              unsigned clock_rate, 
    91110                                              unsigned samples_per_frame, 
    92                                               unsigned max_cnt, 
     111                                              unsigned max_frames, 
    93112                                              int delay, 
    94113                                              pjmedia_delay_buf **p_b) 
    95114{ 
    96115    pjmedia_delay_buf *b; 
     116    pj_status_t status; 
    97117 
    98     PJ_ASSERT_RETURN(pool && samples_per_frame && max_cnt && p_b, PJ_EINVAL); 
     118    PJ_ASSERT_RETURN(pool && samples_per_frame && max_frames && p_b, PJ_EINVAL); 
     119    PJ_ASSERT_RETURN((int)max_frames >= delay, PJ_EINVAL); 
    99120 
    100121    if (!name) { 
    101122        name = "delaybuf"; 
     
    104125    b = PJ_POOL_ZALLOC_T(pool, pjmedia_delay_buf); 
    105126 
    106127    pj_ansi_strncpy(b->obj_name, name, PJ_MAX_OBJ_NAME-1); 
    107     b->frame_buf = (pj_int16_t*) 
    108                    pj_pool_zalloc(pool, samples_per_frame * max_cnt *  
    109                                          sizeof(pj_int16_t)); 
    110128    b->samples_per_frame = samples_per_frame; 
    111     b->max_cnt = max_cnt; 
     129    b->max_frames = max_frames; 
    112130 
     131    b->frame_buf = (pj_int16_t*) 
     132                   pj_pool_zalloc(pool, samples_per_frame * max_frames *  
     133                                  sizeof(pj_int16_t)); 
     134 
    113135    if (delay >= 0) { 
    114         PJ_ASSERT_RETURN(delay <= (int)max_cnt, PJ_EINVAL); 
     136        if (delay == 0) 
     137            delay = 1; 
    115138        b->max_level = delay; 
     139        b->max_cnt = delay * samples_per_frame; 
    116140        b->state = STATE_RUNNING; 
    117141    } else { 
     142        b->max_cnt = max_frames * samples_per_frame; 
    118143        b->last_op = OP_UNDEFINED; 
    119144        b->state = STATE_WAITING; 
    120         b->buf_cnt = 0; 
    121145    } 
    122146 
     147    status = pjmedia_wsola_create(pool, clock_rate, samples_per_frame,  
     148                                  PJMEDIA_WSOLA_NO_PLC, &b->wsola); 
     149    if (status != PJ_SUCCESS) 
     150        return status; 
     151 
    123152    *p_b = b; 
    124153 
    125     PJ_LOG(5,(b->obj_name,"Delay buffer created")); 
     154    TRACE__((b->obj_name,"Delay buffer created")); 
    126155 
    127156    return PJ_SUCCESS; 
    128157} 
    129158 
     159PJ_DEF(pj_status_t) pjmedia_delay_buf_destroy(pjmedia_delay_buf *b) 
     160{ 
     161    pj_status_t status; 
     162 
     163    status = pjmedia_wsola_destroy(b->wsola); 
     164    if (status == PJ_SUCCESS) 
     165        b->wsola = NULL; 
     166 
     167    return status; 
     168} 
     169 
     170/* This function will erase samples from delay buffer. 
     171 * The number of erased samples is guaranteed to be >= erase_cnt. 
     172 */ 
     173static void shrink_buffer(pjmedia_delay_buf *b, unsigned erase_cnt) 
     174{ 
     175    unsigned buf1len; 
     176    unsigned buf2len; 
     177    pj_status_t status; 
     178 
     179    pj_assert(b && erase_cnt); 
     180 
     181    if (b->get_pos < b->put_pos) { 
     182        /* sssss .. sssss 
     183         *  ^          ^ 
     184         *  G          P 
     185         */ 
     186        buf1len = b->put_pos - b->get_pos; 
     187        buf2len = 0; 
     188    } else { 
     189        /* sssss .. sssss 
     190         *  ^ ^ 
     191         *  P G 
     192         */ 
     193        buf1len = b->max_cnt - b->get_pos; 
     194        buf2len = b->put_pos; 
     195    } 
     196 
     197    /* Consistency checking */ 
     198    pj_assert((buf1len + buf2len) == b->buf_cnt); 
     199 
     200    if (buf1len != 0) 
     201        status = pjmedia_wsola_discard(b->wsola,  
     202                                       &b->frame_buf[b->get_pos], buf1len, 
     203                                       b->frame_buf, buf2len, 
     204                                       &erase_cnt); 
     205    else 
     206        status = pjmedia_wsola_discard(b->wsola,  
     207                                       b->frame_buf, buf2len, 
     208                                       NULL, 0, 
     209                                       &erase_cnt); 
     210 
     211    if ((status == PJ_SUCCESS) && (erase_cnt > 0)) { 
     212        /* WSOLA discard will shrink only the second buffer, but it may 
     213         * also shrink first buffer if second buffer is 'destroyed', so 
     214         * it is safe to just set the new put_pos. 
     215         */ 
     216        if (b->put_pos >= erase_cnt) 
     217            b->put_pos -= erase_cnt; 
     218        else 
     219            b->put_pos = b->max_cnt - (erase_cnt - b->put_pos); 
     220 
     221        b->buf_cnt -= erase_cnt; 
     222 
     223        TRACE__((b->obj_name,"Successfully shrinking %d samples, " 
     224                 "buf_cnt=%d", erase_cnt, b->buf_cnt)); 
     225    } 
     226 
     227    /* Shrinking failed or erased count is less than requested, 
     228     * delay buf needs to drop eldest samples, this is bad since the voice 
     229     * samples may not have smooth transition. 
     230     */ 
     231    if (b->buf_cnt + b->samples_per_frame > b->max_cnt) { 
     232        erase_cnt = b->buf_cnt + b->samples_per_frame - b->max_cnt; 
     233 
     234        b->buf_cnt -= erase_cnt; 
     235 
     236        /* Shift get_pos forward */ 
     237        b->get_pos = (b->get_pos + erase_cnt) % b->max_cnt; 
     238 
     239        TRACE__((b->obj_name,"Shrinking failed or insufficient, dropping" 
     240                 " %d eldest samples, buf_cnt=%d", erase_cnt, b->buf_cnt)); 
     241    } 
     242} 
     243 
     244static void set_max_cnt(pjmedia_delay_buf *b, unsigned new_max_cnt) 
     245{ 
     246    unsigned old_max_cnt = b->max_cnt; 
     247 
     248    /* nothing to adjust */ 
     249    if (old_max_cnt == new_max_cnt) 
     250        return; 
     251 
     252    /* For now, only support shrinking */ 
     253    pj_assert(old_max_cnt > new_max_cnt); 
     254 
     255    shrink_buffer(b, old_max_cnt - new_max_cnt); 
     256 
     257    /* Adjust buffer to accomodate the new max_cnt so the samples is secured. 
     258     * This is done by make get_pos = 0  
     259     */ 
     260    if (b->get_pos <= b->put_pos) { 
     261        /* sssss .. sssss 
     262         *   ^         ^ 
     263         *   G         P 
     264         */ 
     265        /* Consistency checking */ 
     266        pj_assert((b->put_pos - b->get_pos) <= new_max_cnt); 
     267        pj_assert((b->put_pos - b->get_pos) == b->buf_cnt); 
     268 
     269        pjmedia_move_samples(b->frame_buf, &b->frame_buf[b->get_pos],  
     270                             b->get_pos); 
     271        b->put_pos -= b->get_pos; 
     272        b->get_pos = 0; 
     273    } else { 
     274        /* sssss .. sssss 
     275         *          ^  ^ 
     276         *          P  G 
     277         */ 
     278        unsigned d = old_max_cnt - b->get_pos; 
     279 
     280        /* Consistency checking */ 
     281        pj_assert((b->get_pos - b->put_pos) >= (old_max_cnt - new_max_cnt)); 
     282 
     283        /* Make get_pos = 0, shift right the leftmost block first */ 
     284        pjmedia_move_samples(&b->frame_buf[d], b->frame_buf, d); 
     285        pjmedia_copy_samples(b->frame_buf, &b->frame_buf[b->get_pos], d); 
     286        b->put_pos += d; 
     287        b->get_pos = 0; 
     288    } 
     289 
     290    b->max_cnt = new_max_cnt; 
     291} 
     292 
    130293static void update(pjmedia_delay_buf *b, enum OP op) 
    131294{ 
    132295    enum OP other = (enum OP) !op; 
     
    157320                /* give SAFE_MARGIN compensation for added stability */ 
    158321                b->max_level += SAFE_MARGIN; 
    159322                 
    160                 PJ_LOG(5,(b->obj_name,"Delay buffer start running, level=%u", 
    161                     b->max_level)); 
     323                /* buffer not enough! */ 
     324                if (b->max_level > b->max_frames) { 
     325                    PJ_LOG(4,(b->obj_name,"Delay buffer learning result (%d)" 
     326                              " exceeds the maximum delay allowed (%d)", 
     327                              b->max_level, 
     328                              b->max_frames)); 
    162329 
    163                 /* 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)); 
     330                    b->max_level = b->max_frames; 
    169331                } 
    170332 
     333                /* we need to set new max_cnt & adjust buffer */ 
     334                set_max_cnt(b, b->max_level * b->samples_per_frame); 
     335 
    171336                b->state = STATE_RUNNING; 
     337 
     338                TRACE__((b->obj_name,"Delay buffer start running, level=%u", 
     339                         b->max_level)); 
    172340            } 
    173341        } 
    174342        b->last_op = op; 
     
    181349PJ_DEF(pj_status_t) pjmedia_delay_buf_put(pjmedia_delay_buf *b, 
    182350                                           pj_int16_t frame[]) 
    183351{ 
     352    pj_status_t status; 
     353 
    184354    update(b, OP_PUT); 
    185355     
    186     if (b->state != STATE_RUNNING) 
    187         return PJ_EPENDING; 
     356    status = pjmedia_wsola_save(b->wsola, frame, PJ_FALSE); 
     357    if (status != PJ_SUCCESS) 
     358        return status; 
    188359 
    189     pj_memcpy(&b->frame_buf[b->put_pos * b->samples_per_frame], frame,  
    190         b->samples_per_frame*sizeof(pj_int16_t)); 
     360    /* Overflow checking */ 
     361    if (b->buf_cnt + b->samples_per_frame > b->max_cnt) 
     362    { 
     363        /* shrink one frame or just the diff? */ 
     364        //unsigned erase_cnt = b->samples_per_frame; 
     365        unsigned erase_cnt = b->buf_cnt + b->samples_per_frame - b->max_cnt; 
    191366 
    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; 
     367        shrink_buffer(b, erase_cnt); 
     368    } 
    196369 
    197         b->put_pos = b->get_pos; 
     370    /* put the frame on put_pos */ 
     371    if (b->put_pos + b->samples_per_frame <= b->max_cnt) { 
     372        pjmedia_copy_samples(&b->frame_buf[b->put_pos], frame,  
     373                             b->samples_per_frame); 
     374    } else { 
     375        int remainder = b->put_pos + b->samples_per_frame - b->max_cnt; 
    198376 
    199         PJ_LOG(5,(b->obj_name,"Warning: buffer overflow")); 
    200  
    201         return PJ_ETOOMANY; 
     377        pjmedia_copy_samples(&b->frame_buf[b->put_pos], frame,  
     378                             b->samples_per_frame - remainder); 
     379        pjmedia_copy_samples(&b->frame_buf[0],  
     380                             &frame[b->samples_per_frame - remainder],  
     381                             remainder); 
    202382    } 
    203383 
    204     ++b->buf_cnt; 
     384    /* Update put_pos & buf_cnt */ 
     385    b->put_pos = (b->put_pos + b->samples_per_frame) % b->max_cnt; 
     386    b->buf_cnt += b->samples_per_frame; 
    205387 
    206     if (++b->put_pos == b->max_level) 
    207         b->put_pos = 0; 
    208  
    209388    return PJ_SUCCESS; 
    210389} 
    211390 
    212391PJ_DEF(pj_status_t) pjmedia_delay_buf_get(pjmedia_delay_buf *b, 
    213392                                           pj_int16_t frame[]) 
    214393{ 
     394    pj_status_t status; 
     395 
    215396    update(b, OP_GET); 
    216397 
    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")); 
     398    /* Starvation checking */ 
     399    if (b->buf_cnt < b->samples_per_frame) { 
    220400 
    221         pj_bzero(frame, b->samples_per_frame*sizeof(pj_int16_t)); 
    222         return PJ_EPENDING; 
     401        TRACE__((b->obj_name,"Warning: buffer lack of samples, buf_cnt=%d", 
     402                 b->buf_cnt)); 
     403 
     404        status = pjmedia_wsola_generate(b->wsola, frame); 
     405 
     406        if (status == PJ_SUCCESS) { 
     407            TRACE__((b->obj_name,"Successfully generate frame")); 
     408            if (b->buf_cnt == 0) 
     409                return PJ_SUCCESS; 
     410 
     411            /* Put generated frame into buffer */ 
     412            if (b->put_pos + b->samples_per_frame <= b->max_cnt) { 
     413                pjmedia_copy_samples(&b->frame_buf[b->put_pos], frame,  
     414                                     b->samples_per_frame); 
     415            } else { 
     416                int remainder = b->put_pos + b->samples_per_frame - b->max_cnt; 
     417 
     418                pjmedia_copy_samples(&b->frame_buf[b->put_pos], &frame[0],  
     419                                     b->samples_per_frame - remainder); 
     420                pjmedia_copy_samples(&b->frame_buf[0],  
     421                                     &frame[b->samples_per_frame - remainder],  
     422                                     remainder); 
     423            } 
     424         
     425            b->put_pos = (b->put_pos + b->samples_per_frame) % b->max_cnt; 
     426            b->buf_cnt += b->samples_per_frame; 
     427 
     428        } else { 
     429            /* Give all what delay buffer has, then pad zeroes */ 
     430            TRACE__((b->obj_name,"Failed generate frame")); 
     431 
     432            pjmedia_copy_samples(frame, &b->frame_buf[b->get_pos], b->buf_cnt); 
     433            pjmedia_zero_samples(&frame[b->buf_cnt],  
     434                                 b->samples_per_frame - b->buf_cnt); 
     435            b->get_pos += b->buf_cnt; 
     436            b->buf_cnt = 0; 
     437 
     438            /* Consistency checking */ 
     439            pj_assert(b->get_pos == b->put_pos); 
     440 
     441            return PJ_SUCCESS; 
     442        } 
    223443    } 
    224444 
    225     pj_memcpy(frame, &b->frame_buf[b->get_pos * b->samples_per_frame], 
    226         b->samples_per_frame*sizeof(pj_int16_t)); 
     445    pjmedia_copy_samples(frame, &b->frame_buf[b->get_pos], 
     446                         b->samples_per_frame); 
    227447 
    228     if (++b->get_pos == b->max_level) 
    229         b->get_pos = 0; 
     448    b->get_pos = (b->get_pos + b->samples_per_frame) % b->max_cnt; 
     449    b->buf_cnt -= b->samples_per_frame; 
    230450 
    231     --b->buf_cnt; 
    232  
    233451    return PJ_SUCCESS; 
    234452} 
    235453 
    236 PJ_DECL(pj_status_t) pjmedia_delay_buf_learn(pjmedia_delay_buf *b) 
     454PJ_DEF(pj_status_t) pjmedia_delay_buf_learn(pjmedia_delay_buf *b) 
    237455{ 
    238456    PJ_ASSERT_RETURN(b, PJ_EINVAL); 
    239457 
     
    242460    b->state = STATE_LEARNING; 
    243461    b->state_count = 0; 
    244462    b->max_level = 0; 
     463    b->max_cnt = b->max_frames * b->samples_per_frame; 
    245464 
     465    pjmedia_delay_buf_reset(b); 
     466 
     467    TRACE__((b->obj_name,"Delay buffer start learning")); 
     468 
     469    return PJ_SUCCESS; 
     470} 
     471 
     472PJ_DEF(pj_status_t) pjmedia_delay_buf_reset(pjmedia_delay_buf *b) 
     473{ 
     474    PJ_ASSERT_RETURN(b, PJ_EINVAL); 
     475 
    246476    /* clean up buffer */ 
    247477    b->buf_cnt = 0; 
    248478    b->put_pos = b->get_pos = 0; 
     479    pjmedia_wsola_reset(b->wsola, 0); 
    249480 
    250     PJ_LOG(5,(b->obj_name,"Delay buffer start learning")); 
     481    TRACE__((b->obj_name,"Delay buffer resetted")); 
    251482 
    252483    return PJ_SUCCESS; 
    253484} 
  • pjmedia/src/pjmedia/conference.c

     
    1818 */ 
    1919#include <pjmedia/conference.h> 
    2020#include <pjmedia/alaw_ulaw.h> 
     21#include <pjmedia/delaybuf.h> 
    2122#include <pjmedia/errno.h> 
    2223#include <pjmedia/port.h> 
    2324#include <pjmedia/resample.h> 
     
    5657 
    5758#define THIS_FILE       "conference.c" 
    5859 
    59 /* When delay buffer is used, we only need 1 frame buffering */ 
    60 #if defined(PJMEDIA_SOUND_USE_DELAYBUF) && PJMEDIA_SOUND_USE_DELAYBUF!=0 
    61 #   define RX_BUF_COUNT     1 
    62 #else 
    63 #   define RX_BUF_COUNT     PJMEDIA_SOUND_BUFFER_COUNT 
    64 #endif 
     60#define RX_BUF_COUNT        PJMEDIA_SOUND_BUFFER_COUNT 
    6561 
    6662#define BYTES_PER_SAMPLE    2 
    6763 
     
    183179    unsigned             tx_buf_cap;    /**< Max size, in samples.          */ 
    184180    unsigned             tx_buf_count;  /**< # of samples in the buffer.    */ 
    185181 
    186     /* Snd buffers is a special buffer for sound device port (port 0, master 
    187      * port). It's not used by other ports. 
     182    /* Delay buffer is a special buffer for sound device port (port 0, master 
     183     * port) and other passive ports (sound device port is also passive port). 
    188184     * 
    189      * There are multiple numbers of this buffer, because we can not expect 
    190      * the mic and speaker thread to run equally after one another. In most 
    191      * systems, each thread will run multiple times before the other thread 
    192      * gains execution time. For example, in my system, mic thread is called 
    193      * three times, then speaker thread is called three times, and so on. 
     185     * We need the delay buffer because we can not expect the mic and speaker  
     186     * thread to run equally after one another. In most systems, each thread  
     187     * will run multiple times before the other thread gains execution time.  
     188     * For example, in my system, mic thread is called three times, then  
     189     * speaker thread is called three times, and so on. This we call burst. 
     190     * 
     191     * There is also possibility of drift, unbalanced rate between put_frame 
     192     * and get_frame operation, in passive ports. If drift happens, snd_buf 
     193     * needs to be expanded or shrinked.  
     194     * 
     195     * Burst and drift are handled by delay buffer. 
    194196     */ 
    195     int                  snd_write_pos, snd_read_pos; 
    196     pj_int16_t          *snd_buf[RX_BUF_COUNT]; /**< Buffer                 */ 
     197    pjmedia_delay_buf   *delay_buf; 
    197198}; 
    198199 
    199200 
     
    226227static pj_status_t get_frame_pasv(pjmedia_port *this_port,  
    227228                                  pjmedia_frame *frame); 
    228229static pj_status_t destroy_port(pjmedia_port *this_port); 
     230static pj_status_t destroy_port_pasv(pjmedia_port *this_port); 
    229231 
    230232 
    231233/* 
     
    377379                                     struct conf_port **p_conf_port) 
    378380{ 
    379381    struct conf_port *conf_port; 
    380     unsigned i; 
    381382    pj_status_t status; 
    382383 
    383384    /* Create port */ 
     
    385386    if (status != PJ_SUCCESS) 
    386387        return status; 
    387388 
    388     /* Passive port has rx buffers. */ 
    389     for (i=0; i<RX_BUF_COUNT; ++i) { 
    390         conf_port->snd_buf[i] = (pj_int16_t*) 
    391                                 pj_pool_zalloc(pool, conf->samples_per_frame * 
    392                                               sizeof(conf_port->snd_buf[0][0])); 
    393         if (conf_port->snd_buf[i] == NULL) { 
    394             return PJ_ENOMEM; 
    395         } 
    396     } 
    397     conf_port->snd_write_pos = 0; 
    398     conf_port->snd_read_pos = 0; 
     389    /* Passive port has delay buf. */ 
     390    status = pjmedia_delay_buf_create(pool, name->ptr,  
     391                                      conf->clock_rate, 
     392                                      conf->samples_per_frame, 
     393                                      RX_BUF_COUNT, /* max */ 
     394                                      -1, /* delay */ 
     395                                      &conf_port->delay_buf); 
     396    if (status != PJ_SUCCESS) 
     397        return status; 
    399398 
    400399    *p_conf_port = conf_port; 
    401400 
     
    444443                                              conf->bits_per_sample, 
    445444                                              0,    /* Options */ 
    446445                                              &conf->snd_dev_port); 
     446 
    447447        } 
    448448 
    449449        if (status != PJ_SUCCESS) 
     
    606606    return pjmedia_conf_destroy(conf); 
    607607} 
    608608 
     609static pj_status_t destroy_port_pasv(pjmedia_port *this_port) { 
     610    pjmedia_conf *conf = (pjmedia_conf*) this_port->port_data.pdata; 
     611    struct conf_port *port = conf->ports[this_port->port_data.ldata]; 
     612    pj_status_t status; 
    609613 
     614    status = pjmedia_delay_buf_destroy(port->delay_buf); 
     615    if (status == PJ_SUCCESS) 
     616        port->delay_buf = NULL; 
     617 
     618    return status; 
     619} 
     620 
    610621/* 
    611622 * Get port zero interface. 
    612623 */ 
     
    785796 
    786797    port->get_frame = &get_frame_pasv; 
    787798    port->put_frame = &put_frame; 
    788     port->on_destroy = NULL; 
     799    port->on_destroy = &destroy_port_pasv; 
    789800 
    790801     
    791802    /* Create conf port structure. */ 
     
    954965                  (int)dst_port->name.slen, 
    955966                  dst_port->name.ptr)); 
    956967 
    957          
     968        /* if source port is passive port and has no listener, reset delaybuf */ 
     969        if (src_port->delay_buf && src_port->listener_cnt == 0) 
     970            pjmedia_delay_buf_reset(src_port->delay_buf); 
    958971    } 
    959972 
    960973    pj_mutex_unlock(conf->mutex); 
     
    16161629            continue; 
    16171630        } 
    16181631 
    1619         /* Get frame from this port.  
    1620          * For port zero (sound port) and passive ports, get the frame  from  
    1621          * the rx_buffer instead. 
     1632        /* Get frame from this port. 
     1633         * For passive ports, get the frame from the delay_buf. 
     1634         * For other ports, get the frame from the port.  
    16221635         */ 
    1623         if (conf_port->port == NULL) { 
    1624             pj_int16_t *snd_buf; 
    1625  
    1626             if (conf_port->snd_read_pos == conf_port->snd_write_pos) { 
    1627                 conf_port->snd_read_pos =  
    1628                     (conf_port->snd_write_pos+RX_BUF_COUNT-RX_BUF_COUNT/2) %  
    1629                         RX_BUF_COUNT; 
    1630             } 
    1631  
    1632             /* Skip if this port is muted/disabled. */ 
    1633             if (conf_port->rx_setting != PJMEDIA_PORT_ENABLE) { 
    1634                 conf_port->rx_level = 0; 
     1636        if (conf_port->delay_buf != NULL) { 
     1637            pj_status_t status; 
     1638         
     1639            status = pjmedia_delay_buf_get(conf_port->delay_buf, 
     1640                                  (pj_int16_t*)frame->buf); 
     1641            if (status != PJ_SUCCESS) 
    16351642                continue; 
    1636             } 
    16371643 
    1638             snd_buf = conf_port->snd_buf[conf_port->snd_read_pos]; 
    1639             pjmedia_copy_samples((pj_int16_t*)frame->buf, snd_buf,  
    1640                                  conf->samples_per_frame); 
    1641             conf_port->snd_read_pos = (conf_port->snd_read_pos+1) % RX_BUF_COUNT; 
    1642  
    16431644        } else { 
    16441645 
    16451646            pj_status_t status; 
     
    18301831 
    18311832 
    18321833/* 
    1833  * Recorder callback. 
     1834 * Recorder (or passive port) callback. 
    18341835 */ 
    18351836static pj_status_t put_frame(pjmedia_port *this_port,  
    18361837                             const pjmedia_frame *frame) 
    18371838{ 
    18381839    pjmedia_conf *conf = (pjmedia_conf*) this_port->port_data.pdata; 
    18391840    struct conf_port *port = conf->ports[this_port->port_data.ldata]; 
    1840     const pj_int16_t *input = (const pj_int16_t*) frame->buf; 
    1841     pj_int16_t *target_snd_buf; 
     1841    pj_status_t status; 
    18421842 
    18431843    /* Check for correct size. */ 
    18441844    PJ_ASSERT_RETURN( frame->size == conf->samples_per_frame * 
    18451845                                     conf->bits_per_sample / 8, 
    18461846                      PJMEDIA_ENCSAMPLESPFRAME); 
    18471847 
     1848    /* Check existance of delay_buf instance */ 
     1849    PJ_ASSERT_RETURN( port->delay_buf, PJ_EBUG ); 
     1850 
    18481851    /* Skip if this port is muted/disabled. */ 
    18491852    if (port->rx_setting != PJMEDIA_PORT_ENABLE) { 
    18501853        return PJ_SUCCESS; 
     
    18551858        return PJ_SUCCESS; 
    18561859    } 
    18571860 
     1861    status = pjmedia_delay_buf_put(port->delay_buf, (pj_int16_t*)frame->buf); 
    18581862 
    1859     /* Determine which rx_buffer to fill in */ 
    1860     target_snd_buf = port->snd_buf[port->snd_write_pos]; 
    1861      
    1862     /* Copy samples from audio device to target rx_buffer */ 
    1863     pjmedia_copy_samples(target_snd_buf, input, conf->samples_per_frame); 
    1864  
    1865     /* Switch buffer */ 
    1866     port->snd_write_pos = (port->snd_write_pos+1)%RX_BUF_COUNT; 
    1867  
    1868  
    1869     return PJ_SUCCESS; 
     1863    return status; 
    18701864} 
    18711865 
  • pjmedia/src/pjmedia/sound_port.c

     
    3232 
    3333#define THIS_FILE           "sound_port.c" 
    3434 
     35#define TEST_OVERFLOW_UNDERFLOW 
     36 
    3537enum 
    3638{ 
    3739    PJMEDIA_PLC_ENABLED     = 1, 
     
    101103#if PJMEDIA_SOUND_USE_DELAYBUF 
    102104    if (snd_port->delay_buf) { 
    103105        status = pjmedia_delay_buf_get(snd_port->delay_buf, (pj_int16_t*)output); 
    104         if (status != PJ_SUCCESS) { 
     106        if (status != PJ_SUCCESS) 
    105107            pj_bzero(output, size); 
    106         } 
    107108 
    108109        frame.type = PJMEDIA_FRAME_TYPE_AUDIO; 
    109110        pjmedia_port_put_frame(port, &frame); 
     111 
     112#ifdef TEST_OVERFLOW_UNDERFLOW 
     113        { 
     114            static int count = 1; 
     115            if (++count % 10 == 0) { 
     116                status = pjmedia_delay_buf_get(snd_port->delay_buf,  
     117                                               (pj_int16_t*)output); 
     118                if (status != PJ_SUCCESS) 
     119                    pj_bzero(output, size); 
     120 
     121                frame.type = PJMEDIA_FRAME_TYPE_AUDIO; 
     122                pjmedia_port_put_frame(port, &frame); 
     123            } 
     124        } 
     125#endif 
     126 
    110127    } 
    111128#endif 
    112129 
     
    371388    snd_port->bits_per_sample = bits_per_sample; 
    372389     
    373390#if PJMEDIA_SOUND_USE_DELAYBUF 
    374     status = pjmedia_delay_buf_create(pool, "snd_buff", samples_per_frame,  
     391    status = pjmedia_delay_buf_create(pool, "snd_buff",  
     392                                      clock_rate, samples_per_frame,  
    375393                                      PJMEDIA_SOUND_BUFFER_COUNT, -1,  
    376394                                      &snd_port->delay_buf); 
    377395    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);