Ticket #438: scomb-dbuf3.patch

File scomb-dbuf3.patch, 23.3 KB (added by bennylp, 16 years ago)

Patch combination of splitcomb patch and delay buffer pause patch. With this patch, the splitcomb still have pause functionality, which we will remove

  • pjmedia/src/pjmedia/delaybuf.c

     
    3838{ 
    3939    STATE_WAITING, 
    4040    STATE_LEARNING, 
     41    STATE_PAUSED, 
    4142    STATE_RUNNING 
    4243}; 
    4344 
     
    6364 */ 
    6465#define SAFE_MARGIN     2 
    6566 
     67/* Delay buf will continuously detect activity of operations. If only one 
     68 * operation is called sequentially (bursting) for more than max_level +  
     69 * IDLE_MARGIN, delay buffer will assume the other operation is idle and  
     70 * delay buffer will automatically change its state to STATE_PAUSED. 
     71 */ 
     72#define IDLE_MARGIN     2 
     73 
    6674/* 
    6775 * Some experimental data (with SAFE_MARGIN=1): 
    6876 * 
     
    97105    unsigned         buf_cnt;           /**< Number of buffered samples      */ 
    98106    unsigned         max_cnt;           /**< Max number of buffered samples  */ 
    99107 
    100     struct { 
    101         unsigned     level;             /**< Burst level storage on learning */ 
    102     } op[2]; 
     108    unsigned         level;             /**< Burst level storage on learning */ 
    103109    enum OP          last_op;           /**< Last op (GET or PUT) of learning*/ 
    104110    unsigned         state_count;       /**< Counter of op cycles of learning*/ 
    105111 
    106112    unsigned         max_level;         /**< Learning result: burst level    */ 
    107113 
    108114    pjmedia_wsola   *wsola;             /**< Drift handler                   */ 
     115     
     116    unsigned         max_burst;         /**< Maximum burst before media flow  
     117                                             is suspended                    */ 
    109118}; 
    110119 
    111120PJ_DEF(pj_status_t) pjmedia_delay_buf_create( pj_pool_t *pool, 
     
    135144    pj_ansi_strncpy(b->obj_name, name, PJ_MAX_OBJ_NAME-1); 
    136145    b->samples_per_frame = samples_per_frame; 
    137146    b->max_frames = max_frames; 
     147    b->max_burst = max_frames + IDLE_MARGIN; 
    138148 
    139149    status = pj_lock_create_recursive_mutex(pool, b->obj_name,  
    140150                                            &b->lock); 
     
    145155                   pj_pool_zalloc(pool, samples_per_frame * max_frames *  
    146156                                  sizeof(pj_int16_t)); 
    147157 
     158    status = pjmedia_wsola_create(pool, clock_rate, samples_per_frame,  
     159                                  PJMEDIA_WSOLA_NO_PLC, &b->wsola); 
     160    if (status != PJ_SUCCESS) 
     161        return status; 
     162 
    148163    if (delay >= 0) { 
     164        /* Fixed delay */ 
    149165        if (delay == 0) 
    150166            delay = 1; 
    151167        b->max_level = delay; 
    152168        b->max_cnt = delay * samples_per_frame; 
    153169        b->state = STATE_RUNNING; 
    154170    } else { 
     171        /* Learning the best delay */ 
    155172        b->max_cnt = max_frames * samples_per_frame; 
    156         b->last_op = OP_UNDEFINED; 
    157173        b->state = STATE_WAITING; 
    158174    } 
     175    b->last_op = OP_UNDEFINED; 
    159176 
    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; 
    164  
    165177    *p_b = b; 
    166178 
    167179    TRACE__((b->obj_name,"Delay buffer created")); 
     
    241253 
    242254        b->buf_cnt -= erase_cnt; 
    243255 
    244         PJ_LOG(5,(b->obj_name,"Successfully shrinking %d samples, " 
     256        PJ_LOG(5,(b->obj_name,"Overflow, %d samples reduced, " 
    245257                  "buf_cnt=%d", erase_cnt, b->buf_cnt)); 
    246258    } 
    247259 
     
    280292        return; 
    281293    } 
    282294 
    283     shrink_buffer(b, old_max_cnt - new_max_cnt); 
     295    /* If current samples number is more than new max cnt,  
     296     * we need to shrink buffer first */ 
     297    if (b->buf_cnt > new_max_cnt) 
     298        shrink_buffer(b, b->buf_cnt - new_max_cnt); 
    284299 
    285300    /* Adjust buffer to accomodate the new max_cnt so the samples is secured. 
    286301     * This is done by make get_pos = 0  
     
    320335 
    321336static void update(pjmedia_delay_buf *b, enum OP op) 
    322337{ 
    323     enum OP other = (enum OP) !op; 
     338    switch (b->state) { 
    324339 
    325     switch (b->state) { 
    326340    case STATE_RUNNING: 
     341        if (op != b->last_op) { 
     342            b->last_op = op; 
     343            b->level = 1; 
     344            break; 
     345        } 
     346        ++b->level; 
     347 
     348        if (b->level > b->max_burst) { 
     349            b->state = STATE_PAUSED; 
     350            pjmedia_delay_buf_reset(b); 
     351            PJ_LOG(5,(b->obj_name, "Delay buffer suspended")); 
     352        } 
     353 
    327354        break; 
     355 
     356    case STATE_PAUSED: 
     357        if (op != b->last_op) { 
     358            b->last_op = op; 
     359            b->level = 1; 
     360            b->state = STATE_RUNNING; 
     361            PJ_LOG(5,(b->obj_name, "Delay buffer resumed")); 
     362        } 
     363        break; 
     364 
    328365    case STATE_WAITING: 
    329         ++b->op[op].level; 
    330         if (b->op[other].level != 0) { 
    331             ++b->state_count; 
    332             if (b->state_count == WAITING_COUNT) { 
     366        if (op != b->last_op) { 
     367            b->last_op = op; 
     368            if (++b->state_count == WAITING_COUNT) { 
    333369                /* Start learning */ 
    334370                pjmedia_delay_buf_learn(b); 
     371                break; 
    335372            } 
    336373        } 
    337         b->last_op = op; 
    338374        break; 
     375 
    339376    case STATE_LEARNING: 
    340         ++b->op[op].level; 
    341         if (b->last_op == other) { 
    342             unsigned last_level = b->op[other].level; 
    343             if (last_level > b->max_level) 
    344                 b->max_level = last_level; 
    345             b->op[other].level = 0; 
    346             b->state_count++; 
    347             if (b->state_count == LEARN_COUNT) { 
     377        if (op != b->last_op) { 
     378            b->last_op = op; 
     379            if (b->level > b->max_level) 
     380                b->max_level = b->level; 
     381            b->level = 1; 
     382 
     383            if (++b->state_count == LEARN_COUNT) { 
    348384                /* give SAFE_MARGIN compensation for added stability */ 
    349385                b->max_level += SAFE_MARGIN; 
     386                b->max_burst = b->max_level + IDLE_MARGIN; 
    350387                 
    351388                /* buffer not enough! */ 
    352389                if (b->max_level > b->max_frames) { 
     
    366403                PJ_LOG(4,(b->obj_name,"Delay buffer start running, level=%u", 
    367404                          b->max_level)); 
    368405            } 
     406         
     407            break; 
    369408        } 
    370         b->last_op = op; 
     409 
     410        ++b->level; 
    371411        break; 
    372412    } 
    373413 
     
    391431        return status; 
    392432    } 
    393433 
     434    if (b->state == STATE_PAUSED) { 
     435        pj_lock_release(b->lock); 
     436        return PJ_SUCCESS; 
     437    } 
     438 
    394439    /* Overflow checking */ 
    395440    if (b->buf_cnt + b->samples_per_frame > b->max_cnt) 
    396441    { 
     
    434479 
    435480    update(b, OP_GET); 
    436481 
     482    if (b->state == STATE_PAUSED) { 
     483        pjmedia_zero_samples(frame, b->samples_per_frame); 
     484        pj_lock_release(b->lock); 
     485        return PJ_SUCCESS; 
     486    } 
     487 
    437488    /* Starvation checking */ 
    438489    if (b->buf_cnt < b->samples_per_frame) { 
    439490 
     
    504555    pj_lock_acquire(b->lock); 
    505556 
    506557    b->last_op = OP_UNDEFINED; 
    507     b->op[OP_GET].level = b->op[OP_PUT].level = 0; 
     558    b->level = 1; 
    508559    b->state = STATE_LEARNING; 
    509560    b->state_count = 0; 
    510     b->max_level = 0; 
     561    b->max_level = 1; 
    511562    b->max_cnt = b->max_frames * b->samples_per_frame; 
    512563 
    513564    pjmedia_delay_buf_reset(b); 
     
    532583 
    533584    pj_lock_release(b->lock); 
    534585 
    535     PJ_LOG(5,(b->obj_name,"Delay buffer resetted")); 
     586    PJ_LOG(5,(b->obj_name,"Delay buffer is reset")); 
    536587 
    537588    return PJ_SUCCESS; 
    538589} 
  • pjmedia/src/pjmedia/splitcomb.c

     
    1717 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
    1818 */ 
    1919#include <pjmedia/splitcomb.h> 
     20#include <pjmedia/delaybuf.h> 
    2021#include <pjmedia/errno.h> 
    2122#include <pj/assert.h> 
    2223#include <pj/log.h> 
     
    2829#define THIS_FILE           "splitcomb.c" 
    2930#define TMP_SAMP_TYPE       pj_int16_t 
    3031 
    31 /* When delay buffer is used, we only need 1 frame buffering */ 
    32 #if defined(PJMEDIA_SOUND_USE_DELAYBUF) && PJMEDIA_SOUND_USE_DELAYBUF!=0 
    33 #   define MAX_BUF_CNT      1 
    34 #else 
    35 #   define MAX_BUF_CNT      PJMEDIA_SOUND_BUFFER_COUNT 
    36 #endif 
     32/* Maximum number of channels. */ 
     33#define MAX_CHANNELS        16 
    3734 
     35#define MAX_BUF_CNT         PJMEDIA_SOUND_BUFFER_COUNT 
     36 
     37/* Operations */ 
     38#define OP_PUT              (1) 
     39#define OP_GET              (-1) 
     40 
     41/* Media flow directions */ 
     42enum sc_dir 
     43{ 
     44    /* This is the direction from the splitcomb to the downstream 
     45     * port(s), or when put_frame() is called to the splitcomb. 
     46     */ 
     47    DIR_DOWNSTREAM, 
     48 
     49    /* This is the direction from the downstream port to the splitcomb, 
     50     * or when get_frame() is called to the splitcomb. 
     51     */ 
     52    DIR_UPSTREAM 
     53}; 
     54 
     55 
     56 
    3857#if 0 
    3958#   define TRACE_UP_(x) PJ_LOG(5,x) 
    4059#   define TRACE_DN_(x) PJ_LOG(5,x) 
     
    4362#   define TRACE_DN_(x) 
    4463#endif 
    4564 
    46 #if 1 
    47 #   define LOG_UP_(x)   PJ_LOG(5,x) 
    48 #   define LOG_DN_(x)   PJ_LOG(5,x) 
    49 #else 
    50 #   define LOG_UP_(x) 
    51 #   define LOG_DN_(x) 
    52 #endif 
    5365 
    5466/* 
    5567 * This structure describes the splitter/combiner. 
     
    6476    struct { 
    6577        pjmedia_port *port; 
    6678        pj_bool_t     reversed; 
    67     } port_desc[64]; 
     79    } port_desc[MAX_CHANNELS]; 
    6880 
    6981    /* Temporary buffers needed to extract mono frame from 
    7082     * multichannel frame. We could use stack for this, but this 
     
    8496    struct splitcomb*parent; 
    8597    unsigned         ch_num; 
    8698 
     99    /* Maximum burst before media flow is suspended */ 
     100    int              max_burst; 
     101 
    87102    /* A reverse port need a temporary buffer to store frame 
    88103     * (because of the different phase, see splitcomb.h for details).  
    89104     * Since we can not expect get_frame() and put_frame() to be 
    90      * called evenly one after another, we use circular buffers to 
    91      * accomodate the "jitter". 
     105     * called evenly one after another, we use delay buffers to 
     106     * accomodate the burst. 
     107     * 
     108     * We maintain state for each direction, hence the array. The 
     109     * array is indexed by direction (sc_dir). 
    92110     */ 
    93     unsigned         buf_cnt; 
     111    struct { 
    94112 
    95     /* Downstream is the direction when get_frame() is called to the 
    96      * splitter/combiner port. 
    97      */ 
    98     unsigned         dn_read_pos, dn_write_pos,  
    99                      dn_overflow_pos, dn_underflow_pos; 
    100     pj_int16_t      *dnstream_buf[MAX_BUF_CNT]; 
     113        /* The delay buffer where frames will be stored */ 
     114        pjmedia_delay_buf   *dbuf; 
    101115 
    102     /* Upstream is the direction when put_frame() is called to the 
    103      * splitter/combiner port. 
     116        /* Flag to indicate that audio flow on this direction 
     117         * is currently being suspended (perhaps because nothing 
     118         * is processing the frame on the other end). 
     119         */ 
     120        pj_bool_t       paused; 
     121 
     122        /* Operation level. When the level exceeds a maximum value, 
     123         * the media flow on this direction will be paused. 
     124         */ 
     125        int             level; 
     126 
     127        /* Timestamp. */ 
     128        pj_timestamp    ts; 
     129 
     130    } buf[2]; 
     131 
     132    /* Must have temporary put buffer for the delay buf, 
     133     * unfortunately. 
    104134     */ 
    105     unsigned         up_read_pos, up_write_pos,  
    106                      up_overflow_pos, up_underflow_pos; 
    107     pj_int16_t      *upstream_buf[MAX_BUF_CNT]; 
     135    pj_int16_t        *tmp_up_buf; 
    108136}; 
    109137 
    110138 
     
    228256                                      unsigned options, 
    229257                                      pjmedia_port **p_chport) 
    230258{ 
    231     const pj_str_t name = pj_str("splitcomb-ch"); 
     259    const pj_str_t name = pj_str("scomb-rev"); 
    232260    struct splitcomb *sc = (struct splitcomb*) splitcomb; 
    233261    struct reverse_port *rport; 
    234     unsigned i; 
     262    unsigned buf_cnt; 
    235263    pjmedia_port *port; 
     264    pj_status_t status; 
    236265 
    237266    /* Sanity check */ 
    238267    PJ_ASSERT_RETURN(pool && splitcomb, PJ_EINVAL); 
     
    265294    port->on_destroy = &rport_on_destroy; 
    266295 
    267296 
    268     rport->buf_cnt = options & 0xFF; 
    269     if (rport->buf_cnt == 0) 
    270         rport->buf_cnt = MAX_BUF_CNT; 
     297    buf_cnt = options & 0xFF; 
     298    if (buf_cnt == 0) 
     299        buf_cnt = MAX_BUF_CNT; 
    271300 
    272     /* Create put buffers */ 
    273     for (i=0; i<rport->buf_cnt; ++i) { 
    274         rport->dnstream_buf[i]=(pj_int16_t*) 
    275                                pj_pool_zalloc(pool, port->info.bytes_per_frame); 
    276         PJ_ASSERT_RETURN(rport->dnstream_buf[i], PJ_ENOMEM); 
     301    rport->max_burst = buf_cnt + 4; 
     302 
     303    /* Create downstream/put buffers */ 
     304    status = pjmedia_delay_buf_create(pool, "scomb-down", 
     305                                      port->info.clock_rate, 
     306                                      port->info.samples_per_frame, 
     307                                      buf_cnt, -1, 0, 
     308                                      &rport->buf[DIR_DOWNSTREAM].dbuf); 
     309    if (status != PJ_SUCCESS) { 
     310        return status; 
    277311    } 
    278     rport->dn_write_pos = rport->buf_cnt/2; 
    279312 
    280     /* Create get buffers */ 
    281     for (i=0; i<rport->buf_cnt; ++i) { 
    282         rport->upstream_buf[i] = (pj_int16_t*) 
    283                                  pj_pool_zalloc(pool,  
    284                                                 port->info.bytes_per_frame); 
    285         PJ_ASSERT_RETURN(rport->upstream_buf[i], PJ_ENOMEM); 
     313    /* Create upstream/get buffers */ 
     314    status = pjmedia_delay_buf_create(pool, "scomb-up", 
     315                                      port->info.clock_rate, 
     316                                      port->info.samples_per_frame, 
     317                                      buf_cnt, -1, 0, 
     318                                      &rport->buf[DIR_UPSTREAM].dbuf); 
     319    if (status != PJ_SUCCESS) { 
     320        pjmedia_delay_buf_destroy(rport->buf[DIR_DOWNSTREAM].dbuf); 
     321        return status; 
    286322    } 
    287     rport->up_write_pos = rport->buf_cnt/2; 
    288323 
     324    /* And temporary upstream/get buffer */ 
     325    rport->tmp_up_buf = (pj_int16_t*) 
     326                        pj_pool_alloc(pool, port->info.bytes_per_frame); 
    289327 
    290328    /* Save port in the splitcomb */ 
    291329    sc->port_desc[ch_num].port = &rport->base; 
     
    294332 
    295333    /* Done */ 
    296334    *p_chport = port; 
    297     return PJ_SUCCESS; 
     335    return status; 
    298336} 
    299337 
    300338 
     
    335373    } 
    336374} 
    337375 
     376/* Update operation on the specified direction  */ 
     377static void op_update(struct reverse_port *rport, int dir, int op) 
     378{ 
     379    char *dir_name[2] = {"downstream", "upstream"}; 
    338380 
     381    rport->buf[dir].level += op; 
     382 
     383    if (op == OP_PUT) { 
     384        rport->buf[dir].ts.u64 += rport->base.info.samples_per_frame; 
     385    } 
     386 
     387    if (rport->buf[dir].paused) { 
     388        if (rport->buf[dir].level < -rport->max_burst) { 
     389            rport->buf[dir].level = -rport->max_burst; 
     390        } else if (rport->buf[dir].level > rport->max_burst) { 
     391            rport->buf[dir].level = rport->max_burst; 
     392        } else { 
     393            /* Level has fallen below max level, we can resume 
     394             * media flow. 
     395             */ 
     396            PJ_LOG(5,(rport->base.info.name.ptr,  
     397                      "Resuming media flow on %s direction", dir_name[dir])); 
     398            rport->buf[dir].level = 0; 
     399            pjmedia_delay_buf_learn(rport->buf[dir].dbuf); 
     400            rport->buf[dir].paused = PJ_FALSE; 
     401        } 
     402    } else { 
     403        if (rport->buf[dir].level >= rport->max_burst || 
     404            rport->buf[dir].level <= -rport->max_burst)  
     405        { 
     406            /* Level has reached maximum level, the other side of 
     407             * rport is not sending/retrieving frames. Pause the 
     408             * rport on this direction. 
     409             */ 
     410            PJ_LOG(5,(rport->base.info.name.ptr,  
     411                      "Pausing media flow on %s direction", dir_name[dir])); 
     412            rport->buf[dir].paused = PJ_TRUE; 
     413        } 
     414    } 
     415} 
     416 
     417 
    339418/* 
    340419 * "Write" a multichannel frame. This would split the multichannel frame 
    341420 * into individual mono channel, and write it to the appropriate port. 
     
    373452        if (!port) 
    374453            continue; 
    375454 
     455        /* Extract the mono frame to temporary buffer */ 
     456        extract_mono_frame((const pj_int16_t*)frame->buf, sc->put_buf, ch,  
     457                           this_port->info.channel_count,  
     458                           frame->size * 8 /  
     459                             this_port->info.bits_per_sample / 
     460                             this_port->info.channel_count); 
     461 
    376462        if (!sc->port_desc[ch].reversed) { 
    377463            /* Write to normal port */ 
    378464            pjmedia_frame mono_frame; 
    379465 
    380             /* Extract the mono frame */ 
    381             extract_mono_frame((const pj_int16_t*)frame->buf, sc->put_buf, ch,  
    382                                this_port->info.channel_count,  
    383                                frame->size * 8 /  
    384                                  this_port->info.bits_per_sample / 
    385                                  this_port->info.channel_count); 
    386  
    387466            mono_frame.buf = sc->put_buf; 
    388467            mono_frame.size = frame->size / this_port->info.channel_count; 
    389468            mono_frame.type = frame->type; 
     
    395474        } else { 
    396475            /* Write to reversed phase port */ 
    397476            struct reverse_port *rport = (struct reverse_port*)port; 
    398              
    399             if (rport->dn_write_pos == rport->dn_read_pos) { 
    400477 
    401                 /* Only report overflow if the frame is constantly read 
    402                  * by the 'consumer' of the reverse port. 
    403                  * It is possible that nobody reads the buffer, so causing 
    404                  * overflow to happen rapidly, and writing log message this 
    405                  * way does not seem to be wise. 
    406                  */ 
    407                 if (rport->dn_read_pos != rport->dn_overflow_pos) { 
    408                     rport->dn_overflow_pos = rport->dn_read_pos; 
    409                     LOG_DN_((THIS_FILE, "Overflow in downstream direction")); 
    410                 } 
     478            /* Update rport state. */ 
     479            op_update(rport, DIR_DOWNSTREAM, OP_PUT); 
    411480 
    412                 /* Adjust write position */ 
    413                 rport->dn_write_pos =  
    414                     (rport->dn_write_pos + rport->buf_cnt/2) %  
    415                     rport->buf_cnt; 
     481            if (!rport->buf[DIR_DOWNSTREAM].paused) { 
     482                pjmedia_delay_buf_put(rport->buf[DIR_DOWNSTREAM].dbuf,  
     483                                      sc->put_buf); 
    416484            } 
    417  
    418             /* Extract mono-frame and put it in downstream buffer */ 
    419             extract_mono_frame((const pj_int16_t*)frame->buf,  
    420                                rport->dnstream_buf[rport->dn_write_pos], 
    421                                ch, this_port->info.channel_count,  
    422                                frame->size * 8 /  
    423                                  this_port->info.bits_per_sample / 
    424                                  this_port->info.channel_count); 
    425  
    426             rport->dn_write_pos = (rport->dn_write_pos + 1) % 
    427                                    rport->buf_cnt; 
    428485        } 
    429486    } 
    430487 
     
    444501    unsigned ch; 
    445502    pj_bool_t has_frame = PJ_FALSE; 
    446503 
    447     /* Clear output frame */ 
    448     pjmedia_zero_samples((pj_int16_t*)frame->buf,  
    449                          this_port->info.samples_per_frame); 
    450  
    451504    /* Read frame from each port */ 
    452505    for (ch=0; ch < this_port->info.channel_count; ++ch) { 
    453506        pjmedia_port *port = sc->port_desc[ch].port; 
    454507        pjmedia_frame mono_frame; 
    455508        pj_status_t status; 
    456509 
    457         if (!port) 
    458             continue; 
     510        if (!port) { 
     511            pjmedia_zero_samples(sc->get_buf,  
     512                                 this_port->info.samples_per_frame / 
     513                                    this_port->info.channel_count); 
    459514 
    460         /* Read from the port */ 
    461         if (sc->port_desc[ch].reversed == PJ_FALSE) { 
     515        } else if (sc->port_desc[ch].reversed == PJ_FALSE) { 
    462516            /* Read from normal port */ 
    463517            mono_frame.buf = sc->get_buf; 
    464518            mono_frame.size = port->info.bytes_per_frame; 
     
    468522            if (status != PJ_SUCCESS ||  
    469523                mono_frame.type != PJMEDIA_FRAME_TYPE_AUDIO) 
    470524            { 
    471                 continue; 
     525                pjmedia_zero_samples(sc->get_buf,  
     526                                     port->info.samples_per_frame); 
    472527            } 
    473528 
    474             /* Combine the mono frame into multichannel frame */ 
    475             store_mono_frame((const pj_int16_t*)mono_frame.buf,  
    476                              (pj_int16_t*)frame->buf, ch, 
    477                              this_port->info.channel_count, 
    478                              mono_frame.size * 8 / 
    479                                 this_port->info.bits_per_sample); 
    480  
    481529            frame->timestamp.u64 = mono_frame.timestamp.u64; 
    482530 
    483531        } else { 
    484532            /* Read from temporary buffer for reverse port */ 
    485533            struct reverse_port *rport = (struct reverse_port*)port; 
    486534 
    487             /* Check for underflows */ 
    488             if (rport->up_read_pos == rport->up_write_pos) { 
     535            /* Update rport state. */ 
     536            op_update(rport, DIR_UPSTREAM, OP_GET); 
    489537 
    490                 /* Only report underflow if the buffer is constantly filled 
    491                  * up at the other side. 
    492                  * It is possible that nobody writes the buffer, so causing 
    493                  * underflow to happen rapidly, and writing log message this 
    494                  * way does not seem to be wise. 
    495                  */ 
    496                 if (rport->up_write_pos != rport->up_underflow_pos) { 
    497                     rport->up_underflow_pos = rport->up_write_pos; 
    498                     LOG_UP_((THIS_FILE, "Underflow in upstream direction")); 
    499                 } 
     538            if (!rport->buf[DIR_UPSTREAM].paused) { 
     539                pjmedia_delay_buf_get(rport->buf[DIR_UPSTREAM].dbuf,  
     540                                      sc->get_buf); 
    500541 
    501                 /* Adjust read position */ 
    502                 rport->up_read_pos =  
    503                     (rport->up_write_pos - rport->buf_cnt/2) % 
    504                     rport->buf_cnt; 
     542            } else { 
     543                pjmedia_zero_samples(sc->get_buf,  
     544                                      rport->base.info.samples_per_frame); 
    505545            } 
    506546 
    507             TRACE_UP_((THIS_FILE, "Upstream read at buffer pos %d",  
    508                        rport->up_read_pos)); 
     547            frame->timestamp.u64 = rport->buf[DIR_UPSTREAM].ts.u64; 
     548        } 
    509549 
    510             /* Combine the mono frame into multichannel frame */ 
    511             store_mono_frame((const pj_int16_t*)rport->upstream_buf[rport->up_read_pos],  
    512                              (pj_int16_t*)frame->buf, ch, 
    513                              this_port->info.channel_count, 
    514                              port->info.samples_per_frame); 
     550        /* Combine the mono frame into multichannel frame */ 
     551        store_mono_frame(sc->get_buf,  
     552                         (pj_int16_t*)frame->buf, ch, 
     553                         this_port->info.channel_count, 
     554                         this_port->info.samples_per_frame); 
    515555 
    516             rport->up_read_pos = (rport->up_read_pos + 1) % 
    517                                    rport->buf_cnt; 
    518         } 
    519556 
    520557 
    521558        has_frame = PJ_TRUE; 
     
    548585                                   const pjmedia_frame *frame) 
    549586{ 
    550587    struct reverse_port *rport = (struct reverse_port*) this_port; 
    551     unsigned count; 
    552588 
    553589    pj_assert(frame->size <= rport->base.info.bytes_per_frame); 
    554590 
    555     /* Check for overflows */ 
    556     if (rport->up_write_pos == rport->up_read_pos) { 
    557  
    558         /* Only report overflow if the frame is constantly read 
    559          * at the other end of the buffer (the multichannel side). 
    560          * It is possible that nobody reads the buffer, so causing 
    561          * overflow to happen rapidly, and writing log message this 
    562          * way does not seem to be wise. 
    563          */ 
    564         if (rport->up_read_pos != rport->up_overflow_pos) { 
    565             rport->up_overflow_pos = rport->up_read_pos; 
    566             LOG_UP_((THIS_FILE, "Overflow in upstream direction")); 
    567         } 
    568  
    569         /* Adjust the write position */ 
    570         rport->up_write_pos = (rport->up_read_pos + rport->buf_cnt/2) % 
    571                                rport->buf_cnt; 
    572     } 
    573  
    574591    /* Handle NULL frame */ 
    575592    if (frame->type != PJMEDIA_FRAME_TYPE_AUDIO) { 
    576593        TRACE_UP_((THIS_FILE, "Upstream write %d null samples at buf pos %d", 
    577594                   this_port->info.samples_per_frame, rport->up_write_pos)); 
    578         pjmedia_zero_samples(rport->upstream_buf[rport->up_write_pos], 
    579                              this_port->info.samples_per_frame); 
    580         rport->up_write_pos = (rport->up_write_pos+1) % rport->buf_cnt; 
     595        /* Should write zero frame to delaybuf? */ 
    581596        return PJ_SUCCESS; 
    582597    } 
    583598 
     
    585600    PJ_ASSERT_RETURN(frame->size == this_port->info.bytes_per_frame, 
    586601                     PJ_EINVAL); 
    587602 
    588     /* Copy normal frame to curcular buffer */ 
    589     count = frame->size * 8 / this_port->info.bits_per_sample; 
     603    /* Update rport state. */ 
     604    op_update(rport, DIR_UPSTREAM, OP_PUT); 
    590605 
    591     TRACE_UP_((THIS_FILE, "Upstream write %d samples at buf pos %d", 
    592                count, rport->up_write_pos)); 
     606    /* Discard frame if rport is paused on this direction */ 
     607    if (rport->buf[DIR_UPSTREAM].paused) 
     608        return PJ_SUCCESS; 
    593609 
     610    /* Unfortunately must copy to temporary buffer since delay buf 
     611     * modifies the frame content. 
     612     */ 
     613    pjmedia_copy_samples(rport->tmp_up_buf, (const pj_int16_t*)frame->buf, 
     614                         this_port->info.samples_per_frame); 
    594615 
    595     pjmedia_copy_samples(rport->upstream_buf[rport->up_write_pos], 
    596                          (const pj_int16_t*) frame->buf, count); 
    597     rport->up_write_pos = (rport->up_write_pos+1) % rport->buf_cnt; 
    598  
    599     return PJ_SUCCESS; 
     616    /* Put frame to delay buffer */ 
     617    return pjmedia_delay_buf_put(rport->buf[DIR_UPSTREAM].dbuf,  
     618                                 rport->tmp_up_buf); 
    600619} 
    601620 
    602621 
     
    607626                                   pjmedia_frame *frame) 
    608627{ 
    609628    struct reverse_port *rport = (struct reverse_port*) this_port; 
    610     unsigned count; 
    611629 
    612     count = rport->base.info.samples_per_frame; 
     630    /* Update state */ 
     631    op_update(rport, DIR_DOWNSTREAM, OP_GET); 
    613632 
     633    /* Return no frame if media flow on this direction is being 
     634     * paused. 
     635     */ 
     636    if (rport->buf[DIR_DOWNSTREAM].paused) { 
     637        frame->type = PJMEDIA_FRAME_TYPE_NONE; 
     638        return PJ_SUCCESS; 
     639    } 
     640 
     641    /* Get frame from delay buffer */ 
    614642    frame->size = this_port->info.bytes_per_frame; 
    615643    frame->type = PJMEDIA_FRAME_TYPE_AUDIO; 
     644    frame->timestamp.u64 = rport->buf[DIR_DOWNSTREAM].ts.u64; 
    616645 
    617     /* Check for underflows */ 
    618     if (rport->dn_read_pos == rport->dn_write_pos) { 
    619  
    620         /* Only report underflow if the buffer is constantly filled 
    621          * up at the other side. 
    622          * It is possible that nobody writes the buffer, so causing 
    623          * underflow to happen rapidly, and writing log message this 
    624          * way does not seem to be wise. 
    625          */ 
    626         if (rport->dn_write_pos != rport->dn_underflow_pos) { 
    627             rport->dn_underflow_pos = rport->dn_write_pos; 
    628             LOG_DN_((THIS_FILE, "Underflow in downstream direction")); 
    629         } 
    630  
    631         /* Adjust read position */ 
    632         rport->dn_read_pos =  
    633             (rport->dn_write_pos - rport->buf_cnt/2) % rport->buf_cnt; 
    634          
    635     } 
    636  
    637     /* Get the samples from the circular buffer */ 
    638     pjmedia_copy_samples((pj_int16_t*)frame->buf,  
    639                          rport->dnstream_buf[rport->dn_read_pos], 
    640                          count); 
    641     rport->dn_read_pos = (rport->dn_read_pos+1) % rport->buf_cnt; 
    642  
    643     return PJ_SUCCESS; 
     646    return pjmedia_delay_buf_get(rport->buf[DIR_DOWNSTREAM].dbuf,  
     647                                 (short*)frame->buf); 
    644648} 
    645649 
    646650 
    647651static pj_status_t rport_on_destroy(pjmedia_port *this_port) 
    648652{ 
    649     /* Nothing to do */ 
    650     PJ_UNUSED_ARG(this_port); 
     653    struct reverse_port *rport = (struct reverse_port*) this_port; 
    651654 
     655    pjmedia_delay_buf_destroy(rport->buf[DIR_DOWNSTREAM].dbuf); 
     656    pjmedia_delay_buf_destroy(rport->buf[DIR_UPSTREAM].dbuf); 
     657 
    652658    return PJ_SUCCESS; 
    653659} 
    654660