Ticket #438: ticket438.patch

File ticket438.patch, 21.7 KB (added by nanang, 16 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 * Destroy delay buffer. 
     138 * 
     139 * @param b         Delay buffer session. 
     140 * 
     141 * @return          PJ_SUCCESS normally. 
     142 */ 
     143PJ_DECL(pj_status_t) pjmedia_delay_buf_destroy(pjmedia_delay_buf *b); 
    134144 
     145 
    135146PJ_END_DECL 
    136147 
    137148 
  • 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 
    130171static void update(pjmedia_delay_buf *b, enum OP op) 
    131172{ 
    132173    enum OP other = (enum OP) !op; 
     
    157198                /* give SAFE_MARGIN compensation for added stability */ 
    158199                b->max_level += SAFE_MARGIN; 
    159200                 
    160                 PJ_LOG(5,(b->obj_name,"Delay buffer start running, level=%u", 
    161                     b->max_level)); 
     201                TRACE__((b->obj_name,"Delay buffer start running, level=%u", 
     202                        b->max_level)); 
    162203 
    163204                /* 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)); 
     205                if (b->max_level > b->max_frames) { 
     206                    PJ_LOG(4,(b->obj_name,"Delay buffer learning result (%d)" 
     207                              " exceeds the maximum delay allowed (%d)", 
     208                              b->max_level, 
     209                              b->max_frames)); 
     210 
     211                    b->max_level = b->max_frames; 
    169212                } 
    170213 
     214                b->max_cnt = b->max_level * b->samples_per_frame; 
    171215                b->state = STATE_RUNNING; 
    172216            } 
    173217        } 
     
    181225PJ_DEF(pj_status_t) pjmedia_delay_buf_put(pjmedia_delay_buf *b, 
    182226                                           pj_int16_t frame[]) 
    183227{ 
     228    pj_status_t status; 
     229 
    184230    update(b, OP_PUT); 
    185231     
     232    status = pjmedia_wsola_save(b->wsola, frame, PJ_FALSE); 
     233    if (status != PJ_SUCCESS) 
     234        return status; 
     235 
    186236    if (b->state != STATE_RUNNING) 
    187237        return PJ_EPENDING; 
     238     
     239    /* Overflow checking */ 
     240    if (b->buf_cnt + b->samples_per_frame > b->max_cnt) 
     241    { 
     242        /* shrink one frame or just the diff? */ 
     243        //unsigned erase_cnt = b->samples_per_frame; 
     244        unsigned erase_cnt = b->buf_cnt + b->samples_per_frame - b->max_cnt; 
    188245 
    189     pj_memcpy(&b->frame_buf[b->put_pos * b->samples_per_frame], frame,  
    190         b->samples_per_frame*sizeof(pj_int16_t)); 
     246        unsigned buf1len; 
     247        unsigned buf2len; 
    191248 
    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; 
     249        TRACE__((b->obj_name,"Warning: buffer overflow, buf_cnt=%d, " 
     250                 "trying to shrink %d samples", b->buf_cnt, erase_cnt)); 
    196251 
    197         b->put_pos = b->get_pos; 
     252        if (b->get_pos < b->put_pos) { 
     253            /* sssss .. sssss 
     254             *  ^          ^ 
     255             *  G          P 
     256             */ 
     257            buf1len = b->put_pos - b->get_pos; 
     258            buf2len = 0; 
     259        } else { 
     260            /* sssss .. sssss 
     261             *  ^ ^ 
     262             *  P G 
     263             */ 
     264            buf1len = b->max_cnt - b->get_pos; 
     265            buf2len = b->put_pos; 
     266        } 
    198267 
    199         PJ_LOG(5,(b->obj_name,"Warning: buffer overflow")); 
     268        if (buf1len != 0) 
     269            status = pjmedia_wsola_discard(b->wsola,  
     270                                           &b->frame_buf[b->get_pos], buf1len, 
     271                                           b->frame_buf, buf2len, 
     272                                           &erase_cnt); 
     273        else 
     274            status = pjmedia_wsola_discard(b->wsola,  
     275                                           b->frame_buf, buf2len, 
     276                                           NULL, 0, 
     277                                           &erase_cnt); 
    200278 
    201         return PJ_ETOOMANY; 
     279        if ((status == PJ_SUCCESS) && (erase_cnt > 0)) { 
     280            /* WSOLA discard will shrink only the second buffer, but it may 
     281             * also shrink first buffer if second buffer is 'destroyed', so 
     282             * it is safe to just set the new put_pos. 
     283             */ 
     284            if (b->put_pos >= erase_cnt) 
     285                b->put_pos -= erase_cnt; 
     286            else 
     287                b->put_pos = b->max_cnt - (erase_cnt - b->put_pos); 
     288 
     289            b->buf_cnt -= erase_cnt; 
     290 
     291            TRACE__((b->obj_name,"Successfully shrinking %d samples, " 
     292                     "buf_cnt=%d", erase_cnt, b->buf_cnt)); 
     293        } 
     294 
     295        /* Shrinking failed or erased count is less than requested, 
     296         * delay buf needs to drop eldest samples, this is bad since the voice 
     297         * samples may not have smooth transition. 
     298         */ 
     299        if (b->buf_cnt + b->samples_per_frame > b->max_cnt) { 
     300            erase_cnt = b->buf_cnt + b->samples_per_frame - b->max_cnt; 
     301 
     302            b->buf_cnt -= erase_cnt; 
     303 
     304            /* Shift get_pos forward */ 
     305            b->get_pos = (b->get_pos + erase_cnt) % b->max_cnt; 
     306 
     307            TRACE__((b->obj_name,"Shrinking failed or insufficient, dropping" 
     308                     " %d eldest samples, buf_cnt=%d", erase_cnt, b->buf_cnt)); 
     309        } 
    202310    } 
    203311 
    204     ++b->buf_cnt; 
     312    /* put the frame on put_pos */ 
     313    if (b->put_pos + b->samples_per_frame <= b->max_cnt) { 
     314        pjmedia_copy_samples(&b->frame_buf[b->put_pos], frame,  
     315                             b->samples_per_frame); 
     316    } else { 
     317        int remainder = b->put_pos + b->samples_per_frame - b->max_cnt; 
    205318 
    206     if (++b->put_pos == b->max_level) 
    207         b->put_pos = 0; 
     319        pjmedia_copy_samples(&b->frame_buf[b->put_pos], frame,  
     320                             b->samples_per_frame - remainder); 
     321        pjmedia_copy_samples(&b->frame_buf[0],  
     322                             &frame[b->samples_per_frame - remainder],  
     323                             remainder); 
     324    } 
    208325 
     326    /* Update put_pos & buf_cnt */ 
     327    b->put_pos = (b->put_pos + b->samples_per_frame) % b->max_cnt; 
     328    b->buf_cnt += b->samples_per_frame; 
     329 
    209330    return PJ_SUCCESS; 
    210331} 
    211332 
    212333PJ_DEF(pj_status_t) pjmedia_delay_buf_get(pjmedia_delay_buf *b, 
    213334                                           pj_int16_t frame[]) 
    214335{ 
     336    pj_status_t status; 
    215337    update(b, OP_GET); 
    216338 
    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)); 
     339    if (b->state != STATE_RUNNING) { 
     340        pjmedia_zero_samples(frame, b->samples_per_frame); 
    222341        return PJ_EPENDING; 
    223342    } 
    224343 
    225     pj_memcpy(frame, &b->frame_buf[b->get_pos * b->samples_per_frame], 
    226         b->samples_per_frame*sizeof(pj_int16_t)); 
     344    /* Starvation checking */ 
     345    if (b->buf_cnt < b->samples_per_frame) { 
    227346 
    228     if (++b->get_pos == b->max_level) 
    229         b->get_pos = 0; 
     347        TRACE__((b->obj_name,"Warning: buffer lack of samples, buf_cnt=%d", 
     348                 b->buf_cnt)); 
    230349 
    231     --b->buf_cnt; 
     350        status = pjmedia_wsola_generate(b->wsola, frame); 
    232351 
     352        if (status == PJ_SUCCESS) { 
     353            TRACE__((b->obj_name,"Successfully generate frame")); 
     354            if (b->buf_cnt == 0) 
     355                return PJ_SUCCESS; 
     356 
     357            /* put generated frame into buffer */ 
     358            if (b->put_pos + b->samples_per_frame <= b->max_cnt) { 
     359                pjmedia_copy_samples(&b->frame_buf[b->put_pos], frame,  
     360                                     b->samples_per_frame); 
     361            } else { 
     362                int remainder = b->put_pos + b->samples_per_frame - b->max_cnt; 
     363 
     364                pjmedia_copy_samples(&b->frame_buf[b->put_pos], &frame[0],  
     365                                     b->samples_per_frame - remainder); 
     366                pjmedia_copy_samples(&b->frame_buf[0],  
     367                                     &frame[b->samples_per_frame - remainder],  
     368                                     remainder); 
     369            } 
     370         
     371            b->put_pos = (b->put_pos + b->samples_per_frame) % b->max_cnt; 
     372            b->buf_cnt += b->samples_per_frame; 
     373 
     374        } else { 
     375            /* Give all what delay buffer has, then pad zeroes */ 
     376            TRACE__((b->obj_name,"Failed generate frame")); 
     377 
     378            pjmedia_copy_samples(frame, &b->frame_buf[b->get_pos], b->buf_cnt); 
     379            pjmedia_zero_samples(&frame[b->buf_cnt],  
     380                                 b->samples_per_frame - b->buf_cnt); 
     381            b->get_pos += b->buf_cnt; 
     382            b->buf_cnt = 0; 
     383 
     384            /* Consistency checking */ 
     385            pj_assert(b->get_pos == b->put_pos); 
     386 
     387            return PJ_SUCCESS; 
     388        } 
     389    } 
     390 
     391    pjmedia_copy_samples(frame, &b->frame_buf[b->get_pos], 
     392                         b->samples_per_frame); 
     393 
     394    b->get_pos = (b->get_pos + b->samples_per_frame) % b->max_cnt; 
     395    b->buf_cnt -= b->samples_per_frame; 
     396 
    233397    return PJ_SUCCESS; 
    234398} 
    235399 
     
    242406    b->state = STATE_LEARNING; 
    243407    b->state_count = 0; 
    244408    b->max_level = 0; 
     409    b->max_cnt = 0; 
    245410 
    246411    /* clean up buffer */ 
    247412    b->buf_cnt = 0; 
    248413    b->put_pos = b->get_pos = 0; 
    249414 
    250     PJ_LOG(5,(b->obj_name,"Delay buffer start learning")); 
     415    TRACE__((b->obj_name,"Delay buffer start learning")); 
    251416 
    252417    return PJ_SUCCESS; 
    253418} 
  • 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. */ 
     
    16161627            continue; 
    16171628        } 
    16181629 
    1619         /* Get frame from this port.  
    1620          * For port zero (sound port) and passive ports, get the frame  from  
    1621          * the rx_buffer instead. 
     1630        /* Get frame from this port. 
     1631         * For passive ports, get the frame from the delay_buf. 
     1632         * For other ports, get the frame from the port.  
    16221633         */ 
    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; 
     1634        if (conf_port->delay_buf != NULL) { 
     1635            pj_status_t status; 
     1636         
     1637            status = pjmedia_delay_buf_get(conf_port->delay_buf, 
     1638                                  (pj_int16_t*)frame->buf); 
     1639            if (status != PJ_SUCCESS) 
    16351640                continue; 
    1636             } 
    16371641 
    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  
    16431642        } else { 
    16441643 
    16451644            pj_status_t status; 
     
    18301829 
    18311830 
    18321831/* 
    1833  * Recorder callback. 
     1832 * Recorder (or passive port) callback. 
    18341833 */ 
    18351834static pj_status_t put_frame(pjmedia_port *this_port,  
    18361835                             const pjmedia_frame *frame) 
    18371836{ 
    18381837    pjmedia_conf *conf = (pjmedia_conf*) this_port->port_data.pdata; 
    18391838    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; 
     1839    pj_status_t status; 
    18421840 
    18431841    /* Check for correct size. */ 
    18441842    PJ_ASSERT_RETURN( frame->size == conf->samples_per_frame * 
    18451843                                     conf->bits_per_sample / 8, 
    18461844                      PJMEDIA_ENCSAMPLESPFRAME); 
    18471845 
     1846    /* Check existance of delay_buf instance */ 
     1847    PJ_ASSERT_RETURN( port->delay_buf, PJ_EBUG ); 
     1848 
    18481849    /* Skip if this port is muted/disabled. */ 
    18491850    if (port->rx_setting != PJMEDIA_PORT_ENABLE) { 
    18501851        return PJ_SUCCESS; 
     
    18551856        return PJ_SUCCESS; 
    18561857    } 
    18571858 
     1859    status = pjmedia_delay_buf_put(port->delay_buf, (pj_int16_t*)frame->buf); 
    18581860 
    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; 
     1861    return status; 
    18701862} 
    18711863 
  • 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);