Changeset 323


Ignore:
Timestamp:
Mar 17, 2006 12:16:01 AM (19 years ago)
Author:
bennylp
Message:

Added feature in conference bridge to get and set the signal level of individual port and individual stream direction

Location:
pjproject/trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjmedia/include/pjmedia/conference.h

    r322 r323  
    5959    PJMEDIA_CONF_NO_MIC  = 1,   /**< Disable audio streams from the 
    6060                                     microphone device.                     */ 
     61    PJMEDIA_CONF_NO_DEVICE = 2, /**< Do not create sound device.            */ 
    6162}; 
    6263 
    6364 
    6465/** 
    65  * Create conference bridge. This normally will also create instances of 
    66  * sound device to be attached to the port zero of the bridge. 
     66 * Create conference bridge with the specified parameters. The sampling rate, 
     67 * samples per frame, and bits per sample will be used for the internal 
     68 * operation of the bridge (e.g. when mixing audio frames). However, ports  
     69 * with different configuration may be connected to the bridge. In this case, 
     70 * the bridge is able to perform sampling rate conversion, and buffering in  
     71 * case the samples per frame is different. 
     72 * 
     73 * For this version of PJMEDIA, only 16bits per sample is supported. 
     74 * 
     75 * For this version of PJMEDIA, the channel count of the ports MUST match 
     76 * the channel count of the bridge. 
     77 * 
     78 * Under normal operation (i.e. when PJMEDIA_CONF_NO_DEVICE option is NOT 
     79 * specified), the bridge internally create an instance of sound device 
     80 * and connect the sound device to port zero of the bridge.  
     81 * 
     82 * If PJMEDIA_CONF_NO_DEVICE options is specified, no sound device will 
     83 * be created in the conference bridge. Application MUST acquire the port 
     84 * interface of the bridge by calling #pjmedia_conf_get_master_port(), and 
     85 * connect this port interface to a sound device port by calling 
     86 * #pjmedia_snd_port_connect(). 
     87 * 
     88 * The sound device is crucial for the bridge's operation, because it provides 
     89 * the bridge with necessary clock to process the audio frames periodically. 
     90 * Internally, the bridge runs when get_frame() to port zero is called. 
    6791 * 
    6892 * @param pool              Pool to use to allocate the bridge and  
     
    114138 
    115139/** 
     140 * Get the master port interface of the conference bridge. The master port 
     141 * corresponds to the port zero of the bridge. This is only usefull when  
     142 * application wants to manage the sound device by itself, instead of  
     143 * allowing the bridge to automatically create a sound device implicitly. 
     144 * 
     145 * This function will only return a port interface if PJMEDIA_CONF_NO_DEVICE 
     146 * option was specified when the bridge was created. 
     147 * 
     148 * Application can connect the port returned by this function to a  
     149 * sound device by calling #pjmedia_snd_port_connect(). 
     150 * 
     151 * @param conf              The conference bridge. 
     152 * 
     153 * @return                  The port interface of port zero of the bridge, 
     154 *                          only when PJMEDIA_CONF_NO_DEVICE options was 
     155 *                          specified when the bridge was created. 
     156 */ 
     157PJ_DECL(pjmedia_port*) pjmedia_conf_get_master_port(pjmedia_conf *conf); 
     158 
     159 
     160/** 
    116161 * Add stream port to the conference bridge. By default, the new conference 
    117162 * port will have both TX and RX enabled, but it is not connected to any 
     
    161206 * @param src_slot      Source slot. 
    162207 * @param sink_slot     Sink slot. 
     208 * @param level         This argument is reserved for future improvements 
     209 *                      where it is possible to adjust the level of signal 
     210 *                      transmitted in a specific connection. For now, 
     211 *                      this argument MUST be zero. 
    163212 * 
    164213 * @return              PJ_SUCCES on success. 
     
    166215PJ_DECL(pj_status_t) pjmedia_conf_connect_port( pjmedia_conf *conf, 
    167216                                                unsigned src_slot, 
    168                                                 unsigned sink_slot ); 
     217                                                unsigned sink_slot, 
     218                                                int level ); 
    169219 
    170220 
     
    224274PJ_DECL(pj_status_t) pjmedia_conf_get_ports_info(pjmedia_conf *conf, 
    225275                                                 unsigned *size, 
    226                                                  pjmedia_conf_port_info info[]); 
     276                                                 pjmedia_conf_port_info info[] 
     277                                                 ); 
     278 
     279 
     280/** 
     281 * Get last signal level transmitted to or received from the specified port. 
     282 * The signal level is an integer value in zero to 255, with zero indicates 
     283 * no signal, and 255 indicates the loudest signal level. 
     284 * 
     285 * @param conf          The conference bridge. 
     286 * @param slot          Slot number. 
     287 * @param tx_level      Optional argument to receive the level of signal 
     288 *                      transmitted to the specified port (i.e. the direction 
     289 *                      is from the bridge to the port). 
     290 * @param rx_level      Optional argument to receive the level of signal 
     291 *                      received from the port (i.e. the direction is from the 
     292 *                      port to the bridge). 
     293 * 
     294 * @return              PJ_SUCCESS on success. 
     295 */ 
     296PJ_DECL(pj_status_t) pjmedia_conf_get_signal_level(pjmedia_conf *conf, 
     297                                                   unsigned slot, 
     298                                                   unsigned *tx_level, 
     299                                                   unsigned *rx_level); 
     300 
     301 
     302/** 
     303 * Adjust the level of signal received from the specified port. 
     304 * Application may adjust the level to make the signal received from the port 
     305 * either louder or more quiet, by giving the value from +127 to -128. The 
     306 * value zero indicates no adjustment, the value -128 will mute the signal,  
     307 * and the value of +127 will make the signal twice as loud. 
     308 * 
     309 * @param conf          The conference bridge. 
     310 * @param slot          Slot number. 
     311 * @param adj_level     Adjustment level, with valid values are from -128 
     312 *                      to +127. A value of zero means there is no level 
     313 *                      adjustment to be made, the value -128 will mute the  
     314 *                      signal, and the value of +127 will make the signal  
     315 *                      twice as loud. 
     316 * 
     317 * @return              PJ_SUCCESS on success. 
     318 */ 
     319PJ_DECL(pj_status_t) pjmedia_conf_adjust_rx_level( pjmedia_conf *conf, 
     320                                                   unsigned slot, 
     321                                                   int adj_level ); 
     322 
     323 
     324/** 
     325 * Adjust the level of signal to be transmitted to the specified port. 
     326 * Application may adjust the level to make the signal transmitted to the port 
     327 * either louder or more quiet, by giving the value from +127 to -128. The 
     328 * value zero indicates no adjustment, the value -128 will mute the signal,  
     329 * and the value of +127 will make the signal twice as loud. 
     330 * 
     331 * @param conf          The conference bridge. 
     332 * @param slot          Slot number. 
     333 * @param adj_level     Adjustment level, with valid values are from -128 
     334 *                      to +127. A value of zero means there is no level 
     335 *                      adjustment to be made, the value -128 will mute the  
     336 *                      signal, and the value of +127 will make the signal  
     337 *                      twice as loud. 
     338 * 
     339 * @return              PJ_SUCCESS on success. 
     340 */ 
     341PJ_DECL(pj_status_t) pjmedia_conf_adjust_tx_level( pjmedia_conf *conf, 
     342                                                   unsigned slot, 
     343                                                   int adj_level ); 
     344 
    227345 
    228346 
  • pjproject/trunk/pjmedia/src/pjmedia/conference.c

    r322 r323  
    2222#include <pjmedia/resample.h> 
    2323#include <pjmedia/silencedet.h> 
    24 #include <pjmedia/sound.h> 
     24#include <pjmedia/sound_port.h> 
    2525#include <pjmedia/stream.h> 
    2626#include <pj/assert.h> 
     
    4747 * 
    4848 * TX and RX directions are always viewed from the conference bridge's point 
    49  * of view, and NOT from the port's point of view.  
     49 * of view, and NOT from the port's point of view. So TX means the bridge 
     50 * is transmitting to the port, RX means the bridge is receiving from the 
     51 * port. 
    5052 */ 
    5153 
     
    6870    unsigned             samples_per_frame; /**< Port's samples per frame.  */ 
    6971 
     72    /* Calculated signal levels: */ 
     73    pj_bool_t            need_tx_level; /**< Need to calculate tx level?    */ 
     74    unsigned             tx_level;      /**< Last tx level to this port.    */ 
     75    unsigned             rx_level;      /**< Last rx level from this port.  */ 
     76 
     77    /* The normalized signal level adjustment. 
     78     * A value of 128 means there's no adjustment. 
     79     */ 
     80    unsigned             tx_adj_level;  /**< Adjustment for TX.             */ 
     81    unsigned             rx_adj_level;  /**< Adjustment for RX.             */ 
     82 
    7083    /* Resample, for converting clock rate, if they're different. */ 
    7184    pjmedia_resample    *rx_resample; 
     
    7487    /* RX buffer is temporary buffer to be used when there is mismatch 
    7588     * 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. 
     89     * or ptime. The buffer is used for sampling rate conversion AND/OR to 
     90     * buffer the samples until there are enough samples to fulfill a  
     91     * complete frame to be processed by the bridge. 
     92     * 
     93     * When both sample rate AND ptime of the port match the conference  
     94     * settings, this buffer will not be created. 
    7895     *  
    7996     * This buffer contains samples at port's clock rate. 
     
    86103 
    87104    /* Mix buf is a temporary buffer used to calculate the average signal 
    88      * received by this port from all other ports. 
     105     * received by this port from all other ports. Samples from all ports 
     106     * that are transmitting to this port will be accumulated here, then 
     107     * they will be divided by the sources count before the samples are put 
     108     * to the TX buffer of this port. 
    89109     * 
    90110     * This buffer contains samples at bridge's clock rate. 
     
    98118    /* Tx buffer is a temporary buffer to be used when there's mismatch  
    99119     * 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. 
     120     * or ptime. This buffer is used as the source of the sampling rate 
     121     * conversion AND/OR to buffer the samples until there are enough 
     122     * samples to fulfill a complete frame to be transmitted to the port. 
     123     * 
     124     * When both sample rate and ptime of the port match the bridge's  
     125     * settings, this buffer will not be created. 
    102126     *  
    103127     * This buffer contains samples at port's clock rate. 
     
    109133    unsigned             tx_buf_count;  /**< # of samples in the buffer.    */ 
    110134 
    111     /* Snd buffers is a special buffer for sound device port (port 0).  
    112      * It's not used by other ports. 
     135    /* Snd buffers is a special buffer for sound device port (port 0, master 
     136     * port). It's not used by other ports. 
    113137     * 
    114138     * There are multiple numbers of this buffer, because we can not expect 
     
    132156    unsigned              port_cnt;     /**< Current number of ports.       */ 
    133157    unsigned              connect_cnt;  /**< Total number of connections    */ 
    134     pjmedia_snd_stream   *snd_rec;      /**< Sound recorder stream.         */ 
    135     pjmedia_snd_stream   *snd_player;   /**< Sound player stream.           */ 
     158    pjmedia_snd_port     *snd_rec;      /**< Sound recorder stream.         */ 
     159    pjmedia_snd_port     *snd_player;   /**< Sound player stream.           */ 
     160    pjmedia_port         *master_port;  /**< Port zero's port.              */ 
    136161    pj_mutex_t           *mutex;        /**< Conference mutex.              */ 
    137162    struct conf_port    **ports;        /**< Array of ports.                */ 
     
    148173 
    149174/* Prototypes */ 
    150 static pj_status_t play_cb( /* in */  void *user_data, 
    151                             /* in */  pj_uint32_t timestamp, 
    152                             /* out */ void *output, 
    153                             /* out */ unsigned size); 
    154 static pj_status_t rec_cb(  /* in */  void *user_data, 
    155                             /* in */  pj_uint32_t timestamp, 
    156                             /* in */  const void *input, 
    157                             /* in*/   unsigned size); 
     175static pj_status_t put_frame(pjmedia_port *this_port,  
     176                             const pjmedia_frame *frame); 
     177static pj_status_t get_frame(pjmedia_port *this_port,  
     178                             pjmedia_frame *frame); 
     179 
    158180 
    159181/* 
     
    179201    conf_port->rx_setting = PJMEDIA_PORT_ENABLE; 
    180202    conf_port->tx_setting = PJMEDIA_PORT_ENABLE; 
     203 
     204    /* Default level adjustment is 128 (which means no adjustment) */ 
     205    conf_port->tx_adj_level = 128; 
     206    conf_port->rx_adj_level = 128; 
    181207 
    182208    /* Create transmit flag array */ 
     
    310336    conf->port_cnt++; 
    311337 
     338 
     339    /* Create sound devices: */ 
     340 
     341    /* Create recorder only if mic is not disabled. */ 
     342    if ((conf->options & PJMEDIA_CONF_NO_DEVICE) == 0 && 
     343        (conf->options & PJMEDIA_CONF_NO_MIC) == 0)  
     344    { 
     345        status = pjmedia_snd_port_create_rec( pool, -1, conf->clock_rate,  
     346                                              conf->channel_count,  
     347                                              conf->samples_per_frame, 
     348                                              conf->bits_per_sample, 
     349                                              0,    /* Options */ 
     350                                              &conf->snd_rec); 
     351        if (status != PJ_SUCCESS) { 
     352            conf->snd_rec = NULL; 
     353            return status; 
     354        } 
     355    } 
     356 
     357    /* Create player device */ 
     358    if ((conf->options & PJMEDIA_CONF_NO_DEVICE) == 0) { 
     359        status = pjmedia_snd_port_create_player(pool, -1, conf->clock_rate,  
     360                                                conf->channel_count, 
     361                                                conf->samples_per_frame, 
     362                                                conf->bits_per_sample,  
     363                                                0,      /* options */ 
     364                                                &conf->snd_player); 
     365        if (status != PJ_SUCCESS) { 
     366            if (conf->snd_rec) { 
     367                pjmedia_snd_port_destroy(conf->snd_rec); 
     368                conf->snd_rec = NULL; 
     369            } 
     370            conf->snd_player = NULL; 
     371            return status; 
     372        } 
     373    } 
     374 
     375 
    312376    PJ_LOG(5,(THIS_FILE, "Sound device successfully created for port 0")); 
    313377    return PJ_SUCCESS; 
     
    349413    conf->max_ports = max_ports; 
    350414    conf->clock_rate = clock_rate; 
     415    conf->channel_count = channel_count; 
    351416    conf->samples_per_frame = samples_per_frame; 
    352417    conf->bits_per_sample = bits_per_sample; 
     418 
     419     
     420    /* Create and initialize the master port interface. */ 
     421    conf->master_port = pj_pool_zalloc(pool, sizeof(pjmedia_port)); 
     422    PJ_ASSERT_RETURN(conf->master_port, PJ_ENOMEM); 
     423     
     424    conf->master_port->info.bits_per_sample = bits_per_sample; 
     425    conf->master_port->info.bytes_per_frame = samples_per_frame * 
     426                                              bits_per_sample / 8; 
     427    conf->master_port->info.channel_count = channel_count; 
     428    conf->master_port->info.encoding_name = pj_str("pcm"); 
     429    conf->master_port->info.has_info = 1; 
     430    conf->master_port->info.name = pj_str("master port"); 
     431    conf->master_port->info.need_info = 0; 
     432    conf->master_port->info.pt = 0xFF; 
     433    conf->master_port->info.sample_rate = clock_rate; 
     434    conf->master_port->info.samples_per_frame = samples_per_frame; 
     435    conf->master_port->info.signature = 0; 
     436    conf->master_port->info.type = PJMEDIA_TYPE_AUDIO; 
     437 
     438    conf->master_port->get_frame = &get_frame; 
     439    conf->master_port->put_frame = &put_frame; 
     440 
     441    conf->master_port->user_data = conf; 
    353442 
    354443 
     
    367456        return status; 
    368457 
     458    /* If sound device was created, connect sound device to the 
     459     * master port. 
     460     */ 
     461    if (conf->snd_player) { 
     462        status = pjmedia_snd_port_connect( conf->snd_player,  
     463                                           conf->master_port ); 
     464        if (status != PJ_SUCCESS) { 
     465            pjmedia_conf_destroy(conf); 
     466            return status; 
     467        } 
     468    } 
     469 
     470    if (conf->snd_rec) { 
     471        status = pjmedia_snd_port_connect( conf->snd_rec, 
     472                                           conf->master_port); 
     473        if (status != PJ_SUCCESS) { 
     474            pjmedia_conf_destroy(conf); 
     475            return status; 
     476        } 
     477    } 
     478 
    369479 
    370480    /* Done */ 
     
    377487 
    378488/* 
    379  * Create sound device 
    380  */ 
    381 static pj_status_t create_sound( pjmedia_conf *conf ) 
    382 { 
    383     pj_status_t status; 
    384  
    385     /* Open recorder only if mic is not disabled. */ 
    386     if ((conf->options & PJMEDIA_CONF_NO_MIC) == 0) { 
    387         status = pjmedia_snd_open_recorder(-1, conf->clock_rate, 1,  
    388                                       conf->samples_per_frame, 
    389                                       conf->bits_per_sample, 
    390                                       &rec_cb, conf, &conf->snd_rec); 
    391         if (status != PJ_SUCCESS) { 
    392             conf->snd_rec = NULL; 
    393             return status; 
    394         } 
    395     } 
    396  
    397     /* Open player */ 
    398     status = pjmedia_snd_open_player(-1, conf->clock_rate, 1, 
    399                                 conf->samples_per_frame, 
    400                                 conf->bits_per_sample,  
    401                                 &play_cb, conf, &conf->snd_player); 
    402     if (status != PJ_SUCCESS) { 
    403         if (conf->snd_rec) { 
    404             pjmedia_snd_stream_close(conf->snd_rec); 
    405             conf->snd_rec = NULL; 
    406         } 
    407         conf->snd_player = NULL; 
    408         return status; 
    409     } 
    410  
    411     return PJ_SUCCESS; 
    412 } 
    413  
    414 /* 
    415  * Destroy sound device 
    416  */ 
    417 static pj_status_t destroy_sound( pjmedia_conf *conf ) 
    418 { 
    419     if (conf->snd_rec) { 
    420         pjmedia_snd_stream_close(conf->snd_rec); 
    421         conf->snd_rec = NULL; 
    422     } 
    423     if (conf->snd_player) { 
    424         pjmedia_snd_stream_close(conf->snd_player); 
    425         conf->snd_player = NULL; 
    426     } 
    427     return PJ_SUCCESS; 
    428 } 
    429  
    430 /* 
    431  * Activate sound device. 
     489 * Pause sound device. 
     490 */ 
     491static pj_status_t pause_sound( pjmedia_conf *conf ) 
     492{ 
     493    /* Do nothing. */ 
     494    PJ_UNUSED_ARG(conf); 
     495    return PJ_SUCCESS; 
     496} 
     497 
     498/* 
     499 * Resume sound device. 
    432500 */ 
    433501static pj_status_t resume_sound( pjmedia_conf *conf ) 
    434502{ 
    435     char errmsg[PJ_ERR_MSG_SIZE]; 
    436     pj_status_t status; 
    437  
    438     if (conf->snd_player == NULL) { 
    439         status = create_sound(conf); 
    440         if (status != PJ_SUCCESS) 
    441             return status; 
    442     } 
    443  
    444     /* Start recorder. */ 
    445     if (conf->snd_rec) { 
    446         status = pjmedia_snd_stream_start(conf->snd_rec); 
    447         if (status != PJ_SUCCESS) 
    448             goto on_error; 
    449     } 
    450  
    451     /* Start player. */ 
    452     if (conf->snd_player) { 
    453         status = pjmedia_snd_stream_start(conf->snd_player); 
    454         if (status != PJ_SUCCESS) 
    455             goto on_error; 
    456     } 
    457  
    458     return PJ_SUCCESS; 
    459  
    460 on_error: 
    461     pj_strerror(status, errmsg, sizeof(errmsg)); 
    462     PJ_LOG(4,(THIS_FILE, "Error starting sound player/recorder: %s", 
    463               errmsg)); 
    464     return status; 
     503    /* Do nothing. */ 
     504    PJ_UNUSED_ARG(conf); 
     505    return PJ_SUCCESS; 
    465506} 
    466507 
     
    473514    PJ_ASSERT_RETURN(conf != NULL, PJ_EINVAL); 
    474515 
    475     //suspend_sound(conf); 
    476     destroy_sound(conf); 
     516    /* Destroy sound devices. */ 
     517    if (conf->snd_rec) { 
     518        pjmedia_snd_port_destroy(conf->snd_rec); 
     519        conf->snd_rec = NULL; 
     520    } 
     521    if (conf->snd_player) { 
     522        pjmedia_snd_port_destroy(conf->snd_player); 
     523        conf->snd_player = NULL; 
     524    } 
     525 
     526    /* Destroy mutex */ 
    477527    pj_mutex_destroy(conf->mutex); 
    478528 
    479529    return PJ_SUCCESS; 
     530} 
     531 
     532 
     533/* 
     534 * Get port zero interface. 
     535 */ 
     536PJ_DEF(pjmedia_port*) pjmedia_conf_get_master_port(pjmedia_conf *conf) 
     537{ 
     538    /* Sanity check. */ 
     539    PJ_ASSERT_RETURN(conf != NULL, NULL); 
     540 
     541    /* Can only return port interface when PJMEDIA_CONF_NO_DEVICE was 
     542     * present in the option. 
     543     */ 
     544    PJ_ASSERT_RETURN((conf->options & PJMEDIA_CONF_NO_DEVICE) != 0, NULL); 
     545     
     546    return conf->master_port; 
    480547} 
    481548 
     
    520587    pj_assert(index != conf->max_ports); 
    521588 
    522     /* Create port structure. */ 
     589    /* Create conf port structure. */ 
    523590    status = create_conf_port(pool, conf, strm_port, port_name, &conf_port); 
    524591    if (status != PJ_SUCCESS) { 
     
    575642PJ_DEF(pj_status_t) pjmedia_conf_connect_port( pjmedia_conf *conf, 
    576643                                               unsigned src_slot, 
    577                                                unsigned sink_slot ) 
     644                                               unsigned sink_slot, 
     645                                               int level ) 
    578646{ 
    579647    struct conf_port *src_port, *dst_port; 
     
    587655    PJ_ASSERT_RETURN(conf->ports[src_slot] != NULL, PJ_EINVAL); 
    588656    PJ_ASSERT_RETURN(conf->ports[sink_slot] != NULL, PJ_EINVAL); 
     657 
     658    /* For now, level MUST be zero. */ 
     659    PJ_ASSERT_RETURN(level == 0, PJ_EINVAL); 
    589660 
    590661    pj_mutex_lock(conf->mutex); 
     
    659730 
    660731    if (conf->connect_cnt == 0) { 
    661         destroy_sound(conf); 
     732        pause_sound(conf); 
    662733    } 
    663734 
     
    724795    /* Stop sound if there's no connection. */ 
    725796    if (conf->connect_cnt == 0) { 
    726         destroy_sound(conf); 
     797        pause_sound(conf); 
    727798    } 
    728799 
     
    780851 
    781852 
     853/* 
     854 * Get signal level. 
     855 */ 
     856PJ_DEF(pj_status_t) pjmedia_conf_get_signal_level( pjmedia_conf *conf, 
     857                                                   unsigned slot, 
     858                                                   unsigned *tx_level, 
     859                                                   unsigned *rx_level) 
     860{ 
     861    struct conf_port *conf_port; 
     862 
     863    /* Check arguments */ 
     864    PJ_ASSERT_RETURN(conf && slot<conf->max_ports, PJ_EINVAL); 
     865 
     866    /* Port must be valid. */ 
     867    PJ_ASSERT_RETURN(conf->ports[slot] != NULL, PJ_EINVAL); 
     868 
     869    conf_port = conf->ports[slot]; 
     870 
     871    if (tx_level != NULL) { 
     872        conf_port->need_tx_level = 1; 
     873        *tx_level = conf_port->tx_level; 
     874    } 
     875 
     876    if (rx_level != NULL)  
     877        *rx_level = conf_port->rx_level; 
     878 
     879    return PJ_SUCCESS; 
     880} 
     881 
     882 
     883/* 
     884 * Adjust RX level of individual port. 
     885 */ 
     886PJ_DEF(pj_status_t) pjmedia_conf_adjust_rx_level( pjmedia_conf *conf, 
     887                                                  unsigned slot, 
     888                                                  int adj_level ) 
     889{ 
     890    struct conf_port *conf_port; 
     891 
     892    /* Check arguments */ 
     893    PJ_ASSERT_RETURN(conf && slot<conf->max_ports, PJ_EINVAL); 
     894 
     895    /* Port must be valid. */ 
     896    PJ_ASSERT_RETURN(conf->ports[slot] != NULL, PJ_EINVAL); 
     897 
     898    /* Value must be from -128 to +127 */ 
     899    PJ_ASSERT_RETURN(adj_level >= -128 && adj_level <= 127, PJ_EINVAL); 
     900 
     901    conf_port = conf->ports[slot]; 
     902 
     903    /* Set normalized adjustment level. */ 
     904    conf_port->rx_adj_level = adj_level + 128; 
     905 
     906    return PJ_SUCCESS; 
     907} 
     908 
     909 
     910/* 
     911 * Adjust TX level of individual port. 
     912 */ 
     913PJ_DEF(pj_status_t) pjmedia_conf_adjust_tx_level( pjmedia_conf *conf, 
     914                                                  unsigned slot, 
     915                                                  int adj_level ) 
     916{ 
     917    struct conf_port *conf_port; 
     918 
     919    /* Check arguments */ 
     920    PJ_ASSERT_RETURN(conf && slot<conf->max_ports, PJ_EINVAL); 
     921 
     922    /* Port must be valid. */ 
     923    PJ_ASSERT_RETURN(conf->ports[slot] != NULL, PJ_EINVAL); 
     924 
     925    /* Value must be from -128 to +127 */ 
     926    PJ_ASSERT_RETURN(adj_level >= -128 && adj_level <= 127, PJ_EINVAL); 
     927 
     928    conf_port = conf->ports[slot]; 
     929 
     930    /* Set normalized adjustment level. */ 
     931    conf_port->tx_adj_level = adj_level + 128; 
     932 
     933    return PJ_SUCCESS; 
     934} 
     935 
     936 
    782937/* Convert signed 16bit pcm sample to unsigned 16bit sample */ 
    783938static pj_uint16_t pcm2unsigned(pj_int32_t pcm) 
     
    9251080            pjmedia_port_put_frame(cport->port, &frame); 
    9261081 
     1082        cport->tx_level = 0; 
    9271083        return PJ_SUCCESS; 
    9281084 
    9291085    } else if (cport->tx_setting != PJMEDIA_PORT_ENABLE) { 
     1086        cport->tx_level = 0; 
    9301087        return PJ_SUCCESS; 
    9311088    } 
     
    9341091     * to the mixed samples itself. This is possible because mixed sample 
    9351092     * is 32bit. 
     1093     * 
     1094     * In addition to this process, if we need to change the level of 
     1095     * TX signal, we adjust is here too. 
    9361096     */ 
    9371097    buf = (pj_int16_t*)cport->mix_buf; 
    938     for (j=0; j<conf->samples_per_frame; ++j) { 
    939         buf[j] = unsigned2pcm(cport->mix_buf[j] / cport->sources); 
     1098 
     1099    if (cport->tx_adj_level != 128) { 
     1100 
     1101        unsigned adj_level = cport->tx_adj_level; 
     1102 
     1103        /* We need to adjust signal level. */ 
     1104        for (j=0; j<conf->samples_per_frame; ++j) { 
     1105            pj_int32_t itemp; 
     1106 
     1107            /* Calculate average level, and convert the sample to 
     1108             * 16bit signed integer. 
     1109             */ 
     1110            itemp = unsigned2pcm(cport->mix_buf[j] / cport->sources); 
     1111 
     1112            /* Adjust the level */ 
     1113            itemp = itemp * adj_level / 128; 
     1114 
     1115            /* Clip the signal if it's too loud */ 
     1116            if (itemp > 32767) itemp = 32767; 
     1117            else if (itemp < -32768) itemp = -32768; 
     1118 
     1119            /* Put back in the buffer. */ 
     1120            buf[j] = (pj_int16_t) itemp; 
     1121        } 
     1122 
     1123    } else { 
     1124        /* No need to adjust signal level. */ 
     1125        for (j=0; j<conf->samples_per_frame; ++j) { 
     1126            buf[j] = unsigned2pcm(cport->mix_buf[j] / cport->sources); 
     1127        } 
     1128    } 
     1129 
     1130    /* Calculate TX level if we need to do so.  
     1131     * This actually is not the most correct place to calculate TX signal  
     1132     * level of the port; it should calculate the level of the actual 
     1133     * frame just before put_frame() is called. 
     1134     * But doing so would make the code more complicated than it is 
     1135     * necessary, since the purpose of level calculation mostly is just 
     1136     * for VU meter display. By doing it here, it should give the acceptable 
     1137     * indication of the signal level of the port. 
     1138     */ 
     1139    if (cport->need_tx_level) { 
     1140        pj_uint32_t level; 
     1141 
     1142        /* Get the signal level. */ 
     1143        level = pjmedia_calc_avg_signal(buf, conf->samples_per_frame); 
     1144 
     1145        /* Convert level to 8bit complement ulaw */ 
     1146        cport->tx_level = linear2ulaw(level) ^ 0xff; 
     1147 
     1148    } else { 
     1149        cport->tx_level = 0; 
    9401150    } 
    9411151 
     
    10131223 * Player callback. 
    10141224 */ 
    1015 static pj_status_t play_cb( /* in */  void *user_data, 
    1016                             /* in */  pj_uint32_t timestamp, 
    1017                             /* out */ void *output, 
    1018                             /* out */ unsigned size) 
    1019 { 
    1020     pjmedia_conf *conf = user_data; 
     1225static pj_status_t get_frame(pjmedia_port *this_port,  
     1226                             pjmedia_frame *frame) 
     1227{ 
     1228    pjmedia_conf *conf = this_port->user_data; 
    10211229    unsigned ci, cj, i, j; 
    10221230     
    1023     PJ_UNUSED_ARG(timestamp); 
    1024     PJ_UNUSED_ARG(size); 
    1025  
     1231    /* Check that correct size is specified. */ 
     1232    pj_assert(frame->size == conf->samples_per_frame * 
     1233                             conf->bits_per_sample / 8); 
     1234 
     1235    /* Must lock mutex (must we??) */ 
    10261236    pj_mutex_lock(conf->mutex); 
    10271237 
     
    10571267            continue; 
    10581268 
     1269        /* Var "ci" is to count how many ports have been visited so far. */ 
    10591270        ++ci; 
    10601271 
    10611272        /* Skip if we're not allowed to receive from this port. */ 
    10621273        if (conf_port->rx_setting == PJMEDIA_PORT_DISABLE) { 
     1274            conf_port->rx_level = 0; 
    10631275            continue; 
    10641276        } 
    10651277 
    10661278        /* Also skip if this port doesn't have listeners. */ 
    1067         if (conf_port->listener_cnt == 0) 
     1279        if (conf_port->listener_cnt == 0) { 
     1280            conf_port->rx_level = 0; 
    10681281            continue; 
     1282        } 
    10691283 
    10701284        /* Get frame from this port.  
     
    10831297            /* Skip if this port is muted/disabled. */ 
    10841298            if (conf_port->rx_setting != PJMEDIA_PORT_ENABLE) { 
     1299                conf_port->rx_level = 0; 
    10851300                continue; 
    10861301            } 
    10871302 
    1088  
    1089             /* Skip if no port is listening to the microphone */ 
    1090             if (conf_port->listener_cnt == 0) { 
    1091                 continue; 
    1092             } 
    1093  
    10941303            snd_buf = conf_port->snd_buf[conf_port->snd_read_pos]; 
    10951304            for (j=0; j<conf->samples_per_frame; ++j) { 
    1096                 ((pj_int16_t*)output)[j] = snd_buf[j]; 
     1305                ((pj_int16_t*)frame->buf)[j] = snd_buf[j]; 
    10971306            } 
    10981307            conf_port->snd_read_pos = (conf_port->snd_read_pos+1) % RX_BUF_COUNT; 
     
    11031312            pjmedia_frame_type frame_type; 
    11041313 
    1105             status = read_port(conf, conf_port, output,  
     1314            status = read_port(conf, conf_port, frame->buf,  
    11061315                               conf->samples_per_frame, &frame_type); 
    11071316             
     
    11171326        } 
    11181327 
    1119         /* Get the signal level. */ 
    1120         level = pjmedia_calc_avg_signal(output, conf->samples_per_frame); 
     1328        /* If we need to adjust the RX level from this port, adjust the level 
     1329         * and calculate the average level at the same time. 
     1330         * Otherwise just calculate the averate level. 
     1331         */ 
     1332        if (conf_port->rx_adj_level != 128) { 
     1333            pj_int16_t *input = frame->buf; 
     1334            pj_int32_t adj = conf_port->rx_adj_level; 
     1335 
     1336            level = 0; 
     1337            for (j=0; j<conf->samples_per_frame; ++j) { 
     1338                pj_int32_t itemp; 
     1339 
     1340                /* For the level adjustment, we need to store the sample to 
     1341                 * a temporary 32bit integer value to avoid overflowing the 
     1342                 * 16bit sample storage. 
     1343                 */ 
     1344                itemp = input[j]; 
     1345                itemp = itemp * adj / 128; 
     1346 
     1347                /* Clip the signal if it's too loud */ 
     1348                if (itemp > 32767) itemp = 32767; 
     1349                else if (itemp < -32768) itemp = -32768; 
     1350 
     1351                input[j] = (pj_int16_t) itemp; 
     1352                level += itemp; 
     1353            } 
     1354 
     1355            level /= conf->samples_per_frame; 
     1356 
     1357        } else { 
     1358            level = pjmedia_calc_avg_signal(frame->buf,  
     1359                                            conf->samples_per_frame); 
     1360        } 
    11211361 
    11221362        /* Convert level to 8bit complement ulaw */ 
    11231363        level = linear2ulaw(level) ^ 0xff; 
    11241364 
     1365        /* Put this level to port's last RX level. */ 
     1366        conf_port->rx_level = level; 
     1367 
    11251368        /* Convert the buffer to unsigned 16bit value */ 
    11261369        for (j=0; j<conf->samples_per_frame; ++j) 
    1127             conf->uns_buf[j] = pcm2unsigned(((pj_int16_t*)output)[j]); 
     1370            conf->uns_buf[j] = pcm2unsigned(((pj_int16_t*)frame->buf)[j]); 
    11281371 
    11291372        /* Add the signal to all listeners. */ 
     
    11431386                continue; 
    11441387 
     1388            /* Var "cj" is the number of listeners we have visited so far */ 
    11451389            ++cj; 
    11461390 
     
    11581402    } 
    11591403 
    1160     /* For all ports, calculate avg signal. */ 
     1404    /* Time for all ports to transmit whetever they have in their 
     1405     * buffer.  
     1406     */ 
    11611407    for (i=0, ci=0; i<conf->max_ports && ci<conf->port_cnt; ++i) { 
    11621408        struct conf_port *conf_port = conf->ports[i]; 
     
    11661412            continue; 
    11671413 
     1414        /* Var "ci" is to count how many ports have been visited. */ 
    11681415        ++ci; 
    11691416 
    1170         status = write_port( conf, conf_port, timestamp); 
     1417        status = write_port( conf, conf_port, frame->timestamp.u32.lo); 
    11711418        if (status != PJ_SUCCESS) { 
    11721419            PJ_LOG(4,(THIS_FILE, "Port %.*s put_frame() returned %d. " 
     
    11821429    /* Return sound playback frame. */ 
    11831430    if (conf->ports[0]->sources) { 
    1184         copy_samples( output, (pj_int16_t*)conf->ports[0]->mix_buf,  
     1431        copy_samples( frame->buf, (pj_int16_t*)conf->ports[0]->mix_buf,  
    11851432                      conf->samples_per_frame); 
    11861433    } else { 
    1187         zero_samples( output, conf->samples_per_frame );  
     1434        zero_samples( frame->buf, conf->samples_per_frame );  
    11881435    } 
    11891436 
     
    11971444 * Recorder callback. 
    11981445 */ 
    1199 static pj_status_t rec_cb(  /* in */  void *user_data, 
    1200                             /* in */  pj_uint32_t timestamp, 
    1201                             /* in */  const void *input, 
    1202                             /* in */  unsigned size) 
    1203 { 
    1204     pjmedia_conf *conf = user_data; 
     1446static pj_status_t put_frame(pjmedia_port *this_port,  
     1447                             const pjmedia_frame *frame) 
     1448{ 
     1449    pjmedia_conf *conf = this_port->user_data; 
    12051450    struct conf_port *snd_port = conf->ports[0]; 
     1451    const pj_int16_t *input = frame->buf; 
    12061452    pj_int16_t *target_snd_buf; 
    12071453    unsigned i; 
    12081454 
    1209     PJ_UNUSED_ARG(timestamp); 
    1210      
    12111455    TRACE_(("r")); 
    12121456 
    1213     if (size != conf->samples_per_frame*2) { 
    1214         TRACE_(("rxerr ")); 
    1215     } 
     1457    /* Check for correct size. */ 
     1458    PJ_ASSERT_RETURN( frame->size == conf->samples_per_frame * 
     1459                                     conf->bits_per_sample / 8, 
     1460                      PJMEDIA_ENCSAMPLESPFRAME); 
    12161461 
    12171462    /* Skip if this port is muted/disabled. */ 
  • pjproject/trunk/pjmedia/src/pjmedia/resample.c

    r299 r323  
    2020/* 
    2121 * Based on: 
    22  * resample-1.2.tar.Z (from ftp://ccrma-ftp.stanford.edu/pub/NeXT) 
     22 * resample-1.8.tar.gz from the  
     23 * Digital Audio Resampling Home Page located at 
     24 * http://www-ccrma.stanford.edu/~jos/resample/. 
     25 * 
    2326 * SOFTWARE FOR SAMPLING-RATE CONVERSION AND FIR DIGITAL FILTER DESIGN 
    2427 * 
    25  * COPYING 
    26  *  
    27  * This software package is Copyright 1994 by Julius O. Smith 
    28  * (jos@ccrma.stanford.edu), all rights reserved.  Permission to use and copy 
    29  * is granted subject to the terms of the "GNU Software General Public 
    30  * License" (see ftp://prep.ai.mit.edu/pub/gnu/COPYING).  In addition, we 
    31  * request that a copy of any modified files be sent by email to 
    32  * jos@ccrma.stanford.edu so that we may incorporate them in the CCRMA 
    33  * version. 
     28 * Snippet from the resample.1 man page: 
     29 *  
     30 * HISTORY 
     31 * 
     32 * The first version of this software was written by Julius O. Smith III 
     33 * <jos@ccrma.stanford.edu> at CCRMA <http://www-ccrma.stanford.edu> in 
     34 * 1981.  It was called SRCONV and was written in SAIL for PDP-10 
     35 * compatible machines.  The algorithm was first published in 
     36 *  
     37 * Smith, Julius O. and Phil Gossett. ``A Flexible Sampling-Rate 
     38 * Conversion Method,'' Proceedings (2): 19.4.1-19.4.4, IEEE Conference 
     39 * on Acoustics, Speech, and Signal Processing, San Diego, March 1984. 
     40 *  
     41 * An expanded tutorial based on this paper is available at the Digital 
     42 * Audio Resampling Home Page given above. 
     43 *  
     44 * Circa 1988, the SRCONV program was translated from SAIL to C by 
     45 * Christopher Lee Fraley working with Roger Dannenberg at CMU. 
     46 *  
     47 * Since then, the C version has been maintained by jos. 
     48 *  
     49 * Sndlib support was added 6/99 by John Gibson <jgg9c@virginia.edu>. 
     50 *  
     51 * The resample program is free software distributed in accordance 
     52 * with the Lesser GNU Public License (LGPL).  There is NO warranty; not 
     53 * even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
    3454 */ 
    3555 
  • pjproject/trunk/pjsip-apps/src/pjsua/main.c

    r315 r323  
    813813                        status = pjmedia_conf_connect_port(pjsua.mconf,  
    814814                                                           atoi(src_port),  
    815                                                            atoi(dst_port)); 
     815                                                           atoi(dst_port), 
     816                                                           0); 
    816817                    } else { 
    817818                        status = pjmedia_conf_disconnect_port(pjsua.mconf,  
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c

    r305 r323  
    962962 
    963963        pjmedia_conf_connect_port( pjsua.mconf, pjsua.wav_slot,  
    964                                    call->conf_slot); 
     964                                   call->conf_slot, 0); 
    965965 
    966966    } else if (pjsua.auto_loop && call->inv->role == PJSIP_ROLE_UAS) { 
    967967 
    968968        pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot,  
    969                                    call->conf_slot); 
     969                                   call->conf_slot, 0); 
    970970 
    971971    } else if (pjsua.auto_conf) { 
     
    973973        int i; 
    974974 
    975         pjmedia_conf_connect_port( pjsua.mconf, 0, call->conf_slot); 
    976         pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot, 0); 
     975        pjmedia_conf_connect_port( pjsua.mconf, 0, call->conf_slot, 0); 
     976        pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot, 0, 0); 
    977977 
    978978        for (i=0; i < pjsua.max_calls; ++i) { 
     
    982982 
    983983            pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot,  
    984                                        pjsua.calls[i].conf_slot); 
     984                                       pjsua.calls[i].conf_slot, 0); 
    985985            pjmedia_conf_connect_port( pjsua.mconf, pjsua.calls[i].conf_slot, 
    986                                        call->conf_slot); 
     986                                       call->conf_slot, 0); 
    987987        } 
    988988 
     
    992992         * main conference bridge. 
    993993         */ 
    994         pjmedia_conf_connect_port( pjsua.mconf, 0, call->conf_slot); 
    995         pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot, 0); 
     994        pjmedia_conf_connect_port( pjsua.mconf, 0, call->conf_slot, 0); 
     995        pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot, 0, 0); 
    996996    } 
    997997 
Note: See TracChangeset for help on using the changeset viewer.