Changeset 1840


Ignore:
Timestamp:
Mar 3, 2008 2:20:41 PM (16 years ago)
Author:
bennylp
Message:

Ticket #438: added delaybuf in splitcomb. Please see the checkin comment in ticket #438 for the details

Location:
pjproject/trunk/pjmedia/src/pjmedia
Files:
2 edited

Legend:

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

    r1834 r1840  
    242242        b->buf_cnt -= erase_cnt; 
    243243 
    244         PJ_LOG(5,(b->obj_name,"Successfully shrinking %d samples, " 
     244        PJ_LOG(5,(b->obj_name,"Overflow, %d samples reduced, " 
    245245                  "buf_cnt=%d", erase_cnt, b->buf_cnt)); 
    246246    } 
     
    533533    pj_lock_release(b->lock); 
    534534 
    535     PJ_LOG(5,(b->obj_name,"Delay buffer resetted")); 
     535    PJ_LOG(5,(b->obj_name,"Delay buffer is reset")); 
    536536 
    537537    return PJ_SUCCESS; 
  • pjproject/trunk/pjmedia/src/pjmedia/splitcomb.c

    r1715 r1840  
    1818 */ 
    1919#include <pjmedia/splitcomb.h> 
     20#include <pjmedia/delaybuf.h> 
    2021#include <pjmedia/errno.h> 
    2122#include <pj/assert.h> 
     
    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 
     34 
     35/* Maximum number of buffers to be accommodated by delaybuf */ 
     36#define MAX_BUF_CNT         PJMEDIA_SOUND_BUFFER_COUNT 
     37 
     38/* Maximum number of burst before we pause the media flow */ 
     39#define MAX_BURST           (buf_cnt + 6) 
     40 
     41/* Maximum number of NULL frames received before we pause the 
     42 * media flow. 
     43 */ 
     44#define MAX_NULL_FRAMES     (rport->max_burst) 
     45 
     46 
     47/* Operations */ 
     48#define OP_PUT              (1) 
     49#define OP_GET              (-1) 
     50 
     51/* Media flow directions */ 
     52enum sc_dir 
     53{ 
     54    /* This is the direction from the splitcomb to the downstream 
     55     * port(s), or when put_frame() is called to the splitcomb. 
     56     */ 
     57    DIR_DOWNSTREAM, 
     58 
     59    /* This is the direction from the downstream port to the splitcomb, 
     60     * or when get_frame() is called to the splitcomb. 
     61     */ 
     62    DIR_UPSTREAM 
     63}; 
     64 
     65 
    3766 
    3867#if 0 
     
    4473#endif 
    4574 
    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 
    5375 
    5476/* 
     
    6587        pjmedia_port *port; 
    6688        pj_bool_t     reversed; 
    67     } port_desc[64]; 
     89    } port_desc[MAX_CHANNELS]; 
    6890 
    6991    /* Temporary buffers needed to extract mono frame from 
     
    85107    unsigned         ch_num; 
    86108 
     109    /* Maximum burst before media flow is suspended */ 
     110    int              max_burst; 
     111 
     112    /* Maximum NULL frames received before media flow is suspended. */ 
     113    unsigned         max_null_frames; 
     114 
    87115    /* A reverse port need a temporary buffer to store frame 
    88116     * (because of the different phase, see splitcomb.h for details).  
    89117     * 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". 
    92      */ 
    93     unsigned         buf_cnt; 
    94  
    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]; 
    101  
    102     /* Upstream is the direction when put_frame() is called to the 
    103      * splitter/combiner port. 
    104      */ 
    105     unsigned         up_read_pos, up_write_pos,  
    106                      up_overflow_pos, up_underflow_pos; 
    107     pj_int16_t      *upstream_buf[MAX_BUF_CNT]; 
     118     * called evenly one after another, we use delay buffers to 
     119     * accomodate the burst. 
     120     * 
     121     * We maintain state for each direction, hence the array. The 
     122     * array is indexed by direction (sc_dir). 
     123     */ 
     124    struct { 
     125 
     126        /* The delay buffer where frames will be stored */ 
     127        pjmedia_delay_buf   *dbuf; 
     128 
     129        /* Flag to indicate that audio flow on this direction 
     130         * is currently being suspended (perhaps because nothing 
     131         * is processing the frame on the other end). 
     132         */ 
     133        pj_bool_t       paused; 
     134 
     135        /* Operation level. When the level exceeds a maximum value, 
     136         * the media flow on this direction will be paused. 
     137         */ 
     138        int             level; 
     139 
     140        /* Timestamp. */ 
     141        pj_timestamp    ts; 
     142 
     143        /* Number of NULL frames transmitted to this port so far. 
     144         * NULL frame indicate that nothing is transmitted, and  
     145         * once we get too many of this, we should pause the media 
     146         * flow to reduce processing. 
     147         */ 
     148        unsigned        null_cnt; 
     149 
     150    } buf[2]; 
     151 
     152    /* Must have temporary put buffer for the delay buf, 
     153     * unfortunately. 
     154     */ 
     155    pj_int16_t        *tmp_up_buf; 
    108156}; 
    109157 
     
    229277                                      pjmedia_port **p_chport) 
    230278{ 
    231     const pj_str_t name = pj_str("splitcomb-ch"); 
     279    const pj_str_t name = pj_str("scomb-rev"); 
    232280    struct splitcomb *sc = (struct splitcomb*) splitcomb; 
    233281    struct reverse_port *rport; 
    234     unsigned i; 
     282    unsigned buf_cnt; 
    235283    pjmedia_port *port; 
     284    pj_status_t status; 
    236285 
    237286    /* Sanity check */ 
     
    266315 
    267316 
    268     rport->buf_cnt = options & 0xFF; 
    269     if (rport->buf_cnt == 0) 
    270         rport->buf_cnt = MAX_BUF_CNT; 
    271  
    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); 
    277     } 
    278     rport->dn_write_pos = rport->buf_cnt/2; 
    279  
    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); 
    286     } 
    287     rport->up_write_pos = rport->buf_cnt/2; 
    288  
     317    buf_cnt = options & 0xFF; 
     318    if (buf_cnt == 0) 
     319        buf_cnt = MAX_BUF_CNT; 
     320 
     321    rport->max_burst = MAX_BURST; 
     322    rport->max_null_frames = MAX_NULL_FRAMES; 
     323 
     324    /* Create downstream/put buffers */ 
     325    status = pjmedia_delay_buf_create(pool, "scomb-down", 
     326                                      port->info.clock_rate, 
     327                                      port->info.samples_per_frame, 
     328                                      buf_cnt, -1, 0, 
     329                                      &rport->buf[DIR_DOWNSTREAM].dbuf); 
     330    if (status != PJ_SUCCESS) { 
     331        return status; 
     332    } 
     333 
     334    /* Create upstream/get buffers */ 
     335    status = pjmedia_delay_buf_create(pool, "scomb-up", 
     336                                      port->info.clock_rate, 
     337                                      port->info.samples_per_frame, 
     338                                      buf_cnt, -1, 0, 
     339                                      &rport->buf[DIR_UPSTREAM].dbuf); 
     340    if (status != PJ_SUCCESS) { 
     341        pjmedia_delay_buf_destroy(rport->buf[DIR_DOWNSTREAM].dbuf); 
     342        return status; 
     343    } 
     344 
     345    /* And temporary upstream/get buffer */ 
     346    rport->tmp_up_buf = (pj_int16_t*) 
     347                        pj_pool_alloc(pool, port->info.bytes_per_frame); 
    289348 
    290349    /* Save port in the splitcomb */ 
     
    295354    /* Done */ 
    296355    *p_chport = port; 
    297     return PJ_SUCCESS; 
     356    return status; 
    298357} 
    299358 
     
    336395} 
    337396 
     397/* Update operation on the specified direction  */ 
     398static void op_update(struct reverse_port *rport, int dir, int op) 
     399{ 
     400    char *dir_name[2] = {"downstream", "upstream"}; 
     401 
     402    rport->buf[dir].level += op; 
     403 
     404    if (op == OP_PUT) { 
     405        rport->buf[dir].ts.u64 += rport->base.info.samples_per_frame; 
     406    } 
     407 
     408    if (rport->buf[dir].paused) { 
     409        if (rport->buf[dir].level < -rport->max_burst) { 
     410            /* Prevent the level from overflowing and resets back to zero */ 
     411            rport->buf[dir].level = -rport->max_burst; 
     412        } else if (rport->buf[dir].level > rport->max_burst) { 
     413            /* Prevent the level from overflowing and resets back to zero */ 
     414            rport->buf[dir].level = rport->max_burst; 
     415        } else { 
     416            /* Level has fallen below max level, we can resume 
     417             * media flow. 
     418             */ 
     419            PJ_LOG(5,(rport->base.info.name.ptr,  
     420                      "Resuming media flow on %s direction (level=%d)",  
     421                      dir_name[dir], rport->buf[dir].level)); 
     422            rport->buf[dir].level = 0; 
     423            rport->buf[dir].paused = PJ_FALSE; 
     424 
     425            //This will cause disruption in audio, and it seems to be 
     426            //working fine without this anyway, so we disable it for now. 
     427            //pjmedia_delay_buf_learn(rport->buf[dir].dbuf); 
     428 
     429        } 
     430    } else { 
     431        if (rport->buf[dir].level >= rport->max_burst || 
     432            rport->buf[dir].level <= -rport->max_burst)  
     433        { 
     434            /* Level has reached maximum level, the other side of 
     435             * rport is not sending/retrieving frames. Pause the 
     436             * rport on this direction. 
     437             */ 
     438            PJ_LOG(5,(rport->base.info.name.ptr,  
     439                      "Pausing media flow on %s direction (level=%d)",  
     440                      dir_name[dir], rport->buf[dir].level)); 
     441            rport->buf[dir].paused = PJ_TRUE; 
     442        } 
     443    } 
     444} 
     445 
    338446 
    339447/* 
     
    354462            if (!port) continue; 
    355463 
    356             pjmedia_port_put_frame(port, frame); 
     464            if (!sc->port_desc[ch].reversed) { 
     465                pjmedia_port_put_frame(port, frame); 
     466            } else { 
     467                struct reverse_port *rport = (struct reverse_port*)port; 
     468 
     469                /* Write zero port to delaybuf so that it doesn't underflow.  
     470                 * If we don't do this, get_frame() on this direction will 
     471                 * cause delaybuf to generate missing frame and the last 
     472                 * frame transmitted to delaybuf will be replayed multiple 
     473                 * times, which doesn't sound good. 
     474                 */ 
     475 
     476                /* Update the number of NULL frames received. Once we have too 
     477                 * many of this, we'll stop calling op_update() to let the 
     478                 * media be suspended. 
     479                 */ 
     480 
     481                if (++rport->buf[DIR_DOWNSTREAM].null_cnt >  
     482                        rport->max_null_frames)  
     483                { 
     484                    /* Prevent the counter from overflowing and resetting 
     485                     * back to zero 
     486                     */ 
     487                    rport->buf[DIR_DOWNSTREAM].null_cnt =  
     488                        rport->max_null_frames + 1; 
     489                    continue; 
     490                } 
     491 
     492                /* Update rport state. */ 
     493                op_update(rport, DIR_DOWNSTREAM, OP_PUT); 
     494 
     495                /* Discard frame if rport is paused on this direction */ 
     496                if (rport->buf[DIR_DOWNSTREAM].paused) 
     497                    continue; 
     498 
     499                /* Generate zero frame. */ 
     500                pjmedia_zero_samples(rport->tmp_up_buf,  
     501                                     this_port->info.samples_per_frame); 
     502 
     503                /* Put frame to delay buffer */ 
     504                pjmedia_delay_buf_put(rport->buf[DIR_DOWNSTREAM].dbuf, 
     505                                      rport->tmp_up_buf); 
     506 
     507            } 
    357508        } 
    358509        return PJ_SUCCESS; 
     
    373524        if (!port) 
    374525            continue; 
     526 
     527        /* Extract the mono frame to temporary buffer */ 
     528        extract_mono_frame((const pj_int16_t*)frame->buf, sc->put_buf, ch,  
     529                           this_port->info.channel_count,  
     530                           frame->size * 8 /  
     531                             this_port->info.bits_per_sample / 
     532                             this_port->info.channel_count); 
    375533 
    376534        if (!sc->port_desc[ch].reversed) { 
    377535            /* Write to normal port */ 
    378536            pjmedia_frame mono_frame; 
    379  
    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); 
    386537 
    387538            mono_frame.buf = sc->put_buf; 
     
    396547            /* Write to reversed phase port */ 
    397548            struct reverse_port *rport = (struct reverse_port*)port; 
    398              
    399             if (rport->dn_write_pos == rport->dn_read_pos) { 
    400  
    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                 } 
    411  
    412                 /* Adjust write position */ 
    413                 rport->dn_write_pos =  
    414                     (rport->dn_write_pos + rport->buf_cnt/2) %  
    415                     rport->buf_cnt; 
     549 
     550            /* Reset NULL frame counter */ 
     551            rport->buf[DIR_DOWNSTREAM].null_cnt = 0; 
     552 
     553            /* Update rport state. */ 
     554            op_update(rport, DIR_DOWNSTREAM, OP_PUT); 
     555 
     556            if (!rport->buf[DIR_DOWNSTREAM].paused) { 
     557                pjmedia_delay_buf_put(rport->buf[DIR_DOWNSTREAM].dbuf,  
     558                                      sc->put_buf); 
    416559            } 
    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; 
    428560        } 
    429561    } 
     
    444576    unsigned ch; 
    445577    pj_bool_t has_frame = PJ_FALSE; 
    446  
    447     /* Clear output frame */ 
    448     pjmedia_zero_samples((pj_int16_t*)frame->buf,  
    449                          this_port->info.samples_per_frame); 
    450578 
    451579    /* Read frame from each port */ 
     
    455583        pj_status_t status; 
    456584 
    457         if (!port) 
    458             continue; 
    459  
    460         /* Read from the port */ 
    461         if (sc->port_desc[ch].reversed == PJ_FALSE) { 
     585        if (!port) { 
     586            pjmedia_zero_samples(sc->get_buf,  
     587                                 this_port->info.samples_per_frame / 
     588                                    this_port->info.channel_count); 
     589 
     590        } else if (sc->port_desc[ch].reversed == PJ_FALSE) { 
    462591            /* Read from normal port */ 
    463592            mono_frame.buf = sc->get_buf; 
     
    469598                mono_frame.type != PJMEDIA_FRAME_TYPE_AUDIO) 
    470599            { 
    471                 continue; 
     600                pjmedia_zero_samples(sc->get_buf,  
     601                                     port->info.samples_per_frame); 
    472602            } 
    473  
    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); 
    480603 
    481604            frame->timestamp.u64 = mono_frame.timestamp.u64; 
     
    485608            struct reverse_port *rport = (struct reverse_port*)port; 
    486609 
    487             /* Check for underflows */ 
    488             if (rport->up_read_pos == rport->up_write_pos) { 
    489  
    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                 } 
    500  
    501                 /* Adjust read position */ 
    502                 rport->up_read_pos =  
    503                     (rport->up_write_pos - rport->buf_cnt/2) % 
    504                     rport->buf_cnt; 
     610            /* Update rport state. */ 
     611            op_update(rport, DIR_UPSTREAM, OP_GET); 
     612 
     613            if (!rport->buf[DIR_UPSTREAM].paused) { 
     614                pjmedia_delay_buf_get(rport->buf[DIR_UPSTREAM].dbuf,  
     615                                      sc->get_buf); 
     616 
     617            } else { 
     618                pjmedia_zero_samples(sc->get_buf,  
     619                                      rport->base.info.samples_per_frame); 
    505620            } 
    506621 
    507             TRACE_UP_((THIS_FILE, "Upstream read at buffer pos %d",  
    508                        rport->up_read_pos)); 
    509  
    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); 
    515  
    516             rport->up_read_pos = (rport->up_read_pos + 1) % 
    517                                    rport->buf_cnt; 
     622            frame->timestamp.u64 = rport->buf[DIR_UPSTREAM].ts.u64; 
    518623        } 
     624 
     625        /* Combine the mono frame into multichannel frame */ 
     626        store_mono_frame(sc->get_buf,  
     627                         (pj_int16_t*)frame->buf, ch, 
     628                         this_port->info.channel_count, 
     629                         this_port->info.samples_per_frame); 
     630 
    519631 
    520632 
     
    549661{ 
    550662    struct reverse_port *rport = (struct reverse_port*) this_port; 
    551     unsigned count; 
    552663 
    553664    pj_assert(frame->size <= rport->base.info.bytes_per_frame); 
    554  
    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     } 
    573665 
    574666    /* Handle NULL frame */ 
     
    576668        TRACE_UP_((THIS_FILE, "Upstream write %d null samples at buf pos %d", 
    577669                   this_port->info.samples_per_frame, rport->up_write_pos)); 
    578         pjmedia_zero_samples(rport->upstream_buf[rport->up_write_pos], 
     670 
     671        /* Write zero port to delaybuf so that it doesn't underflow.  
     672         * If we don't do this, get_frame() on this direction will 
     673         * cause delaybuf to generate missing frame and the last 
     674         * frame transmitted to delaybuf will be replayed multiple 
     675         * times, which doesn't sound good. 
     676         */ 
     677 
     678        /* Update the number of NULL frames received. Once we have too 
     679         * many of this, we'll stop calling op_update() to let the 
     680         * media be suspended. 
     681         */ 
     682        if (++rport->buf[DIR_UPSTREAM].null_cnt > rport->max_null_frames) { 
     683            /* Prevent the counter from overflowing and resetting back  
     684             * to zero 
     685             */ 
     686            rport->buf[DIR_UPSTREAM].null_cnt = rport->max_null_frames + 1; 
     687            return PJ_SUCCESS; 
     688        } 
     689 
     690        /* Update rport state. */ 
     691        op_update(rport, DIR_UPSTREAM, OP_PUT); 
     692 
     693        /* Discard frame if rport is paused on this direction */ 
     694        if (rport->buf[DIR_UPSTREAM].paused) 
     695            return PJ_SUCCESS; 
     696 
     697        /* Generate zero frame. */ 
     698        pjmedia_zero_samples(rport->tmp_up_buf,  
    579699                             this_port->info.samples_per_frame); 
    580         rport->up_write_pos = (rport->up_write_pos+1) % rport->buf_cnt; 
    581         return PJ_SUCCESS; 
     700 
     701        /* Put frame to delay buffer */ 
     702        return pjmedia_delay_buf_put(rport->buf[DIR_UPSTREAM].dbuf,  
     703                                     rport->tmp_up_buf); 
    582704    } 
    583705 
     
    586708                     PJ_EINVAL); 
    587709 
    588     /* Copy normal frame to curcular buffer */ 
    589     count = frame->size * 8 / this_port->info.bits_per_sample; 
    590  
    591     TRACE_UP_((THIS_FILE, "Upstream write %d samples at buf pos %d", 
    592                count, rport->up_write_pos)); 
    593  
    594  
    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; 
     710    /* Reset NULL frame counter */ 
     711    rport->buf[DIR_UPSTREAM].null_cnt = 0; 
     712 
     713    /* Update rport state. */ 
     714    op_update(rport, DIR_UPSTREAM, OP_PUT); 
     715 
     716    /* Discard frame if rport is paused on this direction */ 
     717    if (rport->buf[DIR_UPSTREAM].paused) 
     718        return PJ_SUCCESS; 
     719 
     720    /* Unfortunately must copy to temporary buffer since delay buf 
     721     * modifies the frame content. 
     722     */ 
     723    pjmedia_copy_samples(rport->tmp_up_buf, (const pj_int16_t*)frame->buf, 
     724                         this_port->info.samples_per_frame); 
     725 
     726    /* Put frame to delay buffer */ 
     727    return pjmedia_delay_buf_put(rport->buf[DIR_UPSTREAM].dbuf,  
     728                                 rport->tmp_up_buf); 
    600729} 
    601730 
     
    608737{ 
    609738    struct reverse_port *rport = (struct reverse_port*) this_port; 
    610     unsigned count; 
    611  
    612     count = rport->base.info.samples_per_frame; 
    613  
     739 
     740    /* Update state */ 
     741    op_update(rport, DIR_DOWNSTREAM, OP_GET); 
     742 
     743    /* Return no frame if media flow on this direction is being 
     744     * paused. 
     745     */ 
     746    if (rport->buf[DIR_DOWNSTREAM].paused) { 
     747        frame->type = PJMEDIA_FRAME_TYPE_NONE; 
     748        return PJ_SUCCESS; 
     749    } 
     750 
     751    /* Get frame from delay buffer */ 
    614752    frame->size = this_port->info.bytes_per_frame; 
    615753    frame->type = PJMEDIA_FRAME_TYPE_AUDIO; 
    616  
    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; 
     754    frame->timestamp.u64 = rport->buf[DIR_DOWNSTREAM].ts.u64; 
     755 
     756    return pjmedia_delay_buf_get(rport->buf[DIR_DOWNSTREAM].dbuf,  
     757                                 (short*)frame->buf); 
     758} 
     759 
     760 
     761static pj_status_t rport_on_destroy(pjmedia_port *this_port) 
     762{ 
     763    struct reverse_port *rport = (struct reverse_port*) this_port; 
     764 
     765    pjmedia_delay_buf_destroy(rport->buf[DIR_DOWNSTREAM].dbuf); 
     766    pjmedia_delay_buf_destroy(rport->buf[DIR_UPSTREAM].dbuf); 
    642767 
    643768    return PJ_SUCCESS; 
    644769} 
    645770 
    646  
    647 static pj_status_t rport_on_destroy(pjmedia_port *this_port) 
    648 { 
    649     /* Nothing to do */ 
    650     PJ_UNUSED_ARG(this_port); 
    651  
    652     return PJ_SUCCESS; 
    653 } 
    654  
Note: See TracChangeset for help on using the changeset viewer.