Changeset 205 for pjproject/trunk


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

Initial conference implementation

Location:
pjproject/trunk
Files:
4 added
18 edited
2 moved

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjmedia/build/pjmedia.dsp

    r203 r205  
    6666# PROP Target_Dir "" 
    6767# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c 
    68 # ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "../include" /I "../../pjlib/include" /I "../../pjlib-util/include" /I "../src/pjmedia/portaudio" /D "_DEBUG" /D "PA_NO_ASIO" /D "WIN32" /D "_MBCS" /D "_LIB" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /FD /GZ /c 
     68# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "../include" /I "../../pjlib/include" /I "../../pjlib-util/include" /I "../src/pjmedia/portaudio" /D "_DEBUG" /D "PA_NO_ASIO" /D "PA_NO_WIN_DS" /D "WIN32" /D "_MBCS" /D "_LIB" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /FD /GZ /c 
    6969# SUBTRACT CPP /YX 
    7070# ADD BASE RSC /l 0x409 /d "_DEBUG" 
     
    8888# Begin Source File 
    8989 
    90 SOURCE=..\src\pjmedia\audio_conf.c 
    91 # End Source File 
    92 # Begin Source File 
    93  
    9490SOURCE=..\src\pjmedia\codec.c 
     91# End Source File 
     92# Begin Source File 
     93 
     94SOURCE=..\src\pjmedia\conference.c 
    9595# End Source File 
    9696# Begin Source File 
     
    126126# Begin Source File 
    127127 
     128SOURCE=..\src\pjmedia\port.c 
     129# End Source File 
     130# Begin Source File 
     131 
    128132SOURCE=..\src\pjmedia\rtcp.c 
    129133# End Source File 
     
    131135 
    132136SOURCE=..\src\pjmedia\rtp.c 
     137# End Source File 
     138# Begin Source File 
     139 
     140SOURCE=..\src\pjmedia\rtp_port.c 
    133141# End Source File 
    134142# Begin Source File 
     
    162170# Begin Source File 
    163171 
    164 SOURCE=..\include\pjmedia\audio_conf.h 
    165 # End Source File 
    166 # Begin Source File 
    167  
    168172SOURCE=..\include\pjmedia\codec.h 
    169173# End Source File 
    170174# Begin Source File 
    171175 
     176SOURCE=..\include\pjmedia\conference.h 
     177# End Source File 
     178# Begin Source File 
     179 
    172180SOURCE=..\include\pjmedia\config.h 
    173181# End Source File 
     
    194202# Begin Source File 
    195203 
     204SOURCE=..\include\pjmedia\port.h 
     205# End Source File 
     206# Begin Source File 
     207 
    196208SOURCE=..\include\pjmedia\rtcp.h 
    197209# End Source File 
     
    199211 
    200212SOURCE=..\include\pjmedia\rtp.h 
     213# End Source File 
     214# Begin Source File 
     215 
     216SOURCE=..\include\pjmedia\rtp_port.h 
    201217# End Source File 
    202218# Begin Source File 
  • pjproject/trunk/pjmedia/include/pjmedia.h

    r188 r205  
    2626 
    2727#include <pjmedia/types.h> 
     28#include <pjmedia/codec.h> 
     29#include <pjmedia/conference.h> 
     30#include <pjmedia/endpoint.h> 
    2831#include <pjmedia/errno.h> 
    29 #include <pjmedia/codec.h> 
    3032#include <pjmedia/jbuf.h> 
    31 #include <pjmedia/endpoint.h> 
     33#include <pjmedia/port.h> 
    3234#include <pjmedia/rtcp.h> 
    3335#include <pjmedia/rtp.h> 
     36#include <pjmedia/sdp.h> 
     37#include <pjmedia/sdp_neg.h> 
    3438#include <pjmedia/session.h> 
    3539#include <pjmedia/sound.h> 
    36 #include <pjmedia/sdp.h> 
    37 #include <pjmedia/sdp_neg.h> 
    3840 
    3941#endif  /* __PJMEDIA_H__ */ 
  • pjproject/trunk/pjmedia/include/pjmedia/codec.h

    r189 r205  
    120120 
    121121 
    122 /**  
    123  * Types of media frame.  
    124  */ 
    125 enum pjmedia_frame_type 
    126 { 
    127     PJMEDIA_FRAME_TYPE_SILENCE_AUDIO,   /**< Silence audio frame.       */ 
    128     PJMEDIA_FRAME_TYPE_AUDIO,           /**< Normal audio frame.        */ 
    129  
    130 }; 
    131  
    132 /**  
    133  * This structure describes a media frame.  
    134  */ 
    135 struct pjmedia_frame 
    136 { 
    137     pjmedia_frame_type   type;  /**< Frame type.                    */ 
    138     void                *buf;   /**< Pointer to buffer.             */ 
    139     pj_size_t            size;  /**< Frame size in bytes.           */ 
    140 }; 
    141  
    142122/** 
    143123 * This structure describes codec operations. Each codec MUST implement 
  • pjproject/trunk/pjmedia/include/pjmedia/conference.h

    r203 r205  
    2222 
    2323/** 
    24  * @file conf.h 
     24 * @file conference.h 
    2525 * @brief Conference bridge. 
    2626 */ 
    27 #include <pjmedia/types.h> 
     27#include <pjmedia/port.h> 
     28 
     29 
     30PJ_BEGIN_DECL 
     31 
    2832 
    2933/** 
     
    3236typedef struct pjmedia_conf pjmedia_conf; 
    3337 
     38/** 
     39 * Conference port info. 
     40 */ 
     41typedef struct pjmedia_conf_port_info 
     42{ 
     43    pj_str_t            name; 
     44    pjmedia_port_op     tx_setting; 
     45    pjmedia_port_op     rx_setting; 
     46    pj_bool_t          *listener; 
     47} pjmedia_conf_port_info; 
     48 
    3449 
    3550/** 
     
    3752 */ 
    3853PJ_DECL(pj_status_t) pjmedia_conf_create( pj_pool_t *pool, 
    39                                           unsigned max_ports, 
     54                                          unsigned max_slots, 
     55                                          unsigned sampling_rate, 
     56                                          unsigned samples_per_frame, 
     57                                          unsigned bits_per_sample, 
    4058                                          pjmedia_conf **p_conf ); 
    4159 
    4260 
    4361/** 
    44  * Add stream port to the conference bridge. 
     62 * Destroy conference bridge. 
     63 */ 
     64PJ_DECL(pj_status_t) pjmedia_conf_destroy( pjmedia_conf *conf ); 
     65 
     66 
     67/** 
     68 * Add stream port to the conference bridge. By default, the new conference 
     69 * port will have both TX and RX enabled, but it is not connected to any 
     70 * other ports. 
     71 * 
     72 * Application SHOULD call #pjmedia_conf_connect_port() to enable audio 
     73 * transmission and receipt to/from this port. 
     74 * 
     75 * @param conf          The conference bridge. 
     76 * @param pool          Pool to allocate buffers for this port. 
     77 * @param strm_port     Stream port interface. 
     78 * @param name          Port name. 
     79 * @param p_slot        Pointer to receive the slot index of the port in 
     80 *                      the conference bridge. 
     81 * 
     82 * @return              PJ_SUCCESS on success. 
    4583 */ 
    4684PJ_DECL(pj_status_t) pjmedia_conf_add_port( pjmedia_conf *conf, 
    4785                                            pj_pool_t *pool, 
    48                                             pjmedia_stream_port *strm_port, 
    49                                             const pj_str_t *port_name, 
    50                                             unsigned *p_port ); 
     86                                            pjmedia_port *strm_port, 
     87                                            const pj_str_t *name, 
     88                                            unsigned *p_slot ); 
     89 
    5190 
    5291 
    5392/** 
    54  * Mute or unmute port. 
     93 * Change TX and RX settings for the port. 
     94 * 
     95 * @param conf          The conference bridge. 
     96 * @param slot          Port number/slot in the conference bridge. 
     97 * @param tx            Settings for the transmission TO this port. 
     98 * @param rx            Settings for the receipt FROM this port. 
     99 * 
     100 * @return              PJ_SUCCESS on success. 
    55101 */ 
    56 PJ_DECL(pj_status_t) pjmedia_conf_set_mute( pjmedia_conf *conf, 
    57                                             unsigned port, 
    58                                             pj_bool_t mute ); 
     102PJ_DECL(pj_status_t) pjmedia_conf_configure_port( pjmedia_conf *conf, 
     103                                                  unsigned slot, 
     104                                                  pjmedia_port_op tx, 
     105                                                  pjmedia_port_op rx); 
    59106 
    60107 
    61108/** 
    62  * Set the specified port to be member of conference bridge. 
     109 * Enable unidirectional audio from the specified source slot to the 
     110 * specified sink slot. 
     111 * 
     112 * @param conf          The conference bridge. 
     113 * @param src_slot      Source slot. 
     114 * @param sink_slot     Sink slot. 
     115 * 
     116 * @return              PJ_SUCCES on success. 
    63117 */ 
    64 PJ_DECL(pj_status_t) pjmedia_conf_set_membership( pjmedia_conf *conf, 
    65                                                   unsigned port, 
    66                                                   pj_bool_t enabled ); 
     118PJ_DECL(pj_status_t) pjmedia_conf_connect_port( pjmedia_conf *conf, 
     119                                                unsigned src_slot, 
     120                                                unsigned sink_slot ); 
    67121 
    68122 
    69123/** 
    70  * Remove the specified port. 
     124 * Disconnect unidirectional audio from the specified source to the specified 
     125 * sink slot. 
     126 * 
     127 * @param conf          The conference bridge. 
     128 * @param src_slot      Source slot. 
     129 * @param sink_slot     Sink slot. 
     130 * 
     131 * @reutrn              PJ_SUCCESS on success. 
     132 */ 
     133PJ_DECL(pj_status_t) pjmedia_conf_disconnect_port( pjmedia_conf *conf, 
     134                                                   unsigned src_slot, 
     135                                                   unsigned sink_slot ); 
     136 
     137 
     138/** 
     139 * Remove the specified port from the conference bridge. 
     140 * 
     141 * @param conf          The conference bridge. 
     142 * @param slot          The port index to be removed. 
     143 * 
     144 * @return              PJ_SUCCESS on success. 
    71145 */ 
    72146PJ_DECL(pj_status_t) pjmedia_conf_remove_port( pjmedia_conf *conf, 
    73                                                unsigned port ); 
     147                                               unsigned slot ); 
    74148 
     149 
     150 
     151/** 
     152 * Get port info. 
     153 */ 
     154PJ_DECL(pj_status_t) pjmedia_conf_get_port_info( pjmedia_conf *conf, 
     155                                                 unsigned slot, 
     156                                                 pjmedia_conf_port_info *info); 
     157 
     158 
     159PJ_END_DECL 
    75160 
    76161 
  • pjproject/trunk/pjmedia/include/pjmedia/errno.h

    r188 r205  
    345345 */ 
    346346#define PJMEDIA_RTP_EBADSEQ         (PJMEDIA_ERRNO_START+132)    /* 220132 */ 
     347/** 
     348 * @hideinitializer 
     349 * RTP media port destination is not configured 
     350 */ 
     351#define PJMEDIA_RTP_EBADDEST        (PJMEDIA_ERRNO_START+133)    /* 220133 */ 
     352/** 
     353 * @hideinitializer 
     354 * RTP is not configured. 
     355 */ 
     356#define PJMEDIA_RTP_ENOCONFIG       (PJMEDIA_ERRNO_START+134)    /* 220134 */ 
    347357 
    348358 
     
    352362 
    353363 
     364/************************************************************ 
     365 * PORT ERRORS 
     366 ***********************************************************/ 
     367/** 
     368 * @hideinitializer 
     369 * Generic incompatible port error. 
     370 */ 
     371#define PJMEDIA_ENOTCOMPATIBLE      (PJMEDIA_ERRNO_START+160)    /* 220160 */ 
     372/** 
     373 * @hideinitializer 
     374 * Incompatible clock rate 
     375 */ 
     376#define PJMEDIA_ENCCLOCKRATE        (PJMEDIA_ERRNO_START+161)    /* 220161 */ 
     377/** 
     378 * @hideinitializer 
     379 * Incompatible samples per frame 
     380 */ 
     381#define PJMEDIA_ENCSAMPLESPFRAME    (PJMEDIA_ERRNO_START+162)    /* 220162 */ 
     382/** 
     383 * @hideinitializer 
     384 * Incompatible media type 
     385 */ 
     386#define PJMEDIA_ENCTYPE             (PJMEDIA_ERRNO_START+163)    /* 220163 */ 
     387/** 
     388 * @hideinitializer 
     389 * Incompatible bits per sample 
     390 */ 
     391#define PJMEDIA_ENCBITS             (PJMEDIA_ERRNO_START+164)    /* 220164 */ 
     392/** 
     393 * @hideinitializer 
     394 * Incompatible bytes per frame 
     395 */ 
     396#define PJMEDIA_ENCBYTES            (PJMEDIA_ERRNO_START+165)    /* 220165 */ 
     397 
     398 
     399 
    354400PJ_END_DECL 
    355401 
  • pjproject/trunk/pjmedia/include/pjmedia/rtp.h

    r199 r205  
    7070 */ 
    7171 
     72#ifdef _MSC_VER 
     73#   pragma warning(disable:4214)    // bit field types other than int 
     74#endif 
    7275 
    7376 
  • pjproject/trunk/pjmedia/include/pjmedia/session.h

    r189 r205  
    176176 
    177177/** 
     178 * Get the port interface for the specified stream. 
     179 */ 
     180PJ_DECL(pj_status_t) pjmedia_session_get_port( pjmedia_session *session, 
     181                                               unsigned index, 
     182                                               pjmedia_port **p_port); 
     183 
     184 
     185/** 
    178186 * Get session statistics. The stream statistic shows various 
    179187 * indicators such as packet count, packet lost, jitter, delay, etc. 
  • pjproject/trunk/pjmedia/include/pjmedia/stream.h

    r203 r205  
    2929#include <pjmedia/codec.h> 
    3030#include <pjmedia/endpoint.h> 
     31#include <pjmedia/port.h> 
    3132#include <pj/sock.h> 
    3233 
     
    9899 
    99100 
    100 /** 
    101  * Stream ports. 
    102  */ 
    103 struct pjmedia_stream_port 
    104 { 
    105     /** 
    106      * Sink port. 
    107      */ 
    108     pj_status_t (*put_frame)(const pj_int16_t *frame, pj_size_t frame_cnt); 
    109  
    110     /** 
    111      * Source port. 
    112      */ 
    113     pj_status_t (*get_frame)(pj_int16_t *frame, pj_size_t frame_cnt); 
    114 }; 
    115  
    116101 
    117102/** 
     
    141126 */ 
    142127PJ_DECL(pj_status_t) pjmedia_stream_destroy(pjmedia_stream *stream); 
     128 
     129/** 
     130 * Get the port interface of the stream. 
     131 * 
     132 * @param stream        The media stream. 
     133 * @param p_port        Pointer to receive the port interface. 
     134 * 
     135 * @return              PJ_SUCCESS on success. 
     136 */ 
     137PJ_DECL(pj_status_t) pjmedia_stream_get_port(pjmedia_stream *stream, 
     138                                             pjmedia_port **p_port ); 
     139 
    143140 
    144141/** 
  • pjproject/trunk/pjmedia/include/pjmedia/types.h

    r203 r205  
    152152 
    153153/** 
    154  * @see pjmedia_stream_port 
    155  */ 
    156 typedef struct pjmedia_stream_port pjmedia_stream_port; 
    157  
    158 /** 
    159154 * Typedef for media stream. 
    160155 */ 
  • pjproject/trunk/pjmedia/src/pjmedia-codec/gsm.c

    r198 r205  
    2121#include <pjmedia/errno.h> 
    2222#include <pjmedia/endpoint.h> 
     23#include <pjmedia/port.h> 
    2324#include <pj/assert.h> 
    2425#include <pj/pool.h> 
  • 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; 
  • pjproject/trunk/pjmedia/src/pjmedia/g711.c

    r203 r205  
    2222#include <pjmedia/codec.h> 
    2323#include <pjmedia/errno.h> 
     24#include <pjmedia/port.h> 
    2425#include <pj/pool.h> 
    2526#include <pj/string.h> 
     
    502503 * John Wiley & Sons, pps 98-111 and 472-476. 
    503504 */ 
    504 static unsigned char 
     505unsigned char 
    505506linear2alaw( 
    506507        int             pcm_val)        /* 2's complement (16-bit range) */ 
     
    538539 * 
    539540 */ 
    540 static int 
     541int 
    541542alaw2linear( 
    542543        unsigned char   a_val) 
     
    636637 * original code word. This is in keeping with ISDN conventions. 
    637638 */ 
    638 static int 
     639int 
    639640ulaw2linear( 
    640641        unsigned char   u_val) 
  • pjproject/trunk/pjmedia/src/pjmedia/rtp.c

    r199 r205  
    4444    /* Check RTP header packing. */ 
    4545    if (sizeof(struct pjmedia_rtp_hdr) != 12) { 
    46         unsigned sz = sizeof(struct pjmedia_rtp_hdr); 
    4746        pj_assert(!"Wrong RTP header packing!"); 
    4847        return PJMEDIA_RTP_EINPACK; 
  • pjproject/trunk/pjmedia/src/pjmedia/session.c

    r188 r205  
    385385} 
    386386 
     387 
     388PJ_DEF(pj_status_t) pjmedia_session_get_port(  pjmedia_session *session, 
     389                                               unsigned index, 
     390                                               pjmedia_port **p_port) 
     391{ 
     392    return pjmedia_stream_get_port( session->stream[index], p_port); 
     393} 
     394 
    387395/** 
    388396 * Get statistics 
  • pjproject/trunk/pjmedia/src/pjmedia/stream.c

    r188 r205  
    5353    pj_bool_t               paused;         /**< Paused?.                   */ 
    5454    pj_snd_stream_info      snd_info;       /**< Sound stream param.        */ 
    55     pj_snd_stream          *snd_stream;     /**< Sound stream.              */ 
     55    //pj_snd_stream        *snd_stream;     /**< Sound stream.              */ 
    5656    unsigned                in_pkt_size;    /**< Size of input buffer.      */ 
    5757    void                   *in_pkt;         /**< Input buffer.              */ 
     
    7373struct pjmedia_stream 
    7474{ 
     75    pjmedia_port             port;          /**< Port interface.            */ 
    7576    pjmedia_channel         *enc;           /**< Encoding channel.          */ 
    7677    pjmedia_channel         *dec;           /**< Decoding channel.          */ 
     
    103104 * needs to feed the player with some frames. 
    104105 */ 
    105 static pj_status_t play_callback(/* in */   void *user_data, 
    106                                  /* in */   pj_uint32_t timestamp, 
    107                                  /* out */  void *frame, 
    108                                  /*inout*/  unsigned size) 
    109 { 
    110     pjmedia_channel *channel = user_data; 
    111     pjmedia_stream *stream = channel->stream; 
     106static pj_status_t get_frame( pjmedia_port *port, pjmedia_frame *frame) 
     107{ 
     108    pjmedia_stream *stream = port->user_data; 
     109    pjmedia_channel *channel = stream->dec; 
     110     
    112111    char frame_type; 
    113112    pj_status_t status; 
    114113    struct pjmedia_frame frame_in, frame_out; 
    115114 
    116     PJ_UNUSED_ARG(timestamp); 
    117  
    118115    /* Do nothing if we're quitting. */ 
    119     if (stream->quit_flag) 
    120         return -1; 
     116    if (stream->quit_flag) { 
     117        frame->type = PJMEDIA_FRAME_TYPE_NONE; 
     118        return PJ_SUCCESS; 
     119    } 
    121120 
    122121    /* Lock jitter buffer mutex */ 
     
    133132        frame_type == PJMEDIA_JB_MISSING_FRAME)  
    134133    { 
    135         pj_memset(frame, 0, size); 
    136         return 0; 
     134        frame->type = PJMEDIA_FRAME_TYPE_NONE; 
     135        return PJ_SUCCESS; 
    137136    } 
    138137 
     
    148147        TRACE_((THIS_FILE, "decode() has return error status %d", status)); 
    149148 
    150         pj_memset(frame, 0, size); 
    151         return 0; 
     149        frame->type = PJMEDIA_FRAME_TYPE_NONE; 
     150        return PJ_SUCCESS; 
    152151    } 
    153152 
    154153    /* Put in sound buffer. */ 
    155     if (frame_out.size > size) { 
     154    if (frame_out.size > frame->size) { 
    156155        TRACE_((THIS_FILE, "Sound playout buffer truncated %d bytes",  
    157                 frame_out.size - size)); 
    158         frame_out.size = size; 
    159     } 
    160  
    161     pj_memcpy(frame, frame_out.buf, size); 
    162  
    163     return 0; 
     156                frame_out.size - frame->size)); 
     157        frame_out.size = frame->size; 
     158    } 
     159 
     160    frame->type = PJMEDIA_FRAME_TYPE_AUDIO; 
     161    frame->size = frame_out.size; 
     162    frame->timestamp.u64 = 0; 
     163    pj_memcpy(frame->buf, frame_out.buf, frame_out.size); 
     164 
     165    return PJ_SUCCESS; 
    164166} 
    165167 
     
    172174 * send it to remote. 
    173175 */ 
    174 static pj_status_t rec_callback( /* in */ void *user_data, 
    175                                  /* in */ pj_uint32_t timestamp, 
    176                                  /* in */ const void *frame, 
    177                                  /* in */ unsigned size) 
    178 { 
    179     pjmedia_channel *channel = user_data; 
    180     pjmedia_stream *stream = channel->stream; 
     176static pj_status_t put_frame( pjmedia_port *port,  
     177                              const pjmedia_frame *frame ) 
     178{ 
     179    pjmedia_stream *stream = port->user_data; 
     180    pjmedia_channel *channel = stream->enc; 
    181181    pj_status_t status = 0; 
    182     struct pjmedia_frame frame_in, frame_out; 
     182    struct pjmedia_frame frame_out; 
    183183    int ts_len; 
    184184    void *rtphdr; 
     
    187187 
    188188 
    189     PJ_UNUSED_ARG(timestamp); 
    190  
    191189    /* Check if stream is quitting. */ 
    192190    if (stream->quit_flag) 
     
    194192 
    195193    /* Encode. */ 
    196     frame_in.type = PJMEDIA_TYPE_AUDIO; 
    197     frame_in.buf = (void*)frame; 
    198     frame_in.size = size; 
    199194    frame_out.buf = ((char*)channel->out_pkt) + sizeof(pjmedia_rtp_hdr); 
    200     status = stream->codec->op->encode( stream->codec, &frame_in,  
     195    status = stream->codec->op->encode( stream->codec, frame,  
    201196                                        channel->out_pkt_size - sizeof(pjmedia_rtp_hdr),  
    202197                                        &frame_out); 
     
    208203 
    209204    /* Encapsulate. */ 
    210     ts_len = size / (channel->snd_info.bits_per_sample / 8); 
     205    ts_len = frame->size / (channel->snd_info.bits_per_sample / 8); 
    211206    status = pjmedia_rtp_encode_rtp( &channel->rtp,  
    212207                                channel->pt, 0,  
     
    239234    stream->stat.enc.bytes += frame_out.size+sizeof(pjmedia_rtp_hdr); 
    240235 
    241     return 0; 
     236    return PJ_SUCCESS; 
    242237} 
    243238 
     
    426421    init_snd_param(&channel->snd_info, codec_param); 
    427422 
     423    /* 
    428424    if (dir == PJMEDIA_DIR_ENCODING) 
    429425        channel->snd_stream = pj_snd_open_recorder(-1, &channel->snd_info,  
     
    435431    if (!channel->snd_stream) 
    436432        return -1; 
    437  
     433    */ 
    438434 
    439435    /* Done. */ 
     
    463459    stream = pj_pool_zalloc(pool, sizeof(pjmedia_stream)); 
    464460    PJ_ASSERT_RETURN(stream != NULL, PJ_ENOMEM); 
     461 
     462    /* Init port. */ 
     463    stream->port.info.name = pj_str("stream"); 
     464    stream->port.info.signature = ('S'<<3 | 'T'<<2 | 'R'<<1 | 'M'); 
     465    stream->port.info.type = PJMEDIA_TYPE_AUDIO; 
     466    stream->port.info.has_info = 1; 
     467    stream->port.info.need_info = 0; 
     468    stream->port.info.pt = info->fmt.pt; 
     469    pj_strdup(pool, &stream->port.info.encoding_name, &info->fmt.encoding_name); 
     470    stream->port.info.sample_rate = info->fmt.sample_rate; 
     471    stream->port.user_data = stream; 
     472    stream->port.put_frame = &put_frame; 
     473    stream->port.get_frame = &get_frame; 
    465474 
    466475 
     
    495504        goto err_cleanup; 
    496505 
     506    /* Set additional info. */ 
     507    stream->port.info.bits_per_sample = 0; 
     508    stream->port.info.samples_per_frame = info->fmt.sample_rate*codec_param.ptime/1000; 
     509    stream->port.info.bytes_per_frame = codec_param.avg_bps/8 * codec_param.ptime/1000; 
     510 
    497511 
    498512    /* Open the codec: */ 
     
    576590    /* Close encoding sound stream. */ 
    577591     
     592    /* 
    578593    if (stream->enc && stream->enc->snd_stream) { 
    579594 
     
    583598 
    584599    } 
     600    */ 
    585601 
    586602    /* Close decoding sound stream. */ 
    587603 
     604    /* 
    588605    if (stream->dec && stream->dec->snd_stream) { 
    589606 
     
    593610 
    594611    } 
     612    */ 
    595613 
    596614    /* Wait for jitter buffer thread to quit: */ 
     
    623641 
    624642/* 
     643 * Get the port interface. 
     644 */ 
     645PJ_DEF(pj_status_t) pjmedia_stream_get_port( pjmedia_stream *stream, 
     646                                             pjmedia_port **p_port ) 
     647{ 
     648    *p_port = &stream->port; 
     649    return PJ_SUCCESS; 
     650} 
     651 
     652 
     653/* 
    625654 * Start stream. 
    626655 */ 
     
    632661    if (stream->enc && (stream->dir & PJMEDIA_DIR_ENCODING)) { 
    633662        stream->enc->paused = 0; 
    634         pj_snd_stream_start(stream->enc->snd_stream); 
     663        //pj_snd_stream_start(stream->enc->snd_stream); 
    635664    } 
    636665 
    637666    if (stream->dec && (stream->dir & PJMEDIA_DIR_DECODING)) { 
    638667        stream->dec->paused = 0; 
    639         pj_snd_stream_start(stream->dec->snd_stream); 
     668        //pj_snd_stream_start(stream->dec->snd_stream); 
    640669    } 
    641670 
  • pjproject/trunk/pjmedia/src/pjmedia/vad.c

    r203 r205  
    5757 
    5858 
    59 unsigned char linear2ulaw(int           pcm_val); 
     59unsigned char linear2ulaw(int pcm_val); 
     60 
    6061 
    6162PJ_DEF(pj_status_t) pjmedia_vad_create( pj_pool_t *pool, 
     
    8889    vad->frame_size = frame_size; 
    8990    vad->mode = VAD_MODE_ADAPTIVE; 
    90     vad->min_signal_cnt = 3; 
    91     vad->min_silence_cnt = 20; 
    92     vad->recalc_cnt = 30; 
     91    vad->min_signal_cnt = 10; 
     92    vad->min_silence_cnt = 64; 
     93    vad->recalc_cnt = 250; 
    9394    vad->cur_threshold = 20; 
    9495 
     
    228229             */ 
    229230            vad->cur_threshold += (vad->weakest_signal - vad->cur_threshold)/4; 
    230             PJ_LOG(5,(THIS_FILE, "Vad cur_threshold increased to %d", 
     231            PJ_LOG(6,(THIS_FILE, "Vad cur_threshold increased to %d", 
    231232                      vad->cur_threshold)); 
    232233        } 
     
    236237             */ 
    237238            vad->cur_threshold = (vad->cur_threshold+vad->loudest_silence)/2+1; 
    238             PJ_LOG(5,(THIS_FILE, "Vad cur_threshold decreased to %d", 
     239            PJ_LOG(6,(THIS_FILE, "Vad cur_threshold decreased to %d", 
    239240                      vad->cur_threshold)); 
    240241        } 
     
    251252 
    252253            if (updated) { 
    253                 PJ_LOG(5,(THIS_FILE, 
     254                PJ_LOG(6,(THIS_FILE, 
    254255                          "Vad cur_threshold updated to %d", 
    255256                          vad->cur_threshold)); 
  • pjproject/trunk/pjsip/src/pjsua/main.c

    r201 r205  
    137137    puts("|  [  Select previous dialog   |                          |                   |"); 
    138138    puts("+-----------------------------------------------------------------------------+"); 
     139    puts("|      Conference Command                                                     |"); 
     140    puts("| cl  List ports                                                              |"); 
     141    puts("| cc  Connect port                                                            |"); 
     142    puts("| cd  Disconnect port                                                         |"); 
     143    puts("+-----------------------------------------------------------------------------+"); 
    139144    puts("|  q  QUIT                                                                    |"); 
    140145    puts("+=============================================================================+"); 
     
    254259    } 
    255260} 
     261 
     262static void conf_list(void) 
     263{ 
     264    pjmedia_conf_port_info info; 
     265    struct pjsua_inv_data *inv_data; 
     266 
     267    printf("Conference ports:\n"); 
     268 
     269    inv_data = pjsua.inv_list.next; 
     270    while (inv_data != &pjsua.inv_list) { 
     271         
     272        pjmedia_conf_get_port_info(pjsua.mconf, inv_data->conf_slot, &info); 
     273 
     274        printf("Port %2d %.*s\n", inv_data->conf_slot,  
     275                                  (int)info.name.slen, info.name.ptr); 
     276 
     277        inv_data = inv_data->next; 
     278    } 
     279} 
     280 
    256281 
    257282static void ui_console_main(void) 
     
    396421            break; 
    397422 
     423        case 'c': 
     424            switch (menuin[1]) { 
     425            case 'l': 
     426                conf_list(); 
     427                break; 
     428            case 'c': 
     429            case 'd': 
     430                { 
     431                    char src_port[10], dst_port[10]; 
     432                    pj_status_t status; 
     433 
     434                    if (!simple_input("Connect src port #:", src_port, sizeof(src_port))) 
     435                        break; 
     436                    if (!simple_input("To dst port #:", dst_port, sizeof(dst_port))) 
     437                        break; 
     438 
     439                    if (menuin[1]=='c') { 
     440                        status = pjmedia_conf_connect_port(pjsua.mconf, atoi(src_port), atoi(dst_port)); 
     441                    } else { 
     442                        status = pjmedia_conf_disconnect_port(pjsua.mconf, atoi(src_port), atoi(dst_port)); 
     443                    } 
     444                    if (status == PJ_SUCCESS) { 
     445                        puts("Success"); 
     446                    } else { 
     447                        puts("ERROR!!"); 
     448                    } 
     449                } 
     450                break; 
     451            } 
     452            break; 
     453 
    398454        case 'd': 
    399455            pjsua_dump(); 
  • pjproject/trunk/pjsip/src/pjsua/pjsua.h

    r201 r205  
    5050#define PJSUA_MAX_BUDDIES   32 
    5151 
     52/** 
     53 * Max simultaneous calls. 
     54 */ 
     55#define PJSUA_MAX_CALLS     8 
     56 
     57 
    5258/**  
    5359 * Structure to be attached to all dialog.  
     
    5965    PJ_DECL_LIST_MEMBER(struct pjsua_inv_data); 
    6066 
    61     pjsip_inv_session   *inv; 
    62     pjmedia_session     *session; 
    63     void                *mod_data[PJSIP_MAX_MODULE]; 
     67    pjsip_inv_session   *inv;       /**< The invite session.                */ 
     68    pjmedia_session     *session;   /**< The media session.                 */ 
     69    unsigned             conf_slot; /**< Slot # in conference bridge.       */ 
     70    unsigned             call_slot; /**< RTP media index in med_sock_use[]  */ 
    6471}; 
    6572 
     
    106113    /* Media:  */ 
    107114 
    108     pjmedia_endpt   *med_endpt;    /**< Media endpoint.         */ 
    109     pj_bool_t        null_audio; 
    110     pjmedia_sock_info med_skinfo; 
     115    pjmedia_endpt   *med_endpt;     /**< Media endpoint.                */ 
     116    pjmedia_conf    *mconf;         /**< Media conference.              */ 
     117    pj_bool_t        null_audio;    /**< Null audio flag.               */ 
     118 
     119 
     120    /* Since we support simultaneous calls, we need to have multiple 
     121     * RTP sockets. 
     122     */ 
     123    pjmedia_sock_info med_sock_info[PJSUA_MAX_CALLS]; 
     124    pj_bool_t         med_sock_use[PJSUA_MAX_CALLS]; 
    111125 
    112126    /* User info: */ 
     
    138152 
    139153 
    140     /* Threading: */ 
     154    /* Threading (optional): */ 
    141155 
    142156    int              thread_cnt;    /**< Thread count.                  */ 
  • pjproject/trunk/pjsip/src/pjsua/pjsua_core.c

    r201 r205  
    136136 * Initialize sockets and optionally get the public address via STUN.  
    137137 */ 
    138 static pj_status_t init_sockets() 
     138static pj_status_t init_sockets(pj_bool_t sip, 
     139                                pjmedia_sock_info *skinfo) 
    139140{ 
    140141    enum {  
     
    152153    pj_sock_t sock[3]; 
    153154    pj_sockaddr_in mapped_addr[3]; 
    154     pj_status_t status; 
     155    pj_status_t status = PJ_SUCCESS; 
    155156 
    156157    for (i=0; i<3; ++i) 
    157158        sock[i] = PJ_INVALID_SOCKET; 
    158159 
    159     /* Create and bind SIP UDP socket. */ 
    160     status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock[SIP_SOCK]); 
    161     if (status != PJ_SUCCESS) { 
    162         pjsua_perror(THIS_FILE, "socket() error", status); 
    163         goto on_error; 
    164     } 
     160    if (sip) { 
     161        /* Create and bind SIP UDP socket. */ 
     162        status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock[SIP_SOCK]); 
     163        if (status != PJ_SUCCESS) { 
     164            pjsua_perror(THIS_FILE, "socket() error", status); 
     165            goto on_error; 
     166        } 
    165167     
    166     status = pj_sock_bind_in(sock[SIP_SOCK], 0, pjsua.sip_port); 
    167     if (status != PJ_SUCCESS) { 
    168         pjsua_perror(THIS_FILE, "bind() error", status); 
    169         goto on_error; 
     168        status = pj_sock_bind_in(sock[SIP_SOCK], 0, pjsua.sip_port); 
     169        if (status != PJ_SUCCESS) { 
     170            pjsua_perror(THIS_FILE, "bind() error", status); 
     171            goto on_error; 
     172        } 
    170173    } 
    171174 
     
    230233                pj_memcpy(&mapped_addr[i], &addr, sizeof(addr)); 
    231234 
    232             mapped_addr[SIP_SOCK].sin_port = pj_htons((pj_uint16_t)pjsua.sip_port); 
     235            if (sip) 
     236                mapped_addr[SIP_SOCK].sin_port = pj_htons((pj_uint16_t)pjsua.sip_port); 
     237            else 
     238                mapped_addr[RTP_SOCK].sin_port = pj_htons((pj_uint16_t)rtp_port); 
    233239            mapped_addr[RTP_SOCK].sin_port = pj_htons((pj_uint16_t)rtp_port); 
    234240            mapped_addr[RTCP_SOCK].sin_port = pj_htons((pj_uint16_t)(rtp_port+1)); 
     
    257263    } 
    258264 
    259     pjsua.sip_sock = sock[SIP_SOCK]; 
    260     pj_memcpy(&pjsua.sip_sock_name, &mapped_addr[SIP_SOCK], sizeof(pj_sockaddr_in)); 
    261  
    262     pjsua.med_skinfo.rtp_sock = sock[RTP_SOCK]; 
    263     pj_memcpy(&pjsua.med_skinfo.rtp_addr_name,  
     265    if (sip) { 
     266        pjsua.sip_sock = sock[SIP_SOCK]; 
     267        pj_memcpy(&pjsua.sip_sock_name, &mapped_addr[SIP_SOCK], sizeof(pj_sockaddr_in)); 
     268    } 
     269 
     270    skinfo->rtp_sock = sock[RTP_SOCK]; 
     271    pj_memcpy(&skinfo->rtp_addr_name,  
    264272              &mapped_addr[RTP_SOCK], sizeof(pj_sockaddr_in)); 
    265273 
    266     pjsua.med_skinfo.rtcp_sock = sock[RTCP_SOCK]; 
    267     pj_memcpy(&pjsua.med_skinfo.rtcp_addr_name,  
     274    skinfo->rtcp_sock = sock[RTCP_SOCK]; 
     275    pj_memcpy(&skinfo->rtcp_addr_name,  
    268276              &mapped_addr[RTCP_SOCK], sizeof(pj_sockaddr_in)); 
    269277 
    270     PJ_LOG(4,(THIS_FILE, "SIP UDP socket reachable at %s:%d", 
    271               pj_inet_ntoa(pjsua.sip_sock_name.sin_addr),  
    272               pj_ntohs(pjsua.sip_sock_name.sin_port))); 
     278    if (sip) { 
     279        PJ_LOG(4,(THIS_FILE, "SIP UDP socket reachable at %s:%d", 
     280                  pj_inet_ntoa(pjsua.sip_sock_name.sin_addr),  
     281                  pj_ntohs(pjsua.sip_sock_name.sin_port))); 
     282    } 
    273283    PJ_LOG(4,(THIS_FILE, "RTP socket reachable at %s:%d", 
    274               pj_inet_ntoa(pjsua.med_skinfo.rtp_addr_name.sin_addr),  
    275               pj_ntohs(pjsua.med_skinfo.rtp_addr_name.sin_port))); 
     284              pj_inet_ntoa(skinfo->rtp_addr_name.sin_addr),  
     285              pj_ntohs(skinfo->rtp_addr_name.sin_port))); 
    276286    PJ_LOG(4,(THIS_FILE, "RTCP UDP socket reachable at %s:%d", 
    277               pj_inet_ntoa(pjsua.med_skinfo.rtcp_addr_name.sin_addr),  
    278               pj_ntohs(pjsua.med_skinfo.rtcp_addr_name.sin_port))); 
     287              pj_inet_ntoa(skinfo->rtcp_addr_name.sin_addr),  
     288              pj_ntohs(skinfo->rtcp_addr_name.sin_port))); 
    279289 
    280290    return PJ_SUCCESS; 
     
    282292on_error: 
    283293    for (i=0; i<3; ++i) { 
     294        if (sip && i==0) 
     295            continue; 
    284296        if (sock[i] != PJ_INVALID_SOCKET) 
    285297            pj_sock_close(sock[i]); 
     
    485497    } 
    486498 
     499    /* Init conference bridge. */ 
     500 
     501    status = pjmedia_conf_create(pjsua.pool, 8, 8000, 160, 16, &pjsua.mconf); 
     502    if (status != PJ_SUCCESS) { 
     503        pj_caching_pool_destroy(&pjsua.cp); 
     504        pjsua_perror(THIS_FILE,  
     505                     "Media stack initialization has returned error",  
     506                     status); 
     507        return status; 
     508    } 
     509 
    487510    /* Init pjmedia-codecs: */ 
    488511 
     
    511534    int i;  /* Must be signed */ 
    512535    pjsip_transport *udp_transport; 
    513     pj_status_t status; 
     536    pj_status_t status = PJ_SUCCESS; 
    514537 
    515538    /* Init sockets (STUN etc): */ 
    516  
    517     status = init_sockets(); 
    518     if (status != PJ_SUCCESS) { 
    519         pjsua_perror(THIS_FILE, "init_sockets() has returned error",  
    520                     status); 
    521         return status; 
    522     } 
    523  
     539    for (i=0; i<PJ_ARRAY_SIZE(pjsua.med_sock_info); ++i) { 
     540        status = init_sockets(i==0, &pjsua.med_sock_info[i]); 
     541        if (status != PJ_SUCCESS) { 
     542            pjsua_perror(THIS_FILE, "init_sockets() has returned error",  
     543                        status); 
     544            return status; 
     545        } 
     546    } 
    524547 
    525548    /* Add UDP transport: */ 
  • pjproject/trunk/pjsip/src/pjsua/pjsua_inv.c

    r201 r205  
    4242    struct pjsua_inv_data *inv_data; 
    4343    pjsip_tx_data *tdata; 
     44    int med_sk_index = 0; 
    4445    pj_status_t status; 
    4546 
     
    4849    dest_uri = pj_str((char*)cstr_dest_uri); 
    4950 
     51    /* Find free socket. */ 
     52    for (med_sk_index=0; med_sk_index<PJSUA_MAX_CALLS; ++med_sk_index) { 
     53        if (!pjsua.med_sock_use[med_sk_index]) 
     54            break; 
     55    } 
     56 
     57    if (med_sk_index == PJSUA_MAX_CALLS) { 
     58        PJ_LOG(3,(THIS_FILE, "Error: too many calls!")); 
     59        return PJ_ETOOMANY; 
     60    } 
     61 
     62    pjsua.med_sock_use[med_sk_index] = 1; 
     63 
    5064    /* Create outgoing dialog: */ 
    5165 
     
    6175 
    6276    status = pjmedia_endpt_create_sdp( pjsua.med_endpt, dlg->pool, 
    63                                        1, &pjsua.med_skinfo, &offer); 
     77                                       1, &pjsua.med_sock_info[med_sk_index],  
     78                                       &offer); 
    6479    if (status != PJ_SUCCESS) { 
    6580        pjsua_perror(THIS_FILE, "pjmedia unable to create SDP", status); 
     
    8095    inv_data = pj_pool_zalloc( dlg->pool, sizeof(struct pjsua_inv_data)); 
    8196    inv_data->inv = inv; 
     97    inv_data->call_slot = med_sk_index; 
    8298    dlg->mod_data[pjsua.mod.id] = inv_data; 
    8399    inv->mod_data[pjsua.mod.id] = inv_data; 
     
    130146 
    131147    PJ_TODO(DESTROY_DIALOG_ON_FAIL); 
     148    pjsua.med_sock_use[med_sk_index] = 0; 
    132149    return status; 
    133150} 
     
    183200            struct pjsua_inv_data *inv_data; 
    184201            pjmedia_sdp_session *answer; 
    185  
     202            int med_sk_index; 
     203 
     204 
     205            /* Find free socket. */ 
     206            for (med_sk_index=0; med_sk_index<PJSUA_MAX_CALLS; ++med_sk_index) { 
     207                if (!pjsua.med_sock_use[med_sk_index]) 
     208                    break; 
     209            } 
     210 
     211            if (med_sk_index == PJSUA_MAX_CALLS) { 
     212                PJ_LOG(3,(THIS_FILE, "Error: too many calls!")); 
     213                return PJ_TRUE; 
     214            } 
     215 
     216 
     217            pjsua.med_sock_use[med_sk_index] = 1; 
    186218 
    187219            /* Get media capability from media endpoint: */ 
    188220 
    189221            status = pjmedia_endpt_create_sdp( pjsua.med_endpt, rdata->tp_info.pool, 
    190                                                1, &pjsua.med_skinfo, &answer ); 
     222                                               1, &pjsua.med_sock_info[med_sk_index],  
     223                                               &answer ); 
    191224            if (status != PJ_SUCCESS) { 
    192225 
    193226                pjsip_endpt_respond_stateless(pjsua.endpt, rdata, 500, NULL, 
    194227                                              NULL, NULL); 
     228                pjsua.med_sock_use[med_sk_index] = 0; 
    195229                return PJ_TRUE; 
    196230            } 
     
    200234            status = pjsip_dlg_create_uas( pjsip_ua_instance(), rdata, 
    201235                                           &pjsua.contact_uri, &dlg); 
    202             if (status != PJ_SUCCESS) 
     236            if (status != PJ_SUCCESS) { 
     237                pjsua.med_sock_use[med_sk_index] = 0; 
    203238                return PJ_TRUE; 
     239            } 
    204240 
    205241 
     
    215251                                                     pjsip_rdata_get_tsx(rdata), 
    216252                                                     response); 
     253                pjsua.med_sock_use[med_sk_index] = 0; 
    217254                return PJ_TRUE; 
    218255 
     
    224261            inv_data = pj_pool_zalloc(dlg->pool, sizeof(struct pjsua_inv_data)); 
    225262            inv_data->inv = inv; 
     263            inv_data->call_slot = inv_data->call_slot = med_sk_index; 
    226264            dlg->mod_data[pjsua.mod.id] = inv_data; 
    227265            inv->mod_data[pjsua.mod.id] = inv_data; 
     
    261299 
    262300        if (inv_data && inv_data->session) { 
     301            pjmedia_conf_remove_port(pjsua.mconf, inv_data->conf_slot); 
    263302            pjmedia_session_destroy(inv_data->session); 
     303            pjsua.med_sock_use[inv_data->call_slot] = 0; 
    264304            inv_data->session = NULL; 
    265305 
     
    313353    inv_data = inv->dlg->mod_data[pjsua.mod.id]; 
    314354    if (inv_data && inv_data->session) { 
     355        pjmedia_conf_remove_port(pjsua.mconf, inv_data->conf_slot); 
    315356        pjmedia_session_destroy(inv_data->session); 
     357        pjsua.med_sock_use[inv_data->call_slot] = 0; 
    316358        inv_data->session = NULL; 
    317359    } 
     
    336378    } 
    337379 
    338  
    339380    /* Create new media session.  
    340381     * The media session is active immediately. 
     
    342383 
    343384    if (!pjsua.null_audio) { 
    344  
    345         status = pjmedia_session_create( pjsua.med_endpt, 1, &pjsua.med_skinfo, 
     385        pjmedia_port *media_port; 
     386        pj_str_t port_name; 
     387        char tmp[PJSIP_MAX_URL_SIZE]; 
     388 
     389        status = pjmedia_session_create( pjsua.med_endpt, 1,  
     390                                         &pjsua.med_sock_info[inv_data->call_slot], 
    346391                                         local_sdp, remote_sdp,  
    347392                                         &inv_data->session ); 
     
    352397        } 
    353398 
     399        pjmedia_session_get_port(inv_data->session, 0, &media_port); 
     400 
     401        port_name.ptr = tmp; 
     402        port_name.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, 
     403                                         inv_data->inv->dlg->remote.info->uri, 
     404                                         tmp, sizeof(tmp)); 
     405        if (port_name.slen < 1) { 
     406            port_name = pj_str("call"); 
     407        } 
     408        status = pjmedia_conf_add_port( pjsua.mconf, inv->pool, 
     409                                        media_port,  
     410                                        &port_name, 
     411                                        &inv_data->conf_slot); 
     412        if (status != PJ_SUCCESS) { 
     413            pjsua_perror(THIS_FILE, "Unable to create conference slot",  
     414                         status); 
     415            pjmedia_session_destroy(inv_data->session); 
     416            inv_data->session = NULL; 
     417            return; 
     418        } 
     419 
     420        pjmedia_conf_connect_port( pjsua.mconf, 0, inv_data->conf_slot); 
     421        pjmedia_conf_connect_port( pjsua.mconf, inv_data->conf_slot, 0); 
     422 
    354423        PJ_LOG(3,(THIS_FILE,"Media has been started successfully")); 
    355424    } 
Note: See TracChangeset for help on using the changeset viewer.