Ignore:
Timestamp:
Feb 21, 2006 12:11:18 AM (18 years ago)
Author:
bennylp
Message:

Initial conference implementation

File:
1 moved

Legend:

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

    r203 r205  
    1717 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
    1818 */ 
    19 #include <pjmedia/audio_conf.h> 
     19#include <pjmedia/conference.h> 
    2020#include <pjmedia/vad.h> 
    2121#include <pjmedia/stream.h> 
    2222#include <pjmedia/sound.h> 
    2323#include <pjmedia/errno.h> 
     24#include <pjmedia/port.h> 
    2425#include <pj/assert.h> 
    2526#include <pj/log.h> 
     
    2728#include <pj/string.h> 
    2829 
    29  
    30  
    31 #define THIS_FILE   "audio_conf.c" 
     30//#define CONF_DEBUG 
     31#ifdef CONF_DEBUG 
     32#   include <stdio.h> 
     33#   define TRACE_(x)   printf x 
     34#else 
     35#   define TRACE_(x) 
     36#endif 
     37 
     38 
     39#define THIS_FILE       "conference.c" 
     40#define RX_BUF_COUNT    8 
     41 
     42/* 
     43 * DON'T GET CONFUSED!! 
     44 * 
     45 * TX and RX directions are always viewed from the conference bridge's point 
     46 * of view, and NOT from the port's point of view.  
     47 */ 
    3248 
    3349 
    3450struct conf_port 
    3551{ 
    36     pj_str_t             name; 
    37     pjmedia_stream_port *port; 
    38     pj_bool_t            online; 
    39     pj_bool_t            is_member; 
    40     pjmedia_vad         *vad; 
    41     pj_int32_t           level; 
     52    pj_str_t             name;          /**< Port name.                     */ 
     53    pjmedia_port        *port;          /**< get_frame() and put_frame()    */ 
     54    pjmedia_port_op      rx_setting;    /**< Can we receive from this port  */ 
     55    pjmedia_port_op      tx_setting;    /**< Can we transmit to this port   */ 
     56    pj_bool_t           *listeners;     /**< Array of listeners.            */ 
     57    pjmedia_vad         *vad;           /**< VAD for this port.             */ 
     58 
     59    /* Tx buffer contains the frame to be "transmitted" to this port 
     60     * (i.e. for put_frame()). 
     61     * We use dual buffer since the port may be accessed by two threads, 
     62     * and we don't want to use mutex for synchronization. 
     63     */ 
     64    pj_int16_t          *cur_tx_buf;    /**< Buffer for put_frame().        */ 
     65    pj_int16_t          *tx_buf1;       /**< Buffer 1.                      */ 
     66    pj_int16_t          *tx_buf2;       /**< Buffer 2.                      */ 
     67 
     68    /* Rx buffers is a special buffer for sound device port (port 0).  
     69     * It's not used by other ports. 
     70     */ 
     71    int                  rx_write, rx_read; 
     72    pj_int16_t          *rx_buf[RX_BUF_COUNT];  /**< Buffer                         */ 
     73 
     74 
     75    /* Sum buf is a temporary buffer used to calculate the average signal 
     76     * received by this port from all other ports. 
     77     */ 
     78    unsigned             sources;       /**< Number of sources.             */ 
     79    pj_uint32_t         *sum_buf;       /**< Total sum of signal.           */ 
    4280}; 
    4381 
     82 
    4483/* 
    4584 * Conference bridge. 
     
    4786struct pjmedia_conf 
    4887{ 
    49     unsigned              max_ports;    /**< Maximum ports.             */ 
    50     unsigned              port_cnt;     /**< Current number of ports.   */ 
    51     pj_snd_stream        *snd_rec;      /**< Sound recorder stream.     */ 
    52     pj_snd_stream        *snd_player;   /**< Sound player stream.       */ 
    53     struct conf_port    **port;         /**< Array of ports.            */ 
    54     pj_int16_t           *rec_buf;      /**< Sample buffer for rec.     */ 
    55     pj_int16_t           *play_buf;     /**< Sample buffer for player   */ 
    56     unsigned              samples_cnt;  /**< Samples per frame.         */ 
    57     pj_size_t             buf_size;     /**< Buffer size, in bytes.     */ 
     88    unsigned              max_ports;    /**< Maximum ports.                 */ 
     89    unsigned              port_cnt;     /**< Current number of ports.       */ 
     90    unsigned              connect_cnt;  /**< Total number of connections    */ 
     91    pj_snd_stream        *snd_rec;      /**< Sound recorder stream.         */ 
     92    pj_snd_stream        *snd_player;   /**< Sound player stream.           */ 
     93    struct conf_port    **ports;        /**< Array of ports.                */ 
     94    pj_uint16_t          *uns_buf;      /**< Buf for unsigned conversion    */ 
     95    unsigned              sampling_rate;        /**< Sampling rate.         */ 
     96    unsigned              samples_per_frame;    /**< Samples per frame.     */ 
     97    unsigned              bits_per_sample;      /**< Bits per sample.       */ 
     98    pj_snd_stream_info    snd_info; 
    5899}; 
    59100 
     
    69110                            /* in*/   unsigned size); 
    70111 
     112/* 
     113 * Create port. 
     114 */ 
     115static pj_status_t create_conf_port( pj_pool_t *pool, 
     116                                     pjmedia_conf *conf, 
     117                                     const pj_str_t *name, 
     118                                     struct conf_port **p_conf_port) 
     119{ 
     120    struct conf_port *conf_port; 
     121    pj_status_t status; 
     122 
     123    /* Create port. */ 
     124    conf_port = pj_pool_zalloc(pool, sizeof(struct conf_port)); 
     125    PJ_ASSERT_RETURN(conf_port, PJ_ENOMEM); 
     126 
     127    /* Set name */ 
     128    pj_strdup(pool, &conf_port->name, name); 
     129 
     130    /* Default has tx and rx enabled. */ 
     131    conf_port->rx_setting = PJMEDIA_PORT_ENABLE; 
     132    conf_port->tx_setting = PJMEDIA_PORT_ENABLE; 
     133 
     134    /* Create transmit flag array */ 
     135    conf_port->listeners = pj_pool_zalloc(pool,  
     136                                          conf->max_ports*sizeof(pj_bool_t)); 
     137    PJ_ASSERT_RETURN(conf_port->listeners, PJ_ENOMEM); 
     138 
     139 
     140    /* Create and init vad. */ 
     141    status = pjmedia_vad_create( pool, &conf_port->vad); 
     142    if (status != PJ_SUCCESS) 
     143        return status; 
     144 
     145    pjmedia_vad_set_adaptive(conf_port->vad, conf->samples_per_frame); 
     146 
     147 
     148    /* Create TX buffers. */ 
     149    conf_port->tx_buf1 = pj_pool_zalloc(pool, conf->samples_per_frame * 
     150                                              sizeof(conf_port->tx_buf1[0])); 
     151    PJ_ASSERT_RETURN(conf_port->tx_buf1, PJ_ENOMEM); 
     152 
     153    conf_port->tx_buf2 = pj_pool_zalloc(pool, conf->samples_per_frame * 
     154                                              sizeof(conf_port->tx_buf2[0])); 
     155    PJ_ASSERT_RETURN(conf_port->tx_buf2, PJ_ENOMEM); 
     156 
     157    /* Set initial TX buffer */ 
     158    conf_port->cur_tx_buf = conf_port->tx_buf1; 
     159 
     160    /* Create temporary buffer to calculate average signal received by 
     161     * this port. 
     162     */ 
     163    conf_port->sum_buf = pj_pool_zalloc(pool, conf->samples_per_frame * 
     164                                              sizeof(conf_port->sum_buf[0])); 
     165 
     166     
     167 
     168    /* Done */ 
     169    *p_conf_port = conf_port; 
     170    return PJ_SUCCESS; 
     171} 
     172 
     173/* 
     174 * Create port zero for the sound device. 
     175 */ 
     176static pj_status_t create_sound_port( pj_pool_t *pool, 
     177                                      pjmedia_conf *conf ) 
     178{ 
     179    struct conf_port *conf_port; 
     180    pj_str_t name = { "sound-device", 12 }; 
     181    unsigned i; 
     182    pj_status_t status; 
     183 
     184 
     185    /* Init default sound device parameters. */ 
     186    pj_memset(&conf->snd_info, 0, sizeof(conf->snd_info)); 
     187    conf->snd_info.samples_per_sec = conf->sampling_rate; 
     188    conf->snd_info.bits_per_sample = conf->bits_per_sample; 
     189    conf->snd_info.samples_per_frame = conf->samples_per_frame; 
     190    conf->snd_info.bytes_per_frame = conf->samples_per_frame *  
     191                               conf->bits_per_sample / 8; 
     192    conf->snd_info.frames_per_packet = 1; 
     193     
     194 
     195    /* Create port */ 
     196    status = create_conf_port(pool, conf, &name, &conf_port); 
     197    if (status != PJ_SUCCESS) 
     198        goto on_error; 
     199 
     200    /* Sound device has rx buffers. */ 
     201    for (i=0; i<RX_BUF_COUNT; ++i) { 
     202        conf_port->rx_buf[i] = pj_pool_zalloc(pool, conf->samples_per_frame * 
     203                                              sizeof(conf_port->rx_buf[0][0])); 
     204        if (conf_port->rx_buf[i] == NULL) { 
     205            status = PJ_ENOMEM; 
     206            goto on_error; 
     207        } 
     208    } 
     209    conf_port->rx_write = 0; 
     210    conf_port->rx_read = 0; 
     211 
     212 
     213     /* Set to port zero */ 
     214    conf->ports[0] = conf_port; 
     215    conf->port_cnt++; 
     216 
     217    PJ_LOG(5,(THIS_FILE, "Sound device successfully created for port 0")); 
     218    return PJ_SUCCESS; 
     219 
     220on_error: 
     221    return status; 
     222 
     223} 
    71224 
    72225/* 
     
    75228PJ_DEF(pj_status_t) pjmedia_conf_create( pj_pool_t *pool, 
    76229                                         unsigned max_ports, 
     230                                         unsigned sampling_rate, 
     231                                         unsigned samples_per_frame, 
     232                                         unsigned bits_per_sample, 
    77233                                         pjmedia_conf **p_conf ) 
    78234{ 
    79235    pjmedia_conf *conf; 
    80     pj_snd_stream_info snd_info; 
    81236    pj_status_t status; 
    82237 
     238    PJ_LOG(5,(THIS_FILE, "Creating conference bridge with %d ports", 
     239              max_ports)); 
     240 
     241    /* Create and init conf structure. */ 
    83242    conf = pj_pool_zalloc(pool, sizeof(pjmedia_conf)); 
     243    PJ_ASSERT_RETURN(conf, PJ_ENOMEM); 
     244 
     245    conf->ports = pj_pool_zalloc(pool, max_ports*sizeof(void*)); 
     246    PJ_ASSERT_RETURN(conf->ports, PJ_ENOMEM); 
     247 
    84248    conf->max_ports = max_ports; 
    85     conf->port = pj_pool_zalloc(pool, max_ports*sizeof(void*)); 
    86  
    87     /* Create default parameters. */ 
    88     pj_memset(&snd_info, 0, sizeof(snd_info)); 
    89     snd_info.samples_per_sec = 8000; 
    90     snd_info.bits_per_sample = 16; 
    91     snd_info.samples_per_frame = 160; 
    92     snd_info.bytes_per_frame = 16000; 
    93     snd_info.frames_per_packet = 1; 
    94  
    95     /* Create buffers. */ 
    96     conf->samples_cnt = snd_info.samples_per_frame; 
    97     conf->buf_size = snd_info.samples_per_frame * snd_info.bits_per_sample / 8; 
    98     conf->rec_buf = pj_pool_alloc(pool,  conf->buf_size); 
    99     conf->play_buf = pj_pool_alloc(pool, conf->buf_size ); 
    100  
    101  
     249    conf->sampling_rate = sampling_rate; 
     250    conf->samples_per_frame = samples_per_frame; 
     251    conf->bits_per_sample = bits_per_sample; 
     252 
     253 
     254    /* Create port zero for sound device. */ 
     255    status = create_sound_port(pool, conf); 
     256    if (status != PJ_SUCCESS) 
     257        return status; 
     258 
     259    /* Create temporary buffer. */ 
     260    conf->uns_buf = pj_pool_zalloc(pool, samples_per_frame * 
     261                                         sizeof(conf->uns_buf[0])); 
     262    /* Done */ 
     263 
     264    *p_conf = conf; 
     265 
     266    return PJ_SUCCESS; 
     267} 
     268 
     269 
     270/* 
     271 * Create sound device 
     272 */ 
     273static pj_status_t create_sound( pjmedia_conf *conf ) 
     274{ 
    102275    /* Open recorder. */ 
    103     conf->snd_rec = pj_snd_open_recorder(-1 ,&snd_info, &rec_cb, conf); 
     276    conf->snd_rec = pj_snd_open_recorder(-1 ,&conf->snd_info, &rec_cb, conf); 
    104277    if (conf->snd_rec == NULL) { 
    105         status = -1; 
    106         goto on_error; 
     278        return -1; 
    107279    } 
    108280 
    109281    /* Open player */ 
    110     conf->snd_player = pj_snd_open_player(-1, &snd_info, &play_cb, conf); 
     282    conf->snd_player = pj_snd_open_player(-1, &conf->snd_info, &play_cb, conf); 
    111283    if (conf->snd_player == NULL) { 
    112         status = -1; 
    113         goto on_error; 
    114     } 
    115  
    116     /* Done */ 
    117  
    118     *p_conf = conf; 
    119  
    120     return PJ_SUCCESS; 
    121  
    122  
    123 on_error: 
     284        pj_snd_stream_close(conf->snd_rec); 
     285        return -1; 
     286    } 
     287 
     288    return PJ_SUCCESS; 
     289} 
     290 
     291/* 
     292 * Destroy sound device 
     293 */ 
     294static pj_status_t destroy_sound( pjmedia_conf *conf ) 
     295{ 
    124296    if (conf->snd_rec) { 
    125         pj_snd_stream_stop(conf->snd_rec); 
    126297        pj_snd_stream_close(conf->snd_rec); 
    127298        conf->snd_rec = NULL; 
    128299    } 
    129300    if (conf->snd_player) { 
    130         pj_snd_stream_stop(conf->snd_player); 
    131301        pj_snd_stream_close(conf->snd_player); 
    132302        conf->snd_player = NULL; 
    133303    } 
    134     return status; 
     304    return PJ_SUCCESS; 
    135305} 
    136306 
     
    138308 * Activate sound device. 
    139309 */ 
    140 static pj_status_t activate_conf( pjmedia_conf *conf ) 
     310static pj_status_t resume_sound( pjmedia_conf *conf ) 
    141311{ 
    142312    char errmsg[PJ_ERR_MSG_SIZE]; 
    143313    pj_status_t status; 
    144314 
     315    if (conf->snd_rec == NULL) { 
     316        status = create_sound(conf); 
     317        if (status != PJ_SUCCESS) 
     318            return status; 
     319    } 
     320 
    145321    /* Start recorder. */ 
    146     status = pj_snd_stream_start(conf->snd_rec); 
    147     if (status != PJ_SUCCESS) 
    148         goto on_error; 
     322    if (conf->snd_rec) { 
     323        status = pj_snd_stream_start(conf->snd_rec); 
     324        if (status != PJ_SUCCESS) 
     325            goto on_error; 
     326    } 
    149327 
    150328    /* Start player. */ 
    151     status = pj_snd_stream_start(conf->snd_rec); 
    152     if (status != PJ_SUCCESS) 
    153         goto on_error; 
     329    if (conf->snd_player) { 
     330        status = pj_snd_stream_start(conf->snd_player); 
     331        if (status != PJ_SUCCESS) 
     332            goto on_error; 
     333    } 
    154334 
    155335    return PJ_SUCCESS; 
     
    166346 * Suspend sound device 
    167347 */ 
    168 static void suspend_conf( pjmedia_conf *conf ) 
    169 { 
    170     pj_snd_stream_stop(conf->snd_rec); 
    171     pj_snd_stream_stop(conf->snd_player); 
     348static void suspend_sound( pjmedia_conf *conf ) 
     349{ 
     350    if (conf->snd_rec) 
     351        pj_snd_stream_stop(conf->snd_rec); 
     352    if (conf->snd_player) 
     353        pj_snd_stream_stop(conf->snd_player); 
     354} 
     355 
     356 
     357/** 
     358 * Destroy conference bridge. 
     359 */ 
     360PJ_DEF(pj_status_t) pjmedia_conf_destroy( pjmedia_conf *conf ) 
     361{ 
     362    PJ_ASSERT_RETURN(conf != NULL, PJ_EINVAL); 
     363 
     364    suspend_sound(conf); 
     365 
     366    pj_snd_stream_close(conf->snd_rec); 
     367    conf->snd_rec = NULL; 
     368    pj_snd_stream_close(conf->snd_player); 
     369    conf->snd_player = NULL; 
     370 
     371    return PJ_SUCCESS; 
    172372} 
    173373 
     
    178378PJ_DEF(pj_status_t) pjmedia_conf_add_port( pjmedia_conf *conf, 
    179379                                           pj_pool_t *pool, 
    180                                            pjmedia_stream_port *strm_port, 
     380                                           pjmedia_port *strm_port, 
    181381                                           const pj_str_t *port_name, 
    182382                                           unsigned *p_port ) 
     
    194394    } 
    195395 
     396    /* Find empty port in the conference bridge. */ 
     397    for (index=0; index < conf->max_ports; ++index) { 
     398        if (conf->ports[index] == NULL) 
     399            break; 
     400    } 
     401 
     402    pj_assert(index != conf->max_ports); 
     403 
    196404    /* Create port structure. */ 
    197     conf_port = pj_pool_zalloc(pool, sizeof(struct conf_port)); 
    198     pj_strdup_with_null(pool, &conf_port->name, port_name); 
    199     conf_port->port = strm_port; 
    200     conf_port->online = PJ_TRUE; 
    201     conf_port->level = 0; 
    202  
    203     /* Create VAD for this port. */ 
    204     status = pjmedia_vad_create(pool, &conf_port->vad); 
     405    status = create_conf_port(pool, conf, port_name, &conf_port); 
    205406    if (status != PJ_SUCCESS) 
    206407        return status; 
    207408 
    208     /* Set vad settings. */ 
    209     pjmedia_vad_set_adaptive(conf_port->vad, conf->samples_cnt); 
    210  
    211     /* Find empty port in the conference bridge. */ 
    212     for (index=0; index < conf->max_ports; ++index) { 
    213         if (conf->port[index] == NULL) 
    214             break; 
    215     } 
    216  
    217     pj_assert(index != conf->max_ports); 
     409    /* Set the port */ 
     410    conf_port->port = strm_port; 
    218411 
    219412    /* Put the port. */ 
    220     conf->port[index] = conf_port; 
     413    conf->ports[index] = conf_port; 
    221414    conf->port_cnt++; 
    222415 
    223     /* If this is the first port, activate sound device. */ 
    224     if (conf->port_cnt == 1) { 
    225         status = activate_conf(conf);; 
    226         if (status != PJ_SUCCESS) { 
    227             conf->port[index] = NULL; 
    228             --conf->port_cnt; 
    229             return status; 
     416    /* Done. */ 
     417    *p_port = index; 
     418 
     419    return PJ_SUCCESS; 
     420} 
     421 
     422 
     423/* 
     424 * Change TX and RX settings for the port. 
     425 */ 
     426PJ_DECL(pj_status_t) pjmedia_conf_configure_port( pjmedia_conf *conf, 
     427                                                  unsigned slot, 
     428                                                  pjmedia_port_op tx, 
     429                                                  pjmedia_port_op rx) 
     430{ 
     431    struct conf_port *conf_port; 
     432 
     433    /* Check arguments */ 
     434    PJ_ASSERT_RETURN(conf && slot<conf->max_ports, PJ_EINVAL); 
     435 
     436    /* Port must be valid. */ 
     437    PJ_ASSERT_RETURN(conf->ports[slot] != NULL, PJ_EINVAL); 
     438 
     439    conf_port = conf->ports[slot]; 
     440 
     441    if (tx != PJMEDIA_PORT_NO_CHANGE) 
     442        conf_port->tx_setting = tx; 
     443 
     444    if (rx != PJMEDIA_PORT_NO_CHANGE) 
     445        conf_port->rx_setting = rx; 
     446 
     447    return PJ_SUCCESS; 
     448} 
     449 
     450 
     451/* 
     452 * Connect port. 
     453 */ 
     454PJ_DEF(pj_status_t) pjmedia_conf_connect_port( pjmedia_conf *conf, 
     455                                               unsigned src_slot, 
     456                                               unsigned sink_slot ) 
     457{ 
     458    struct conf_port *src_port, *dst_port; 
     459 
     460    /* Check arguments */ 
     461    PJ_ASSERT_RETURN(conf && src_slot<conf->max_ports &&  
     462                     sink_slot<conf->max_ports, PJ_EINVAL); 
     463 
     464    /* Ports must be valid. */ 
     465    PJ_ASSERT_RETURN(conf->ports[src_slot] != NULL, PJ_EINVAL); 
     466    PJ_ASSERT_RETURN(conf->ports[sink_slot] != NULL, PJ_EINVAL); 
     467 
     468    src_port = conf->ports[src_slot]; 
     469    dst_port = conf->ports[sink_slot]; 
     470 
     471    if (src_port->listeners[sink_slot] == 0) { 
     472        src_port->listeners[sink_slot] = 1; 
     473        ++conf->connect_cnt; 
     474 
     475        if (conf->connect_cnt == 1) 
     476            resume_sound(conf); 
     477 
     478        PJ_LOG(5,(THIS_FILE,"Port %.*s transmitting to port %.*s", 
     479                  (int)src_port->name.slen, 
     480                  src_port->name.ptr, 
     481                  (int)dst_port->name.slen, 
     482                  dst_port->name.ptr)); 
     483    } 
     484 
     485    return PJ_SUCCESS; 
     486} 
     487 
     488 
     489/* 
     490 * Disconnect port 
     491 */ 
     492PJ_DEF(pj_status_t) pjmedia_conf_disconnect_port( pjmedia_conf *conf, 
     493                                                  unsigned src_slot, 
     494                                                  unsigned sink_slot ) 
     495{ 
     496    struct conf_port *src_port, *dst_port; 
     497 
     498    /* Check arguments */ 
     499    PJ_ASSERT_RETURN(conf && src_slot<conf->max_ports &&  
     500                     sink_slot<conf->max_ports, PJ_EINVAL); 
     501 
     502    /* Ports must be valid. */ 
     503    PJ_ASSERT_RETURN(conf->ports[src_slot] != NULL, PJ_EINVAL); 
     504    PJ_ASSERT_RETURN(conf->ports[sink_slot] != NULL, PJ_EINVAL); 
     505 
     506    src_port = conf->ports[src_slot]; 
     507    dst_port = conf->ports[sink_slot]; 
     508 
     509    if (src_port->listeners[sink_slot] != 0) { 
     510        src_port->listeners[sink_slot] = 0; 
     511        --conf->connect_cnt; 
     512 
     513        PJ_LOG(5,(THIS_FILE,"Port %.*s stop transmitting to port %.*s", 
     514                  (int)src_port->name.slen, 
     515                  src_port->name.ptr, 
     516                  (int)dst_port->name.slen, 
     517                  dst_port->name.ptr)); 
     518 
     519        if (conf->connect_cnt == 0) { 
     520            suspend_sound(conf); 
     521            destroy_sound(conf); 
    230522        } 
    231523    } 
    232524 
    233     /* Done. */ 
    234     return PJ_SUCCESS; 
    235 } 
    236  
    237  
    238 /* 
    239  * Mute or unmute port. 
    240  */ 
    241 PJ_DEF(pj_status_t) pjmedia_conf_set_mute( pjmedia_conf *conf, 
    242                                            unsigned port, 
    243                                            pj_bool_t mute ) 
    244 { 
     525    return PJ_SUCCESS; 
     526} 
     527 
     528 
     529/* 
     530 * Remove the specified port. 
     531 */ 
     532PJ_DEF(pj_status_t) pjmedia_conf_remove_port( pjmedia_conf *conf, 
     533                                              unsigned port ) 
     534{ 
     535    struct conf_port *conf_port; 
     536    unsigned i; 
     537 
    245538    /* Check arguments */ 
    246539    PJ_ASSERT_RETURN(conf && port < conf->max_ports, PJ_EINVAL); 
    247540 
    248541    /* Port must be valid. */ 
    249     PJ_ASSERT_RETURN(conf->port[port] != NULL, PJ_EINVAL); 
    250  
    251     conf->port[port]->online = !mute; 
    252      
    253     return PJ_SUCCESS; 
    254 } 
    255  
    256  
    257 /* 
    258  * Set the specified port to be member of conference bridge. 
    259  */ 
    260 PJ_DEF(pj_status_t) pjmedia_conf_set_membership( pjmedia_conf *conf, 
    261                                                  unsigned port, 
    262                                                  pj_bool_t enabled ) 
    263 { 
    264     /* Check arguments */ 
    265     PJ_ASSERT_RETURN(conf && port < conf->max_ports, PJ_EINVAL); 
    266  
    267     /* Port must be valid. */ 
    268     PJ_ASSERT_RETURN(conf->port[port] != NULL, PJ_EINVAL); 
    269  
    270     conf->port[port]->is_member = enabled; 
    271      
    272     return PJ_SUCCESS; 
    273 } 
    274  
    275  
    276 /* 
    277  * Remove the specified port. 
    278  */ 
    279 PJ_DEF(pj_status_t) pjmedia_conf_remove_port( pjmedia_conf *conf, 
    280                                               unsigned port ) 
    281 { 
    282     /* Check arguments */ 
    283     PJ_ASSERT_RETURN(conf && port < conf->max_ports, PJ_EINVAL); 
    284  
    285     /* Port must be valid. */ 
    286     PJ_ASSERT_RETURN(conf->port[port] != NULL, PJ_EINVAL); 
     542    PJ_ASSERT_RETURN(conf->ports[port] != NULL, PJ_EINVAL); 
    287543 
    288544    /* Suspend the sound devices. 
    289545     * Don't want to remove port while port is being accessed by sound 
    290      * device's threads. 
     546     * device's threads! 
    291547     */ 
    292     suspend_conf(conf); 
     548    //suspend_sound(conf); 
     549 
     550    conf_port = conf->ports[port]; 
     551    conf_port->tx_setting = PJMEDIA_PORT_DISABLE; 
     552    conf_port->rx_setting = PJMEDIA_PORT_DISABLE; 
     553 
     554    /* Remove this port from transmit array of other ports. */ 
     555    for (i=0; i<conf->max_ports; ++i) { 
     556        conf_port = conf->ports[i]; 
     557 
     558        if (!conf_port) 
     559            continue; 
     560 
     561        if (conf_port->listeners[port] != 0) { 
     562            --conf->connect_cnt; 
     563            conf_port->listeners[port] = 0; 
     564        } 
     565    } 
     566 
     567    /* Remove all ports listening from this port. */ 
     568    conf_port = conf->ports[port]; 
     569    for (i=0; i<conf->max_ports; ++i) { 
     570        if (conf_port->listeners[i]) 
     571            --conf->connect_cnt; 
     572    } 
    293573 
    294574    /* Remove the port. */ 
    295     conf->port[port] = NULL; 
     575    conf->ports[port] = NULL; 
    296576    --conf->port_cnt; 
    297577 
    298     /* Reactivate sound device if ports are not zero */ 
    299     if (conf->port_cnt != 0) 
    300         activate_conf(conf); 
    301  
    302     return PJ_SUCCESS; 
    303 } 
    304  
     578    /* Reactivate sound device if there are connections */ 
     579    if (conf->connect_cnt != 0) { 
     580        //resume_sound(conf); 
     581    } else { 
     582        destroy_sound(conf); 
     583    } 
     584 
     585    pj_thread_sleep(60); 
     586    return PJ_SUCCESS; 
     587} 
     588 
     589/* 
     590 * Get port info 
     591 */ 
     592PJ_DEF(pj_status_t) pjmedia_conf_get_port_info( pjmedia_conf *conf, 
     593                                                unsigned slot, 
     594                                                pjmedia_conf_port_info *info) 
     595{ 
     596    struct conf_port *conf_port; 
     597 
     598    /* Check arguments */ 
     599    PJ_ASSERT_RETURN(conf && slot<conf->max_ports, PJ_EINVAL); 
     600 
     601    /* Port must be valid. */ 
     602    PJ_ASSERT_RETURN(conf->ports[slot] != NULL, PJ_EINVAL); 
     603 
     604    conf_port = conf->ports[slot]; 
     605 
     606    info->name = conf_port->name; 
     607    info->tx_setting = conf_port->tx_setting; 
     608    info->rx_setting = conf_port->rx_setting; 
     609    info->listener = conf_port->listeners; 
     610 
     611    return PJ_SUCCESS; 
     612} 
     613 
     614 
     615/* Convert signed 16bit pcm sample to unsigned 16bit sample */ 
     616static pj_uint16_t pcm2unsigned(pj_int32_t pcm) 
     617{ 
     618    return (pj_uint16_t)(pcm + 32767); 
     619} 
     620 
     621/* Convert unsigned 16bit sample to signed 16bit pcm sample */ 
     622static pj_int16_t unsigned2pcm(pj_uint32_t uns) 
     623{ 
     624    return (pj_int16_t)(uns - 32767); 
     625} 
    305626 
    306627/* 
     
    314635    pjmedia_conf *conf = user_data; 
    315636    pj_int16_t *output_buf = output; 
    316     pj_int32_t highest_level = 0; 
    317     int highest_index = -1; 
    318     unsigned sources = 0; 
    319637    unsigned i, j; 
    320638     
    321639    PJ_UNUSED_ARG(timestamp); 
    322  
    323     /* Clear temporary buffer. */ 
    324     pj_memset(output_buf, 0, size); 
    325  
    326     /* Get frames from ports. */ 
     640    PJ_UNUSED_ARG(size); 
     641 
     642    TRACE_(("p")); 
     643 
     644    /* Clear all port's tmp buffers. */ 
    327645    for (i=0; i<conf->max_ports; ++i) { 
    328         struct conf_port *conf_port = conf->port[i]; 
     646        struct conf_port *conf_port = conf->ports[i]; 
     647        pj_uint32_t *sum_buf; 
     648 
     649        if (!conf_port) 
     650            continue; 
     651 
     652        conf_port->sources = 0; 
     653        sum_buf = conf_port->sum_buf; 
     654 
     655        for (j=0; j<conf->samples_per_frame; ++j) 
     656            sum_buf[j] = 0; 
     657    } 
     658 
     659    /* Get frames from all ports, and "add" the signal  
     660     * to sum_buf of all listeners of the port. 
     661     */ 
     662    for (i=0; i<conf->max_ports; ++i) { 
     663        struct conf_port *conf_port = conf->ports[i]; 
    329664        pj_int32_t level; 
    330665        pj_bool_t silence; 
    331666 
     667        /* Skip empty port. */ 
    332668        if (!conf_port) 
    333669            continue; 
    334670 
    335         conf_port->port->get_frame(conf->play_buf, conf->samples_cnt); 
     671        /* Skip if we're not allowed to receive from this port. */ 
     672        if (conf_port->rx_setting == PJMEDIA_PORT_DISABLE) { 
     673            TRACE_(("rxdis:%d ", i)); 
     674            continue; 
     675        } 
     676 
     677        /* Get frame from this port.  
     678         * If port has rx_buffer, then get the frame from the rx_buffer 
     679         * instead. 
     680         */ 
     681        if (i==0/*conf_port->cur_rx_buf*/) { 
     682            pj_int16_t *rx_buf; 
     683 
     684            if (conf_port->rx_read == conf_port->rx_write) 
     685                conf_port->rx_read = (conf_port->rx_write+RX_BUF_COUNT-RX_BUF_COUNT/2) % RX_BUF_COUNT; 
     686 
     687            rx_buf = conf_port->rx_buf[conf_port->rx_read]; 
     688            for (j=0; j<conf->samples_per_frame; ++j) { 
     689                ((pj_int16_t*)output)[j] = rx_buf[j]; 
     690            } 
     691            conf_port->rx_read = (conf_port->rx_read+1) % RX_BUF_COUNT; 
     692        } else { 
     693            pjmedia_frame frame; 
     694 
     695            pj_memset(&frame, 0, sizeof(frame)); 
     696            frame.buf = output; 
     697            frame.size = size; 
     698            pjmedia_port_get_frame(conf_port->port, &frame); 
     699        } 
     700 
     701        /* Skip (after receiving the frame) if this port is muted. */ 
     702        if (conf_port->rx_setting == PJMEDIA_PORT_MUTE) 
     703            continue; 
     704 
     705        /* Do we have signal? */ 
    336706        silence = pjmedia_vad_detect_silence(conf_port->vad, 
    337                                              conf->play_buf,  
    338                                              conf->samples_cnt, 
     707                                             output,  
     708                                             conf->samples_per_frame, 
    339709                                             &level); 
    340         if (!silence) { 
    341             if (level > highest_level) { 
    342                 highest_index = i; 
    343                 highest_level = level; 
    344             } 
    345  
    346             ++sources; 
    347  
    348             for (j=0; j<conf->samples_cnt; ++j) { 
    349                 output_buf[j] = (pj_int16_t)(output_buf[j] + conf->play_buf[j]); 
     710 
     711        /* Skip if we don't have signal. */ 
     712        if (silence) { 
     713            TRACE_(("sil:%d ", i)); 
     714            continue; 
     715        } 
     716 
     717        /* Convert the buffer to unsigned value */ 
     718        for (j=0; j<conf->samples_per_frame; ++j) 
     719            conf->uns_buf[j] = pcm2unsigned(((pj_int16_t*)output)[j]); 
     720 
     721        /* Add the signal to all listeners. */ 
     722        for (j=0; j<conf->max_ports; ++j) { 
     723            struct conf_port *listener = conf->ports[j]; 
     724            pj_uint32_t *sum_buf; 
     725            unsigned k; 
     726 
     727            if (conf_port->listeners[j] == 0) 
     728                continue; 
     729 
     730            /* Skip if this listener doesn't want to receive audio */ 
     731            if (listener->tx_setting != PJMEDIA_PORT_ENABLE) 
     732                continue; 
     733 
     734            //TRACE_(("mix:%d->%d ", i, j)); 
     735 
     736            sum_buf = listener->sum_buf; 
     737            for (k=0; k<conf->samples_per_frame; ++k) 
     738                sum_buf[k] += conf->uns_buf[k]; 
     739 
     740            listener->sources++; 
     741        } 
     742    } 
     743 
     744    /* For all ports, calculate avg signal. */ 
     745    for (i=0; i<conf->max_ports; ++i) { 
     746        struct conf_port *conf_port = conf->ports[i]; 
     747        pjmedia_frame frame; 
     748        pj_int16_t *target_buf; 
     749 
     750        if (!conf_port) 
     751            continue; 
     752 
     753 
     754        target_buf = (conf_port->cur_tx_buf==conf_port->tx_buf1? 
     755                        conf_port->tx_buf2 : conf_port->tx_buf1); 
     756 
     757        if (!conf_port->sources) { 
     758            for (j=0; j<conf->samples_per_frame; ++j) 
     759                target_buf[j] = 0; 
     760        } else { 
     761            for (j=0; j<conf->samples_per_frame; ++j) { 
     762                target_buf[j] = unsigned2pcm(conf_port->sum_buf[j] / conf_port->sources); 
    350763            } 
    351764        } 
    352     } 
    353  
    354     /* Calculate average signal. */ 
    355     if (sources) { 
    356         for (j=0; j<conf->samples_cnt; ++j) { 
    357             output_buf[j] = (pj_int16_t)(output_buf[j] / sources); 
    358         } 
    359     } 
    360  
    361     /* Broadcast to conference member. */ 
    362     for (i=0; i<conf->max_ports; ++i) { 
    363         struct conf_port *conf_port = conf->port[i]; 
    364  
    365         if (!conf_port) 
     765 
     766        /* Switch buffer. */ 
     767        conf_port->cur_tx_buf = target_buf; 
     768 
     769        if (conf_port->tx_setting != PJMEDIA_PORT_ENABLE) 
    366770            continue; 
    367771 
    368         if (!conf_port->is_member) 
    369             continue; 
    370  
    371         conf_port->port->put_frame(output_buf, conf->samples_cnt); 
    372     } 
    373  
    374     return PJ_SUCCESS; 
    375 } 
     772        pj_memset(&frame, 0, sizeof(frame)); 
     773        frame.type = PJMEDIA_FRAME_TYPE_AUDIO; 
     774        frame.buf = conf_port->cur_tx_buf; 
     775        frame.size = conf->samples_per_frame * conf->bits_per_sample / 8; 
     776        frame.timestamp.u64 = timestamp; 
     777 
     778        if (conf_port->port) 
     779            pjmedia_port_put_frame(conf_port->port, &frame); 
     780 
     781    } 
     782 
     783    /* Return sound playback frame. */ 
     784    for (j=0; j<conf->samples_per_frame; ++j) 
     785        output_buf[j] = conf->ports[0]->cur_tx_buf[j]; 
     786 
     787    return PJ_SUCCESS; 
     788} 
     789 
    376790 
    377791/* 
     
    381795                            /* in */  pj_uint32_t timestamp, 
    382796                            /* in */  const void *input, 
    383                             /* in*/   unsigned size) 
     797                            /* in */  unsigned size) 
    384798{ 
    385799    pjmedia_conf *conf = user_data; 
     800    struct conf_port *snd_port = conf->ports[0]; 
     801    pj_int16_t *target_rx_buf; 
    386802    unsigned i; 
    387803 
    388804    PJ_UNUSED_ARG(timestamp); 
    389     PJ_UNUSED_ARG(size); 
    390  
    391     for (i=0; i<conf->max_ports; ++i) { 
    392         struct conf_port *conf_port = conf->port[i]; 
     805     
     806    TRACE_(("r")); 
     807 
     808    if (size != conf->samples_per_frame*2) { 
     809        TRACE_(("rxerr ")); 
     810    } 
     811 
     812 
     813    /* Determine which rx_buffer to fill in */ 
     814    target_rx_buf = snd_port->rx_buf[snd_port->rx_write]; 
     815     
     816    /* Copy samples from audio device to target rx_buffer */ 
     817    for (i=0; i<conf->samples_per_frame; ++i) { 
     818        target_rx_buf[i] = ((pj_int16_t*)input)[i]; 
     819    } 
     820 
     821    /* Switch buffer */ 
     822    snd_port->rx_write = (snd_port->rx_write+1)%RX_BUF_COUNT; 
     823 
     824 
     825    /* Time for all ports (except sound port) to transmit frames */ 
     826    /* 
     827    for (i=1; i<conf->max_ports; ++i) { 
     828        struct conf_port *conf_port = conf->ports[i]; 
     829        pjmedia_frame frame; 
    393830 
    394831        if (!conf_port) 
    395832            continue; 
    396833 
    397         if (!conf_port->online) 
    398             continue; 
    399  
    400         conf_port->port->put_frame(input, conf->samples_cnt); 
    401     } 
     834    } 
     835    */ 
    402836     
    403837    return PJ_SUCCESS; 
Note: See TracChangeset for help on using the changeset viewer.