Ignore:
Timestamp:
Mar 4, 2006 2:52:44 PM (18 years ago)
Author:
bennylp
Message:

Major modification in conference bridge to allow ports with different ptime and sampling rate. Also introduced sampling rate converter

File:
1 edited

Legend:

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

    r246 r277  
    1818 */ 
    1919#include <pjmedia/conference.h> 
    20 #include <pjmedia/silencedet.h> 
    21 #include <pjmedia/stream.h> 
    22 #include <pjmedia/sound.h> 
    2320#include <pjmedia/errno.h> 
    2421#include <pjmedia/port.h> 
     22#include <pjmedia/resample.h> 
     23#include <pjmedia/silencedet.h> 
     24#include <pjmedia/sound.h> 
     25#include <pjmedia/stream.h> 
    2526#include <pj/assert.h> 
    2627#include <pj/log.h> 
     
    4041#define RX_BUF_COUNT    8 
    4142 
     43#define BYTES_PER_SAMPLE    2 
     44 
    4245/* 
    4346 * DON'T GET CONFUSED!! 
     
    4851 
    4952 
     53/** 
     54 * This is a port connected to conference bridge. 
     55 */ 
    5056struct conf_port 
    5157{ 
     
    5864    pjmedia_silence_det *vad;           /**< VAD for this port.             */ 
    5965 
    60     /* Tx buffer contains the frame to be "transmitted" to this port 
    61      * (i.e. for put_frame()). 
    62      * We use dual buffer since the port may be accessed by two threads, 
    63      * and we don't want to use mutex for synchronization. 
     66    /* Shortcut for port info. */ 
     67    unsigned             clock_rate;    /**< Port's clock rate.             */ 
     68    unsigned             samples_per_frame; /**< Port's samples per frame.  */ 
     69 
     70    /* Resample, for converting clock rate, if they're different. */ 
     71    pjmedia_resample    *rx_resample; 
     72    pjmedia_resample    *tx_resample; 
     73 
     74    /* RX buffer is temporary buffer to be used when there is mismatch 
     75     * between port's sample rate or ptime with conference's sample rate 
     76     * or ptime. When both sample rate and ptime of the port match the 
     77     * conference settings, this buffer will not be used. 
     78     *  
     79     * This buffer contains samples at port's clock rate. 
     80     * The size of this buffer is the sum between port's samples per frame 
     81     * and bridge's samples per frame. 
    6482     */ 
    65     pj_int16_t          *cur_tx_buf;    /**< Buffer for put_frame().        */ 
    66     pj_int16_t          *tx_buf1;       /**< Buffer 1.                      */ 
    67     pj_int16_t          *tx_buf2;       /**< Buffer 2.                      */ 
    68  
    69     /* Rx buffers is a special buffer for sound device port (port 0).  
    70      * It's not used by other ports. 
    71      */ 
    72     int                  rx_write, rx_read; 
    73     pj_int16_t          *rx_buf[RX_BUF_COUNT];  /**< Buffer                         */ 
    74  
    75  
    76     /* Sum buf is a temporary buffer used to calculate the average signal 
     83    pj_int16_t          *rx_buf;        /**< The RX buffer.                 */ 
     84    unsigned             rx_buf_cap;    /**< Max size, in samples           */ 
     85    unsigned             rx_buf_count;  /**< # of samples in the buf.       */ 
     86 
     87    /* Mix buf is a temporary buffer used to calculate the average signal 
    7788     * received by this port from all other ports. 
     89     * 
     90     * This buffer contains samples at bridge's clock rate. 
     91     * The size of this buffer is equal to samples per frame of the bridge. 
     92     * 
     93     * Note that the samples here are unsigned 32bit. 
    7894     */ 
    7995    unsigned             sources;       /**< Number of sources.             */ 
    80     pj_uint32_t         *sum_buf;       /**< Total sum of signal.           */ 
     96    pj_uint32_t         *mix_buf;       /**< Total sum of signal.           */ 
     97 
     98    /* Tx buffer is a temporary buffer to be used when there's mismatch  
     99     * between port's clock rate or ptime with conference's sample rate 
     100     * or ptime. When both sample rate and ptime of the port match the 
     101     * conference's settings, this buffer will not be used. 
     102     *  
     103     * This buffer contains samples at port's clock rate. 
     104     * The size of this buffer is the sum between port's samples per frame 
     105     * and bridge's samples per frame. 
     106     */ 
     107    pj_int16_t          *tx_buf;        /**< Tx buffer.                     */ 
     108    unsigned             tx_buf_cap;    /**< Max size, in samples.          */ 
     109    unsigned             tx_buf_count;  /**< # of samples in the buffer.    */ 
     110 
     111    /* Snd buffers is a special buffer for sound device port (port 0).  
     112     * It's not used by other ports. 
     113     * 
     114     * There are multiple numbers of this buffer, because we can not expect 
     115     * the mic and speaker thread to run equally after one another. In most 
     116     * systems, each thread will run multiple times before the other thread 
     117     * gains execution time. For example, in my system, mic thread is called 
     118     * three times, then speaker thread is called three times, and so on. 
     119     */ 
     120    int                  snd_write_pos, snd_read_pos; 
     121    pj_int16_t          *snd_buf[RX_BUF_COUNT]; /**< Buffer                 */ 
    81122}; 
    82123 
     
    95136    struct conf_port    **ports;        /**< Array of ports.                */ 
    96137    pj_uint16_t          *uns_buf;      /**< Buf for unsigned conversion    */ 
    97     unsigned              sampling_rate;        /**< Sampling rate.         */ 
     138    unsigned              clock_rate;   /**< Sampling rate.         */ 
    98139    unsigned              samples_per_frame;    /**< Samples per frame.     */ 
    99140    unsigned              bits_per_sample;      /**< Bits per sample.       */ 
    100     pj_snd_stream_info    snd_info; 
     141    pj_snd_stream_info    snd_info;     /**< Sound device parameter.        */ 
    101142}; 
    102143 
     
    120161static pj_status_t create_conf_port( pj_pool_t *pool, 
    121162                                     pjmedia_conf *conf, 
     163                                     pjmedia_port *port, 
    122164                                     const pj_str_t *name, 
    123165                                     struct conf_port **p_conf_port) 
     
    150192    pjmedia_silence_det_set_adaptive(conf_port->vad, conf->samples_per_frame); 
    151193 
    152  
    153     /* Create TX buffers. */ 
    154     conf_port->tx_buf1 = pj_pool_zalloc(pool, conf->samples_per_frame * 
    155                                               sizeof(conf_port->tx_buf1[0])); 
    156     PJ_ASSERT_RETURN(conf_port->tx_buf1, PJ_ENOMEM); 
    157  
    158     conf_port->tx_buf2 = pj_pool_zalloc(pool, conf->samples_per_frame * 
    159                                               sizeof(conf_port->tx_buf2[0])); 
    160     PJ_ASSERT_RETURN(conf_port->tx_buf2, PJ_ENOMEM); 
    161  
    162     /* Set initial TX buffer */ 
    163     conf_port->cur_tx_buf = conf_port->tx_buf1; 
    164  
    165     /* Create temporary buffer to calculate average signal received by 
    166      * this port. 
     194    /* Save some port's infos, for convenience. */ 
     195    if (port) { 
     196        conf_port->port = port; 
     197        conf_port->clock_rate = port->info.sample_rate; 
     198        conf_port->samples_per_frame = port->info.samples_per_frame; 
     199    } else { 
     200        conf_port->port = NULL; 
     201        conf_port->clock_rate = conf->clock_rate; 
     202        conf_port->samples_per_frame = conf->samples_per_frame; 
     203    } 
     204 
     205    /* If port's clock rate is different than conference's clock rate, 
     206     * create a resample sessions. 
    167207     */ 
    168     conf_port->sum_buf = pj_pool_zalloc(pool, conf->samples_per_frame * 
    169                                               sizeof(conf_port->sum_buf[0])); 
    170  
    171      
     208    if (conf_port->clock_rate != conf->clock_rate) { 
     209 
     210        double factor; 
     211 
     212        factor = 1.0 * conf_port->clock_rate / conf->clock_rate; 
     213 
     214        /* Create resample for rx buffer. */ 
     215        status = pjmedia_resample_create( pool,  
     216                                          PJ_TRUE,  /* High quality */ 
     217                                          PJ_TRUE,  /* Large filter */ 
     218                                          conf_port->clock_rate,/* Rate in */ 
     219                                          conf->clock_rate, /* Rate out */ 
     220                                          (unsigned)(conf->samples_per_frame *  
     221                                                     factor), 
     222                                          &conf_port->rx_resample); 
     223        if (status != PJ_SUCCESS) 
     224            return status; 
     225 
     226 
     227        /* Create resample for tx buffer. */ 
     228        status = pjmedia_resample_create(pool, 
     229                                         PJ_TRUE,   /* High quality */ 
     230                                         PJ_TRUE,   /* Large filter */ 
     231                                         conf->clock_rate,  /* Rate in */ 
     232                                         conf_port->clock_rate, /* Rate out */ 
     233                                         conf->samples_per_frame, 
     234                                         &conf_port->tx_resample); 
     235        if (status != PJ_SUCCESS) 
     236            return status; 
     237    } 
     238 
     239    /* 
     240     * Initialize rx and tx buffer, only when port's samples per frame or  
     241     * port's clock rate is different then the conference bridge settings. 
     242     */ 
     243    if (conf_port->clock_rate != conf->clock_rate || 
     244        conf_port->samples_per_frame != conf->samples_per_frame) 
     245    { 
     246        /* Create RX buffer. */ 
     247        conf_port->rx_buf_cap = (unsigned)(conf_port->samples_per_frame + 
     248                                           conf->samples_per_frame *  
     249                                           conf_port->clock_rate * 1.0 / 
     250                                           conf->clock_rate); 
     251        conf_port->rx_buf_count = 0; 
     252        conf_port->rx_buf = pj_pool_alloc(pool, conf_port->rx_buf_cap * 
     253                                                sizeof(conf_port->rx_buf[0])); 
     254        PJ_ASSERT_RETURN(conf_port->rx_buf, PJ_ENOMEM); 
     255 
     256        /* Create TX buffer. */ 
     257        conf_port->tx_buf_cap = conf_port->rx_buf_cap; 
     258        conf_port->tx_buf_count = 0; 
     259        conf_port->tx_buf = pj_pool_alloc(pool, conf_port->tx_buf_cap * 
     260                                                sizeof(conf_port->tx_buf[0])); 
     261        PJ_ASSERT_RETURN(conf_port->tx_buf, PJ_ENOMEM); 
     262    } 
     263 
     264 
     265    /* Create mix buffer. */ 
     266    conf_port->mix_buf = pj_pool_zalloc(pool, conf->samples_per_frame * 
     267                                              sizeof(conf_port->mix_buf[0])); 
     268    PJ_ASSERT_RETURN(conf_port->mix_buf, PJ_ENOMEM); 
     269 
    172270 
    173271    /* Done */ 
     
    190288    /* Init default sound device parameters. */ 
    191289    pj_memset(&conf->snd_info, 0, sizeof(conf->snd_info)); 
    192     conf->snd_info.samples_per_sec = conf->sampling_rate; 
     290    conf->snd_info.samples_per_sec = conf->clock_rate; 
    193291    conf->snd_info.bits_per_sample = conf->bits_per_sample; 
    194292    conf->snd_info.samples_per_frame = conf->samples_per_frame; 
     
    199297 
    200298    /* Create port */ 
    201     status = create_conf_port(pool, conf, &name, &conf_port); 
     299    status = create_conf_port(pool, conf, NULL, &name, &conf_port); 
    202300    if (status != PJ_SUCCESS) 
    203301        goto on_error; 
     
    205303    /* Sound device has rx buffers. */ 
    206304    for (i=0; i<RX_BUF_COUNT; ++i) { 
    207         conf_port->rx_buf[i] = pj_pool_zalloc(pool, conf->samples_per_frame * 
    208                                               sizeof(conf_port->rx_buf[0][0])); 
    209         if (conf_port->rx_buf[i] == NULL) { 
     305        conf_port->snd_buf[i] = pj_pool_zalloc(pool, conf->samples_per_frame * 
     306                                              sizeof(conf_port->snd_buf[0][0])); 
     307        if (conf_port->snd_buf[i] == NULL) { 
    210308            status = PJ_ENOMEM; 
    211309            goto on_error; 
    212310        } 
    213311    } 
    214     conf_port->rx_write = 0; 
    215     conf_port->rx_read = 0; 
     312    conf_port->snd_write_pos = 0; 
     313    conf_port->snd_read_pos = 0; 
    216314 
    217315 
     
    233331PJ_DEF(pj_status_t) pjmedia_conf_create( pj_pool_t *pool, 
    234332                                         unsigned max_ports, 
    235                                          unsigned sampling_rate, 
     333                                         unsigned clock_rate, 
    236334                                         unsigned samples_per_frame, 
    237335                                         unsigned bits_per_sample, 
     
    241339    pj_status_t status; 
    242340 
     341    /* Can only accept 16bits per sample, for now.. */ 
     342    PJ_ASSERT_RETURN(bits_per_sample == 16, PJ_EINVAL); 
     343 
    243344    PJ_LOG(5,(THIS_FILE, "Creating conference bridge with %d ports", 
    244345              max_ports)); 
     
    252353 
    253354    conf->max_ports = max_ports; 
    254     conf->sampling_rate = sampling_rate; 
     355    conf->clock_rate = clock_rate; 
    255356    conf->samples_per_frame = samples_per_frame; 
    256357    conf->bits_per_sample = bits_per_sample; 
     
    403504 
    404505    /* Create port structure. */ 
    405     status = create_conf_port(pool, conf, port_name, &conf_port); 
     506    status = create_conf_port(pool, conf, strm_port, port_name, &conf_port); 
    406507    if (status != PJ_SUCCESS) { 
    407508        pj_mutex_unlock(conf->mutex); 
    408509        return status; 
    409510    } 
    410  
    411     /* Set the port */ 
    412     conf_port->port = strm_port; 
    413511 
    414512    /* Put the port. */ 
     
    635733    info->rx_setting = conf_port->rx_setting; 
    636734    info->listener = conf_port->listeners; 
     735    info->clock_rate = conf_port->clock_rate; 
     736    info->samples_per_frame = conf_port->samples_per_frame; 
    637737 
    638738    return PJ_SUCCESS; 
     
    672772    return (pj_int16_t)(uns - 32767); 
    673773} 
     774 
     775/* Copy samples */ 
     776PJ_INLINE(void) copy_samples(pj_int16_t *dst,  
     777                                const pj_int16_t *src, 
     778                                unsigned count) 
     779{ 
     780    unsigned i; 
     781    for (i=0; i<count; ++i) 
     782        dst[i] = src[i]; 
     783} 
     784 
     785/* Zero samples. */ 
     786PJ_INLINE(void) zero_samples(pj_int16_t *buf, unsigned count) 
     787{ 
     788    unsigned i; 
     789    for (i=0; i<count; ++i) 
     790        buf[i] = 0; 
     791} 
     792 
     793 
     794/* 
     795 * Read from port. 
     796 */ 
     797static pj_status_t read_port( pjmedia_conf *conf, 
     798                              struct conf_port *cport, pj_int16_t *frame, 
     799                              pj_size_t count, pjmedia_frame_type *type ) 
     800{ 
     801 
     802    pj_assert(count == conf->samples_per_frame); 
     803 
     804    /* If port's samples per frame and sampling rate matches conference 
     805     * bridge's settings, get the frame directly from the port. 
     806     */ 
     807    if (cport->rx_buf_cap == 0) { 
     808        pjmedia_frame f; 
     809        pj_status_t status; 
     810 
     811        f.buf = frame; 
     812        f.size = count * BYTES_PER_SAMPLE; 
     813 
     814        status = (cport->port->get_frame)(cport->port, &f); 
     815 
     816        *type = f.type; 
     817 
     818        return status; 
     819 
     820    } else { 
     821 
     822        /* 
     823         * If we don't have enough samples in rx_buf, read from the port  
     824         * first. Remember that rx_buf may be in different clock rate! 
     825         */ 
     826        while (cport->rx_buf_count < count * 1.0 * 
     827                cport->clock_rate / conf->clock_rate) { 
     828 
     829            pjmedia_frame f; 
     830            pj_status_t status; 
     831 
     832            f.buf = cport->rx_buf + cport->rx_buf_count; 
     833            f.size = cport->samples_per_frame * BYTES_PER_SAMPLE; 
     834 
     835            status = pjmedia_port_get_frame(cport->port, &f); 
     836 
     837            if (status != PJ_SUCCESS) { 
     838                /* Fatal error! */ 
     839                return status; 
     840            } 
     841 
     842            if (f.type != PJMEDIA_FRAME_TYPE_AUDIO) { 
     843                zero_samples( cport->rx_buf + cport->rx_buf_count, 
     844                              cport->samples_per_frame); 
     845            } 
     846 
     847            cport->rx_buf_count += cport->samples_per_frame; 
     848 
     849            pj_assert(cport->rx_buf_count <= cport->rx_buf_cap); 
     850        } 
     851 
     852        /* 
     853         * If port's clock_rate is different, resample. 
     854         * Otherwise just copy. 
     855         */ 
     856        if (cport->clock_rate != conf->clock_rate) { 
     857             
     858            unsigned src_count; 
     859 
     860            pjmedia_resample_run( cport->rx_resample,cport->rx_buf, frame); 
     861 
     862            src_count = (unsigned)(count * 1.0 * cport->clock_rate /  
     863                                   conf->clock_rate); 
     864            cport->rx_buf_count -= src_count; 
     865            if (cport->rx_buf_count) { 
     866                copy_samples(cport->rx_buf, cport->rx_buf+src_count, 
     867                             cport->rx_buf_count); 
     868            } 
     869 
     870        } else { 
     871 
     872            copy_samples(frame, cport->rx_buf, count); 
     873            cport->rx_buf_count -= count; 
     874            if (cport->rx_buf_count) { 
     875                copy_samples(cport->rx_buf, cport->rx_buf+count, 
     876                             cport->rx_buf_count); 
     877            } 
     878        } 
     879    } 
     880 
     881    return PJ_SUCCESS; 
     882} 
     883 
     884 
     885/* 
     886 * Write the mixed signal to the port. 
     887 */ 
     888static pj_status_t write_port(pjmedia_conf *conf, struct conf_port *cport, 
     889                              pj_uint32_t timestamp) 
     890{ 
     891    pj_int16_t *buf; 
     892    unsigned j; 
     893 
     894    /* If port is muted or nobody is transmitting to this port,  
     895     * transmit NULL frame.  
     896     */ 
     897    if (cport->tx_setting == PJMEDIA_PORT_MUTE || cport->sources==0) { 
     898 
     899        pjmedia_frame frame; 
     900 
     901        frame.type = PJMEDIA_FRAME_TYPE_NONE; 
     902        frame.buf = NULL; 
     903        frame.size = 0; 
     904 
     905        if (cport->port) 
     906            pjmedia_port_put_frame(cport->port, &frame); 
     907 
     908        return PJ_SUCCESS; 
     909 
     910    } else if (cport->tx_setting != PJMEDIA_PORT_ENABLE) { 
     911        return PJ_SUCCESS; 
     912    } 
     913 
     914    /* If there are sources in the mix buffer, convert the mixed samples 
     915     * to the mixed samples itself. This is possible because mixed sample 
     916     * is 32bit. 
     917     */ 
     918    buf = (pj_int16_t*)cport->mix_buf; 
     919    for (j=0; j<conf->samples_per_frame; ++j) { 
     920        buf[j] = unsigned2pcm(cport->mix_buf[j] / cport->sources); 
     921    } 
     922 
     923    /* If port has the same clock_date and samples_per_frame settings as 
     924     * the conference bridge, transmit the frame as is. 
     925     */ 
     926    if (cport->clock_rate == conf->clock_rate && 
     927        cport->samples_per_frame == conf->samples_per_frame) 
     928    { 
     929        pjmedia_frame frame; 
     930 
     931        frame.type = PJMEDIA_FRAME_TYPE_AUDIO; 
     932        frame.buf = (pj_int16_t*)cport->mix_buf; 
     933        frame.size = conf->samples_per_frame * BYTES_PER_SAMPLE; 
     934        frame.timestamp.u64 = timestamp; 
     935 
     936        if (cport->port != NULL) 
     937            return pjmedia_port_put_frame(cport->port, &frame); 
     938        else 
     939            return PJ_SUCCESS; 
     940    } 
     941 
     942    /* If it has different clock_rate, must resample. */ 
     943    if (cport->clock_rate != conf->clock_rate) { 
     944 
     945        unsigned dst_count; 
     946 
     947        pjmedia_resample_run( cport->tx_resample, buf,  
     948                              cport->tx_buf + cport->tx_buf_count ); 
     949 
     950        dst_count = (unsigned)(conf->samples_per_frame * 1.0 * 
     951                               cport->clock_rate / conf->clock_rate); 
     952        cport->tx_buf_count += dst_count; 
     953 
     954    } else { 
     955        /* Same clock rate. 
     956         * Just copy the samples to tx_buffer. 
     957         */ 
     958        copy_samples( cport->tx_buf + cport->tx_buf_count, 
     959                      buf, conf->samples_per_frame ); 
     960        cport->tx_buf_count += conf->samples_per_frame; 
     961    } 
     962 
     963    /* Transmit once we have enough frame in the tx_buf. */ 
     964    if (cport->tx_buf_count >= cport->samples_per_frame) { 
     965         
     966        pjmedia_frame frame; 
     967 
     968        frame.type = PJMEDIA_FRAME_TYPE_AUDIO; 
     969        frame.buf = cport->tx_buf; 
     970        frame.size = cport->samples_per_frame * BYTES_PER_SAMPLE; 
     971        frame.timestamp.u64 = timestamp; 
     972 
     973        if (cport->port) 
     974            return pjmedia_port_put_frame(cport->port, &frame); 
     975        else 
     976            return PJ_SUCCESS; 
     977    } 
     978 
     979    return PJ_SUCCESS; 
     980} 
     981 
    674982 
    675983/* 
     
    682990{ 
    683991    pjmedia_conf *conf = user_data; 
    684     pj_int16_t *output_buf = output; 
    685992    unsigned ci, cj, i, j; 
    686993     
     
    6951002    for (i=0, ci=0; i<conf->max_ports && ci < conf->port_cnt; ++i) { 
    6961003        struct conf_port *conf_port = conf->ports[i]; 
    697         pj_uint32_t *sum_buf; 
     1004        pj_uint32_t *mix_buf; 
    6981005 
    6991006        /* Skip empty slot. */ 
     
    7041011 
    7051012        conf_port->sources = 0; 
    706         sum_buf = conf_port->sum_buf; 
     1013        mix_buf = conf_port->mix_buf; 
    7071014 
    7081015        for (j=0; j<conf->samples_per_frame; ++j) 
    709             sum_buf[j] = 0; 
     1016            mix_buf[j] = 0; 
    7101017    } 
    7111018 
    7121019    /* Get frames from all ports, and "mix" the signal  
    713      * to sum_buf of all listeners of the port. 
     1020     * to mix_buf of all listeners of the port. 
    7141021     */ 
    7151022    for (i=0, ci=0; i<conf->max_ports && ci<conf->port_cnt; ++i) { 
     
    7331040         */ 
    7341041        if (i==0) { 
    735             pj_int16_t *rx_buf; 
    736  
    737             if (conf_port->rx_read == conf_port->rx_write) { 
    738                 conf_port->rx_read =  
    739                     (conf_port->rx_write+RX_BUF_COUNT-RX_BUF_COUNT/2) %  
     1042            pj_int16_t *snd_buf; 
     1043 
     1044            if (conf_port->snd_read_pos == conf_port->snd_write_pos) { 
     1045                conf_port->snd_read_pos =  
     1046                    (conf_port->snd_write_pos+RX_BUF_COUNT-RX_BUF_COUNT/2) %  
    7401047                        RX_BUF_COUNT; 
    7411048            } 
     
    7521059            } 
    7531060 
    754             rx_buf = conf_port->rx_buf[conf_port->rx_read]; 
     1061            snd_buf = conf_port->snd_buf[conf_port->snd_read_pos]; 
    7551062            for (j=0; j<conf->samples_per_frame; ++j) { 
    756                 ((pj_int16_t*)output)[j] = rx_buf[j]; 
     1063                ((pj_int16_t*)output)[j] = snd_buf[j]; 
    7571064            } 
    758             conf_port->rx_read = (conf_port->rx_read+1) % RX_BUF_COUNT; 
     1065            conf_port->snd_read_pos = (conf_port->snd_read_pos+1) % RX_BUF_COUNT; 
    7591066 
    7601067        } else { 
    761             pjmedia_frame frame; 
    762  
    763             pj_memset(&frame, 0, sizeof(frame)); 
    764             frame.buf = output; 
    765             frame.size = size; 
    766             pjmedia_port_get_frame(conf_port->port, &frame); 
    767  
    768            if (frame.type == PJMEDIA_FRAME_TYPE_NONE) 
     1068 
     1069            pj_status_t status; 
     1070            pjmedia_frame_type frame_type; 
     1071 
     1072            status = read_port(conf, conf_port, output,  
     1073                               conf->samples_per_frame, &frame_type); 
     1074             
     1075            if (status != PJ_SUCCESS) { 
     1076                PJ_LOG(4,(THIS_FILE, "Port %.*s get_frame() returned %d. " 
     1077                                     "Port is now disabled", 
     1078                                     (int)conf_port->name.slen, 
     1079                                     conf_port->name.ptr, 
     1080                                     status)); 
     1081                conf_port->rx_setting = PJMEDIA_PORT_DISABLE; 
    7691082                continue; 
     1083            } 
    7701084        } 
    771  
    772         /* Skip (after receiving the frame) if this port is muted. */ 
    773         if (conf_port->rx_setting == PJMEDIA_PORT_MUTE) 
    774             continue; 
    7751085 
    7761086        /* Also skip if this port doesn't have listeners. */ 
     
    7941104        { 
    7951105            struct conf_port *listener = conf->ports[j]; 
    796             pj_uint32_t *sum_buf; 
     1106            pj_uint32_t *mix_buf; 
    7971107            unsigned k; 
    7981108 
     
    8111121 
    8121122            /* Mix the buffer */ 
    813             sum_buf = listener->sum_buf; 
     1123            mix_buf = listener->mix_buf; 
    8141124            for (k=0; k<conf->samples_per_frame; ++k) 
    815                 sum_buf[k] += (conf->uns_buf[k] * level); 
     1125                mix_buf[k] += (conf->uns_buf[k] * level); 
    8161126 
    8171127            listener->sources += level; 
     
    8221132    for (i=0, ci=0; i<conf->max_ports && ci<conf->port_cnt; ++i) { 
    8231133        struct conf_port *conf_port = conf->ports[i]; 
    824         pjmedia_frame frame; 
    825         pj_int16_t *target_buf; 
     1134        pj_status_t status; 
    8261135 
    8271136        if (!conf_port) 
     
    8301139        ++ci; 
    8311140 
    832         if (conf_port->tx_setting == PJMEDIA_PORT_MUTE) { 
    833             frame.type = PJMEDIA_FRAME_TYPE_NONE; 
    834             frame.buf = NULL; 
    835             frame.size = 0; 
    836  
    837             if (conf_port->port) 
    838                 pjmedia_port_put_frame(conf_port->port, &frame); 
    839  
    840             continue; 
    841  
    842         } else if (conf_port->tx_setting != PJMEDIA_PORT_ENABLE) { 
     1141        status = write_port( conf, conf_port, timestamp); 
     1142        if (status != PJ_SUCCESS) { 
     1143            PJ_LOG(4,(THIS_FILE, "Port %.*s put_frame() returned %d. " 
     1144                                 "Port is now disabled", 
     1145                                 (int)conf_port->name.slen, 
     1146                                 conf_port->name.ptr, 
     1147                                 status)); 
     1148            conf_port->tx_setting = PJMEDIA_PORT_DISABLE; 
    8431149            continue; 
    8441150        } 
    845  
    846         target_buf = (conf_port->cur_tx_buf==conf_port->tx_buf1? 
    847                         conf_port->tx_buf2 : conf_port->tx_buf1); 
    848  
    849         if (conf_port->sources) { 
    850             for (j=0; j<conf->samples_per_frame; ++j) { 
    851                 target_buf[j] = unsigned2pcm(conf_port->sum_buf[j] /  
    852                                              conf_port->sources); 
    853             } 
    854         } 
    855  
    856         /* Switch buffer. */ 
    857         conf_port->cur_tx_buf = target_buf; 
    858  
    859         pj_memset(&frame, 0, sizeof(frame)); 
    860         if (conf_port->sources) { 
    861  
    862             pj_bool_t is_silence = PJ_FALSE; 
    863  
    864             /* Apply silence detection. */ 
    865 #if 0 
    866             is_silence = pjmedia_silence_det_detect(conf_port->vad, 
    867                                                     target_buf, 
    868                                                     conf->samples_per_frame, 
    869                                                     NULL); 
    870 #endif 
    871             frame.type = is_silence ? PJMEDIA_FRAME_TYPE_NONE :  
    872                                       PJMEDIA_FRAME_TYPE_AUDIO; 
    873  
    874         } else 
    875             frame.type = PJMEDIA_FRAME_TYPE_NONE; 
    876  
    877         frame.buf = conf_port->cur_tx_buf; 
    878         frame.size = conf->samples_per_frame * conf->bits_per_sample / 8; 
    879         frame.timestamp.u64 = timestamp; 
    880  
    881         if (conf_port->port) 
    882             pjmedia_port_put_frame(conf_port->port, &frame); 
    883  
    8841151    } 
    8851152 
    8861153    /* Return sound playback frame. */ 
    8871154    if (conf->ports[0]->sources) { 
    888         for (j=0; j<conf->samples_per_frame; ++j) 
    889             output_buf[j] = conf->ports[0]->cur_tx_buf[j]; 
     1155        copy_samples( output, (pj_int16_t*)conf->ports[0]->mix_buf,  
     1156                      conf->samples_per_frame); 
    8901157    } else { 
    891         for (j=0; j<conf->samples_per_frame; ++j) 
    892             output_buf[j] = 0; 
     1158        zero_samples( output, conf->samples_per_frame );  
    8931159    } 
    8941160 
     
    9091175    pjmedia_conf *conf = user_data; 
    9101176    struct conf_port *snd_port = conf->ports[0]; 
    911     pj_int16_t *target_rx_buf; 
     1177    pj_int16_t *target_snd_buf; 
    9121178    unsigned i; 
    9131179 
     
    9321198 
    9331199    /* Determine which rx_buffer to fill in */ 
    934     target_rx_buf = snd_port->rx_buf[snd_port->rx_write]; 
     1200    target_snd_buf = snd_port->snd_buf[snd_port->snd_write_pos]; 
    9351201     
    9361202    /* Copy samples from audio device to target rx_buffer */ 
    9371203    for (i=0; i<conf->samples_per_frame; ++i) { 
    938         target_rx_buf[i] = ((pj_int16_t*)input)[i]; 
     1204        target_snd_buf[i] = ((pj_int16_t*)input)[i]; 
    9391205    } 
    9401206 
    9411207    /* Switch buffer */ 
    942     snd_port->rx_write = (snd_port->rx_write+1)%RX_BUF_COUNT; 
    943  
    944  
    945     /* Time for all ports (except sound port) to transmit frames */ 
    946     /* 
    947     for (i=1; i<conf->max_ports; ++i) { 
    948         struct conf_port *conf_port = conf->ports[i]; 
    949         pjmedia_frame frame; 
    950  
    951         if (!conf_port) 
    952             continue; 
    953  
    954     } 
    955     */ 
    956      
    957     return PJ_SUCCESS; 
    958 } 
    959  
     1208    snd_port->snd_write_pos = (snd_port->snd_write_pos+1)%RX_BUF_COUNT; 
     1209 
     1210 
     1211    return PJ_SUCCESS; 
     1212} 
     1213 
Note: See TracChangeset for help on using the changeset viewer.