Changeset 1833 for pjproject/trunk


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

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

Location:
pjproject/trunk/pjmedia
Files:
5 edited

Legend:

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

    r1664 r1833  
    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 
    7778 *                          performed. 
     79 * @param option            Option flags, must be zero for now. 
    7880 * @param p_b               Pointer to receive the delay buffer instance. 
    7981 * 
     
    8486PJ_DECL(pj_status_t) pjmedia_delay_buf_create(pj_pool_t *pool, 
    8587                                              const char *name, 
     88                                              unsigned clock_rate, 
    8689                                              unsigned samples_per_frame, 
    87                                               unsigned max_cnt, 
     90                                              unsigned max_frames, 
    8891                                              int delay, 
     92                                              unsigned options, 
    8993                                              pjmedia_delay_buf **p_b); 
    9094 
     
    132136PJ_DECL(pj_status_t) pjmedia_delay_buf_learn(pjmedia_delay_buf *b); 
    133137 
     138/** 
     139 * Reset delay buffer. This will clear the buffer's content. But keep 
     140 * the learning result. 
     141 * 
     142 * @param b                 The delay buffer. 
     143 * 
     144 * @return                  PJ_SUCCESS on success or the appropriate error. 
     145 */ 
     146PJ_DECL(pj_status_t) pjmedia_delay_buf_reset(pjmedia_delay_buf *b); 
     147 
     148/** 
     149 * Destroy delay buffer. 
     150 * 
     151 * @param b         Delay buffer session. 
     152 * 
     153 * @return          PJ_SUCCESS normally. 
     154 */ 
     155PJ_DECL(pj_status_t) pjmedia_delay_buf_destroy(pjmedia_delay_buf *b); 
     156 
    134157 
    135158PJ_END_DECL 
  • pjproject/trunk/pjmedia/src/pjmedia/conference.c

    r1715 r1833  
    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> 
     
    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 
     
    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. 
    194      */ 
    195     int                  snd_write_pos, snd_read_pos; 
    196     pj_int16_t          *snd_buf[RX_BUF_COUNT]; /**< Buffer                 */ 
     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. 
     196     */ 
     197    pjmedia_delay_buf   *delay_buf; 
    197198}; 
    198199 
     
    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 
     
    378380{ 
    379381    struct conf_port *conf_port; 
    380     unsigned i; 
    381382    pj_status_t status; 
    382383 
     
    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                                      0, /* options */ 
     396                                      &conf_port->delay_buf); 
     397    if (status != PJ_SUCCESS) 
     398        return status; 
    399399 
    400400    *p_conf_port = conf_port; 
     
    445445                                              0,    /* Options */ 
    446446                                              &conf->snd_dev_port); 
     447 
    447448        } 
    448449 
     
    607608} 
    608609 
     610static pj_status_t destroy_port_pasv(pjmedia_port *this_port) { 
     611    pjmedia_conf *conf = (pjmedia_conf*) this_port->port_data.pdata; 
     612    struct conf_port *port = conf->ports[this_port->port_data.ldata]; 
     613    pj_status_t status; 
     614 
     615    status = pjmedia_delay_buf_destroy(port->delay_buf); 
     616    if (status == PJ_SUCCESS) 
     617        port->delay_buf = NULL; 
     618 
     619    return status; 
     620} 
    609621 
    610622/* 
     
    786798    port->get_frame = &get_frame_pasv; 
    787799    port->put_frame = &put_frame; 
    788     port->on_destroy = NULL; 
     800    port->on_destroy = &destroy_port_pasv; 
    789801 
    790802     
     
    955967                  dst_port->name.ptr)); 
    956968 
    957          
     969        /* if source port is passive port and has no listener, reset delaybuf */ 
     970        if (src_port->delay_buf && src_port->listener_cnt == 0) 
     971            pjmedia_delay_buf_reset(src_port->delay_buf); 
    958972    } 
    959973 
     
    16171631        } 
    16181632 
    1619         /* Get frame from this port.  
    1620          * For port zero (sound port) and passive ports, get the frame  from  
    1621          * the rx_buffer instead. 
     1633        /* Get frame from this port. 
     1634         * For passive ports, get the frame from the delay_buf. 
     1635         * For other ports, get the frame from the port.  
    16221636         */ 
    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; 
     1637        if (conf_port->delay_buf != NULL) { 
     1638            pj_status_t status; 
     1639         
     1640            status = pjmedia_delay_buf_get(conf_port->delay_buf, 
     1641                                  (pj_int16_t*)frame->buf); 
     1642            if (status != PJ_SUCCESS) 
    16351643                continue; 
    1636             } 
    1637  
    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; 
    16421644 
    16431645        } else { 
     
    18311833 
    18321834/* 
    1833  * Recorder callback. 
     1835 * Recorder (or passive port) callback. 
    18341836 */ 
    18351837static pj_status_t put_frame(pjmedia_port *this_port,  
     
    18381840    pjmedia_conf *conf = (pjmedia_conf*) this_port->port_data.pdata; 
    18391841    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; 
     1842    pj_status_t status; 
    18421843 
    18431844    /* Check for correct size. */ 
     
    18461847                      PJMEDIA_ENCSAMPLESPFRAME); 
    18471848 
     1849    /* Check existance of delay_buf instance */ 
     1850    PJ_ASSERT_RETURN( port->delay_buf, PJ_EBUG ); 
     1851 
    18481852    /* Skip if this port is muted/disabled. */ 
    18491853    if (port->rx_setting != PJMEDIA_PORT_ENABLE) { 
     
    18561860    } 
    18571861 
    1858  
    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; 
    1870 } 
    1871  
     1862    status = pjmedia_delay_buf_put(port->delay_buf, (pj_int16_t*)frame->buf); 
     1863 
     1864    return status; 
     1865} 
     1866 
  • 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 
  • pjproject/trunk/pjmedia/src/pjmedia/sound_port.c

    r1825 r1833  
    3333#define THIS_FILE           "sound_port.c" 
    3434 
     35#define TEST_OVERFLOW_UNDERFLOW 
     36 
    3537enum 
    3638{ 
     
    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 
     
    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); 
  • pjproject/trunk/pjmedia/src/test/wsola_test.c

    r1832 r1833  
    328328    pool = pj_pool_create(&cp.factory, "", 1000, 1000, NULL); 
    329329 
    330     mem_test(pool); 
    331     return 0; 
    332  
    333330    srand(2); 
    334331 
    335     rc = expand(pool, "beet44.pcm", "output.pcm", 1, 0, 0); 
     332    rc = expand(pool, "beet44.pcm", "output.pcm", 0, 0, 0); 
    336333    //rc = compress(pool, "beet44.pcm", "output.pcm", 2); 
    337334 
Note: See TracChangeset for help on using the changeset viewer.