Changeset 653


Ignore:
Timestamp:
Aug 6, 2006 12:07:13 PM (18 years ago)
Author:
bennylp
Message:

Change AEC into generic echo canceller framework with either AEC or simple echo suppressor backend can be selected during runtime.

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

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjmedia/build/Makefile

    r643 r653  
    6666export PJMEDIA_SRCDIR = ../src/pjmedia 
    6767export PJMEDIA_OBJS += $(OS_OBJS) $(M_OBJS) $(CC_OBJS) $(HOST_OBJS) \ 
    68                         aec_port.o alaw_ulaw.o \ 
    69                         clock_thread.o codec.o conference.o endpoint.o errno.o \ 
     68                        alaw_ulaw.o clock_thread.o codec.o conference.o \ 
     69                        echo_common.o echo_port.o echo_speex.o \ 
     70                        echo_suppress.o endpoint.o errno.o \ 
    7071                        g711.o jbuf.o master_port.o mem_capture.o mem_player.o \ 
    7172                        null_port.o plc_common.o plc_g711.o \ 
  • pjproject/trunk/pjmedia/build/pjmedia.dsp

    r646 r653  
    8888# Begin Source File 
    8989 
    90 SOURCE=..\src\pjmedia\aec_port.c 
    91 # End Source File 
    92 # Begin Source File 
    93  
    94 SOURCE=..\src\pjmedia\aec_speex.c 
    95 # End Source File 
    96 # Begin Source File 
    97  
    9890SOURCE=..\src\pjmedia\alaw_ulaw.c 
    9991# End Source File 
     
    117109 
    118110SOURCE=..\src\pjmedia\dsound.c 
     111# End Source File 
     112# Begin Source File 
     113 
     114SOURCE=..\src\pjmedia\echo_common.c 
     115# End Source File 
     116# Begin Source File 
     117 
     118SOURCE=..\src\pjmedia\echo_port.c 
     119# End Source File 
     120# Begin Source File 
     121 
     122SOURCE=..\src\pjmedia\echo_speex.c 
     123# End Source File 
     124# Begin Source File 
     125 
     126SOURCE=..\src\pjmedia\echo_suppress.c 
    119127# End Source File 
    120128# Begin Source File 
     
    240248# Begin Source File 
    241249 
    242 SOURCE=..\include\pjmedia\aec.h 
    243 # End Source File 
    244 # Begin Source File 
    245  
    246 SOURCE=..\include\pjmedia\aec_port.h 
    247 # End Source File 
    248 # Begin Source File 
    249  
    250250SOURCE=..\include\pjmedia\bidirectional.h 
    251251# End Source File 
     
    269269 
    270270SOURCE=..\include\pjmedia\doxygen.h 
     271# End Source File 
     272# Begin Source File 
     273 
     274SOURCE=..\include\pjmedia\echo.h 
     275# End Source File 
     276# Begin Source File 
     277 
     278SOURCE=..\include\pjmedia\echo_port.h 
    271279# End Source File 
    272280# Begin Source File 
  • pjproject/trunk/pjmedia/include/pjmedia.h

    r646 r653  
    2626 
    2727#include <pjmedia/types.h> 
    28 #include <pjmedia/aec.h> 
    29 #include <pjmedia/aec_port.h> 
    3028#include <pjmedia/bidirectional.h> 
    3129#include <pjmedia/clock.h> 
    3230#include <pjmedia/codec.h> 
    3331#include <pjmedia/conference.h> 
     32#include <pjmedia/echo.h> 
     33#include <pjmedia/echo_port.h> 
     34#include <pjmedia/errno.h> 
    3435#include <pjmedia/endpoint.h> 
    35 #include <pjmedia/errno.h> 
    3636#include <pjmedia/g711.h> 
    3737#include <pjmedia/jbuf.h> 
  • pjproject/trunk/pjmedia/include/pjmedia/config.h

    r651 r653  
    171171 
    172172/** 
     173 * Speex Accoustic Echo Cancellation (AEC). 
     174 * By default is enabled. 
     175 */ 
     176#ifndef PJMEDIA_HAS_SPEEX_AEC 
     177#   define PJMEDIA_HAS_SPEEX_AEC                1 
     178#endif 
     179 
     180 
     181/** 
    173182 * Support for sending and decoding RTCP port in SDP (RFC 3605). 
    174183 * Default is yes. 
  • pjproject/trunk/pjmedia/include/pjmedia/echo.h

    r652 r653  
    1717 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
    1818 */ 
    19 #ifndef __PJMEDIA_AEC_H__ 
    20 #define __PJMEDIA_AEC_H__ 
     19#ifndef __PJMEDIA_ECHO_H__ 
     20#define __PJMEDIA_ECHO_H__ 
    2121 
    2222 
    2323/** 
    24  * @file aec.h 
    25  * @brief AEC (Accoustic Echo Cancellation) API. 
     24 * @file echo.h 
     25 * @brief Echo Cancellation API. 
    2626 */ 
    2727#include <pjmedia/types.h> 
     
    3030 
    3131/** 
    32  * @defgroup PJMEDIA_AEC AEC AEC (Accoustic Echo Cancellation) 
     32 * @defgroup PJMEDIA_Echo_Cancel Canceller Echo Cancellation 
    3333 * @ingroup PJMEDIA_PORT 
    34  * @brief AEC (Accoustic Echo Cancellation) API. 
     34 * @brief Echo Cancellation API. 
    3535 * @{ 
     36 * 
     37 * This section describes API to perform echo cancellation to audio signal. 
     38 * There may be multiple echo canceller implementation in PJMEDIA, ranging 
     39 * from simple echo suppressor to a full Accoustic Echo Canceller/AEC. By  
     40 * using this API, application should be able to use which EC backend to 
     41 * use base on the requirement and capability of the platform. 
    3642 */ 
    3743 
     
    4147 
    4248/** 
    43  * Opaque type for PJMEDIA AEC. 
     49 * Opaque type for PJMEDIA Echo Canceller state. 
    4450 */ 
    45 typedef struct pjmedia_aec pjmedia_aec; 
     51typedef struct pjmedia_echo_state pjmedia_echo_state; 
    4652 
    4753 
    4854/** 
    49  * Create the AEC.  
     55 * Echo cancellation options. 
     56 */ 
     57typedef enum pjmedia_echo_flag 
     58{ 
     59    /** 
     60     * If PJMEDIA_ECHO_SIMPLE flag is specified during echo canceller 
     61     * creation, then a simple echo suppressor will be used instead of 
     62     * an accoustic echo cancellation. 
     63     */ 
     64    PJMEDIA_ECHO_SIMPLE = 1, 
     65 
     66    /** 
     67     * If PJMEDIA_ECHO_NO_LOCK flag is specified, no mutex will be created 
     68     * for the echo canceller, but application will guarantee that echo 
     69     * canceller will not be called by different threads at the same time. 
     70     */ 
     71    PJMEDIA_ECHO_NO_LOCK = 2 
     72 
     73} pjmedia_echo_flag; 
     74 
     75 
     76 
     77 
     78/** 
     79 * Create the echo canceller.  
    5080 * 
    5181 * @param pool              Pool to allocate memory. 
     
    5383 * @param samples_per_frame Number of samples per frame. 
    5484 * @param tail_ms           Tail length, miliseconds. 
     85 * @param options           Options. If PJMEDIA_ECHO_SIMPLE is specified, 
     86 *                          then a simple echo suppressor implementation  
     87 *                          will be used instead of an accoustic echo  
     88 *                          cancellation. 
     89 *                          See #pjmedia_echo_flag for other options. 
     90 * @param p_echo            Pointer to receive the Echo Canceller state. 
    5591 * 
    56  * @return                  PJ_SUCCESS on success. 
     92 * @return                  PJ_SUCCESS on success, or the appropriate status. 
    5793 */ 
    58 PJ_DECL(pj_status_t) pjmedia_aec_create( pj_pool_t *pool, 
     94PJ_DECL(pj_status_t) pjmedia_echo_create(pj_pool_t *pool, 
    5995                                         unsigned clock_rate, 
    6096                                         unsigned samples_per_frame, 
    6197                                         unsigned tail_ms, 
    6298                                         unsigned options, 
    63                                          pjmedia_aec **p_aec ); 
     99                                         pjmedia_echo_state **p_echo ); 
    64100 
    65101 
    66102/** 
    67  * Destroy the AEC.  
     103 * Destroy the Echo Canceller.  
    68104 * 
    69  * @param aec           The AEC. 
     105 * @param echo          The Echo Canceller. 
     106 * 
    70107 * @return              PJ_SUCCESS on success. 
    71108 */ 
    72 PJ_DECL(pj_status_t) pjmedia_aec_destroy(pjmedia_aec *aec ); 
     109PJ_DECL(pj_status_t) pjmedia_echo_destroy(pjmedia_echo_state *echo ); 
    73110 
    74111 
    75112/** 
    76  * Let the AEC knows that a frame has been played to the speaker. 
    77  * The AEC will keep the frame in its internal buffer, to be used 
    78  * when cancelling the echo with #pjmedia_aec_capture(). 
     113 * Let the Echo Canceller knows that a frame has been played to the speaker. 
     114 * The Echo Canceller will keep the frame in its internal buffer, to be used 
     115 * when cancelling the echo with #pjmedia_echo_capture(). 
    79116 * 
    80  * @param aec           The AEC. 
    81  * @param ts            Optional timestamp to let the AEC knows the 
    82  *                      position of the frame relative to capture 
    83  *                      position. If NULL, the AEC assumes that 
    84  *                      application will supply the AEC with continuously 
    85  *                      increasing timestamp. 
     117 * @param echo          The Echo Canceller. 
    86118 * @param play_frm      Sample buffer containing frame to be played 
    87119 *                      (or has been played) to the playback device. 
     
    91123 * @return              PJ_SUCCESS on success. 
    92124 */ 
    93 PJ_DECL(pj_status_t) pjmedia_aec_playback( pjmedia_aec *aec, 
     125PJ_DECL(pj_status_t) pjmedia_echo_playback(pjmedia_echo_state *echo, 
    94126                                           pj_int16_t *play_frm ); 
    95127 
    96128 
    97129/** 
    98  * Let the AEC knows that a frame has been captured from the microphone. 
    99  * The AEC will cancel the echo from the captured signal, using the 
    100  * internal buffer (supplied by #pjmedia_aec_playback()) as the 
    101  * FES (Far End Speech) reference. 
     130 * Let the Echo Canceller knows that a frame has been captured from  
     131 * the microphone. 
     132 * The Echo Canceller will cancel the echo from the captured signal,  
     133 * using the internal buffer (supplied by #pjmedia_echo_playback())  
     134 * as the FES (Far End Speech) reference. 
    102135 * 
    103  * @param aec           The AEC. 
     136 * @param echo          The Echo Canceller. 
    104137 * @param rec_frm       On input, it contains the input signal (captured  
    105138 *                      from microphone) which echo is to be removed. 
     
    113146 * @return              PJ_SUCCESS on success. 
    114147 */ 
    115 PJ_DECL(pj_status_t) pjmedia_aec_capture( pjmedia_aec *aec, 
     148PJ_DECL(pj_status_t) pjmedia_echo_capture(pjmedia_echo_state *echo, 
    116149                                          pj_int16_t *rec_frm, 
    117150                                          unsigned options ); 
     
    121154 * Perform echo cancellation. 
    122155 * 
    123  * @param aec           The AEC. 
     156 * @param echo          The Echo Canceller. 
    124157 * @param rec_frm       On input, it contains the input signal (captured  
    125158 *                      from microphone) which echo is to be removed. 
     
    136169 * @return              PJ_SUCCESS on success. 
    137170 */ 
    138 PJ_DECL(pj_status_t) pjmedia_aec_cancel_echo( pjmedia_aec *aec, 
    139                                               pj_int16_t *rec_frm, 
    140                                               const pj_int16_t *play_frm, 
    141                                               unsigned options, 
    142                                               void *reserved ); 
     171PJ_DECL(pj_status_t) pjmedia_echo_cancel( pjmedia_echo_state *echo, 
     172                                          pj_int16_t *rec_frm, 
     173                                          const pj_int16_t *play_frm, 
     174                                          unsigned options, 
     175                                          void *reserved ); 
    143176 
    144177 
     
    150183 
    151184 
    152 #endif  /* __PJMEDIA_AEC_H__ */ 
     185#endif  /* __PJMEDIA_ECHO_H__ */ 
    153186 
  • pjproject/trunk/pjmedia/include/pjmedia/echo_port.h

    r652 r653  
    2929 
    3030/** 
    31  * @defgroup PJMEDIA_AEC_PORT AEC Port 
     31 * @defgroup PJMEDIA_ECHO_PORT Echo Cancellation Port 
    3232 * @ingroup PJMEDIA_PORT 
    33  * @brief AEC (Accoustic Echo Cancellation) media port. 
     33 * @brief Echo Cancellation Port 
     34 * 
     35 * Echo canceller media port, using @ref PJMEDIA_Echo_Cancel backend. 
    3436 * @{ 
    3537 */ 
     
    4042 
    4143/** 
    42  * Create AEC port.  
     44 * Create echo canceller port.  
    4345 * 
    4446 * @param pool          Pool to allocate memory. 
    4547 * @param dn_port       Downstream port. 
    4648 * @param tail_ms       Tail length in miliseconds. 
     49 * @param options       Options, as in #pjmedia_echo_create(). 
    4750 * @param p_port        Pointer to receive the port instance. 
    4851 * 
    4952 * @return              PJ_SUCCESS on success. 
    5053 */ 
    51 PJ_DECL(pj_status_t) pjmedia_aec_port_create( pj_pool_t *pool, 
     54PJ_DECL(pj_status_t) pjmedia_echo_port_create(pj_pool_t *pool, 
    5255                                              pjmedia_port *dn_port, 
    5356                                              unsigned tail_ms, 
     57                                              unsigned options, 
    5458                                              pjmedia_port **p_port ); 
    5559 
  • pjproject/trunk/pjmedia/include/pjmedia/sound_port.h

    r648 r653  
    184184 
    185185/** 
    186  * Enable accoustic echo cancellation (AEC) to the specified sound.  
    187  * The AEC can only be enabled for sound streams with full-duplex direction. 
    188  * 
    189  * And note, you should only change the AEC settings when the sound port 
    190  * is not connected to any downstream ports. 
    191  * 
    192  * @param snd_port          The sound device port. 
    193  * @param pool              Pool to re-create the AEC if necessary. 
     186 * Configure the echo cancellation tail length. By default, echo canceller 
     187 * is enabled in the sound device with the default tail length. After the 
     188 * sound port is created, application can query the current echo canceller 
     189 * tail length by calling #pjmedia_snd_port_get_ec_tail. 
     190 * 
     191 * Note that you should only change the EC settings when the sound port 
     192 * is not connected to any downstream ports, otherwise race condition may 
     193 * occur. 
     194 * 
     195 * @param snd_port          The sound device port. 
     196 * @param pool              Pool to re-create the echo canceller if necessary. 
    194197 * @param tail_ms           Maximum echo tail length to be supported, in 
    195  *                          miliseconds. If zero is specified, the AEC would 
     198 *                          miliseconds. If zero is specified, the EC would 
    196199 *                          be disabled. 
    197200 * 
    198201 * @return                  PJ_SUCCESS on success. 
    199202 */ 
    200 PJ_DECL(pj_status_t) pjmedia_snd_port_set_aec(pjmedia_snd_port *snd_port, 
    201                                               pj_pool_t *pool, 
    202                                               unsigned tail_ms); 
    203  
    204  
    205 /** 
    206  * Get current AEC tail length, in miliseconds. The tail length will be zero 
    207  * if AEC is not enabled. 
     203PJ_DECL(pj_status_t) pjmedia_snd_port_set_ec_tail(pjmedia_snd_port *snd_port, 
     204                                                  pj_pool_t *pool, 
     205                                                  unsigned tail_ms); 
     206 
     207 
     208/** 
     209 * Get current echo canceller tail length, in miliseconds. The tail length  
     210 * will be zero if EC is not enabled. 
    208211 * 
    209212 * @param snd_port          The sound device port. 
     
    212215 * @return                  PJ_SUCCESS on success. 
    213216 */ 
    214 PJ_DECL(pj_status_t) pjmedia_snd_port_get_aec_tail(pjmedia_snd_port *snd_port, 
    215                                                    unsigned *p_length); 
     217PJ_DECL(pj_status_t) pjmedia_snd_port_get_ec_tail(pjmedia_snd_port *snd_port, 
     218                                                  unsigned *p_length); 
    216219 
    217220 
  • pjproject/trunk/pjmedia/src/pjmedia/echo_port.c

    r652 r653  
    1717 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
    1818 */ 
    19 #include <pjmedia/aec_port.h> 
    20 #include <pjmedia/aec.h> 
     19#include <pjmedia/echo_port.h> 
     20#include <pjmedia/echo.h> 
    2121#include <pjmedia/errno.h> 
    2222#include <pj/assert.h> 
     
    2525 
    2626 
    27 #define THIS_FILE   "aec_port.c" 
    28 #define SIGNATURE   PJMEDIA_PORT_SIGNATURE('A', 'E', 'C', ' ') 
     27#define THIS_FILE   "ec_port.c" 
     28#define SIGNATURE   PJMEDIA_PORT_SIGNATURE('E', 'C', 'H', 'O') 
    2929#define BUF_COUNT   32 
    3030 
    31 struct aec 
     31struct ec 
    3232{ 
    33     pjmedia_port    base; 
    34     pjmedia_port    *dn_port; 
    35     pjmedia_aec     *aec; 
     33    pjmedia_port        base; 
     34    pjmedia_port        *dn_port; 
     35    pjmedia_echo_state  *ec; 
    3636}; 
    3737 
    3838 
    39 static pj_status_t aec_put_frame(pjmedia_port *this_port,  
    40                                  const pjmedia_frame *frame); 
    41 static pj_status_t aec_get_frame(pjmedia_port *this_port,  
    42                                   pjmedia_frame *frame); 
    43 static pj_status_t aec_on_destroy(pjmedia_port *this_port); 
     39static pj_status_t ec_put_frame(pjmedia_port *this_port,  
     40                                const pjmedia_frame *frame); 
     41static pj_status_t ec_get_frame(pjmedia_port *this_port,  
     42                                pjmedia_frame *frame); 
     43static pj_status_t ec_on_destroy(pjmedia_port *this_port); 
    4444 
    4545 
    46 PJ_DEF(pj_status_t) pjmedia_aec_port_create( pj_pool_t *pool, 
     46PJ_DEF(pj_status_t) pjmedia_echo_port_create(pj_pool_t *pool, 
    4747                                             pjmedia_port *dn_port, 
    4848                                             unsigned tail_ms, 
     49                                             unsigned options, 
    4950                                             pjmedia_port **p_port ) 
    5051{ 
    51     const pj_str_t AEC = { "AEC", 3 }; 
    52     struct aec *aec; 
     52    const pj_str_t AEC = { "EC", 2 }; 
     53    struct ec *ec; 
    5354    pj_status_t status; 
    5455 
     
    5859 
    5960    /* Create the port and the AEC itself */ 
    60     aec = pj_pool_zalloc(pool, sizeof(struct aec)); 
     61    ec = pj_pool_zalloc(pool, sizeof(struct ec)); 
    6162     
    62     pjmedia_port_info_init(&aec->base.info, &AEC, SIGNATURE, 
     63    pjmedia_port_info_init(&ec->base.info, &AEC, SIGNATURE, 
    6364                           dn_port->info.clock_rate,  
    6465                           dn_port->info.channel_count,  
     
    6667                           dn_port->info.samples_per_frame); 
    6768 
    68     status = pjmedia_aec_create(pool, dn_port->info.clock_rate,  
    69                                 dn_port->info.samples_per_frame, 
    70                                 tail_ms, 0, &aec->aec); 
     69    status = pjmedia_echo_create(pool, dn_port->info.clock_rate,  
     70                                 dn_port->info.samples_per_frame, 
     71                                 tail_ms, options, &ec->ec); 
    7172    if (status != PJ_SUCCESS) 
    7273        return status; 
    7374 
    7475    /* More init */ 
    75     aec->dn_port = dn_port; 
    76     aec->base.get_frame = &aec_get_frame; 
    77     aec->base.put_frame = &aec_put_frame; 
    78     aec->base.on_destroy = &aec_on_destroy; 
     76    ec->dn_port = dn_port; 
     77    ec->base.get_frame = &ec_get_frame; 
     78    ec->base.put_frame = &ec_put_frame; 
     79    ec->base.on_destroy = &ec_on_destroy; 
    7980 
    8081    /* Done */ 
    81     *p_port = &aec->base; 
     82    *p_port = &ec->base; 
    8283 
    8384    return PJ_SUCCESS; 
     
    8586 
    8687 
    87 static pj_status_t aec_put_frame(pjmedia_port *this_port,  
     88static pj_status_t ec_put_frame( pjmedia_port *this_port,  
    8889                                 const pjmedia_frame *frame) 
    8990{ 
    90     struct aec *aec = (struct aec*)this_port; 
     91    struct ec *ec = (struct ec*)this_port; 
    9192 
    9293    PJ_ASSERT_RETURN(this_port->info.signature == SIGNATURE, PJ_EINVAL); 
    9394 
    9495    if (frame->type == PJMEDIA_FRAME_TYPE_NONE ) { 
    95         return pjmedia_port_put_frame(aec->dn_port, frame); 
     96        return pjmedia_port_put_frame(ec->dn_port, frame); 
    9697    } 
    9798 
     
    99100                     PJ_EINVAL); 
    100101 
    101     pjmedia_aec_capture(aec->aec, frame->buf, 0); 
     102    pjmedia_echo_capture(ec->ec, frame->buf, 0); 
    102103 
    103     return pjmedia_port_put_frame(aec->dn_port, frame); 
     104    return pjmedia_port_put_frame(ec->dn_port, frame); 
    104105} 
    105106 
    106107 
    107 static pj_status_t aec_get_frame( pjmedia_port *this_port,  
    108                                   pjmedia_frame *frame) 
     108static pj_status_t ec_get_frame( pjmedia_port *this_port,  
     109                                 pjmedia_frame *frame) 
    109110{ 
    110     struct aec *aec = (struct aec*)this_port; 
     111    struct ec *ec = (struct ec*)this_port; 
    111112    pj_status_t status; 
    112113 
    113114    PJ_ASSERT_RETURN(this_port->info.signature == SIGNATURE, PJ_EINVAL); 
    114115 
    115     status = pjmedia_port_get_frame(aec->dn_port, frame); 
     116    status = pjmedia_port_get_frame(ec->dn_port, frame); 
    116117    if (status!=PJ_SUCCESS || frame->type!=PJMEDIA_FRAME_TYPE_AUDIO) { 
    117118        pjmedia_zero_samples(frame->buf, this_port->info.samples_per_frame); 
    118119    } 
    119120 
    120     pjmedia_aec_playback(aec->aec, frame->buf); 
     121    pjmedia_echo_playback(ec->ec, frame->buf); 
    121122 
    122123    return status; 
     
    124125 
    125126 
    126 static pj_status_t aec_on_destroy(pjmedia_port *this_port) 
     127static pj_status_t ec_on_destroy(pjmedia_port *this_port) 
    127128{ 
    128     struct aec *aec = (struct aec*)this_port; 
     129    struct ec *ec = (struct ec*)this_port; 
    129130 
    130131    PJ_ASSERT_RETURN(this_port->info.signature == SIGNATURE, PJ_EINVAL); 
    131132 
    132     pjmedia_aec_destroy(aec->aec); 
     133    pjmedia_echo_destroy(ec->ec); 
    133134 
    134135    return PJ_SUCCESS; 
  • pjproject/trunk/pjmedia/src/pjmedia/echo_speex.c

    r652 r653  
    1818 */ 
    1919 
    20 #include <pjmedia/aec.h> 
     20#include <pjmedia/echo.h> 
    2121#include <pjmedia/errno.h> 
    2222#include <pjmedia/silencedet.h> 
     
    3030 
    3131 
    32 #define THIS_FILE   "aec_speex.c" 
     32#define THIS_FILE   "echo_speex.c" 
    3333#define BUF_COUNT   8 
     34 
     35/* 
     36 * Prototypes 
     37 */ 
     38PJ_DECL(pj_status_t) speex_aec_create(pj_pool_t *pool, 
     39                                      unsigned clock_rate, 
     40                                      unsigned samples_per_frame, 
     41                                      unsigned tail_ms, 
     42                                      unsigned options, 
     43                                      void **p_state ); 
     44PJ_DECL(pj_status_t) speex_aec_destroy(void *state ); 
     45PJ_DECL(pj_status_t) speex_aec_playback(void *state, 
     46                                        pj_int16_t *play_frm ); 
     47PJ_DECL(pj_status_t) speex_aec_capture(void *state, 
     48                                       pj_int16_t *rec_frm, 
     49                                       unsigned options ); 
     50PJ_DECL(pj_status_t) speex_aec_cancel_echo(void *state, 
     51                                           pj_int16_t *rec_frm, 
     52                                           const pj_int16_t *play_frm, 
     53                                           unsigned options, 
     54                                           void *reserved ); 
    3455 
    3556 
     
    3960}; 
    4061 
    41 struct pjmedia_aec 
     62typedef struct speex_ec 
    4263{ 
    4364    SpeexEchoState       *state; 
     
    5475    unsigned         wpos;              /* Index to put newest frame.       */ 
    5576    struct frame     frames[BUF_COUNT]; /* Playback frame buffers.          */ 
    56 }; 
     77} speex_ec; 
    5778 
    5879 
     
    6182 * Create the AEC.  
    6283 */ 
    63 PJ_DEF(pj_status_t) pjmedia_aec_create( pj_pool_t *pool, 
    64                                         unsigned clock_rate, 
    65                                         unsigned samples_per_frame, 
    66                                         unsigned tail_ms, 
    67                                         unsigned options, 
    68                                         pjmedia_aec **p_aec ) 
    69 { 
    70     pjmedia_aec *aec; 
     84PJ_DEF(pj_status_t) speex_aec_create(pj_pool_t *pool, 
     85                                     unsigned clock_rate, 
     86                                     unsigned samples_per_frame, 
     87                                     unsigned tail_ms, 
     88                                     unsigned options, 
     89                                     void **p_echo ) 
     90{ 
     91    speex_ec *echo; 
    7192    int sampling_rate; 
    7293    unsigned i; 
     94    int disabled; 
    7395    pj_status_t status; 
    7496 
    75     *p_aec = NULL; 
    76  
    77     aec = pj_pool_zalloc(pool, sizeof(pjmedia_aec)); 
    78     PJ_ASSERT_RETURN(aec != NULL, PJ_ENOMEM); 
    79  
    80     status = pj_lock_create_simple_mutex(pool, "aec%p", &aec->lock); 
    81     if (status != PJ_SUCCESS) 
    82         return status; 
    83  
    84     aec->samples_per_frame = samples_per_frame; 
    85     aec->options = options; 
    86  
    87     aec->state = speex_echo_state_init(samples_per_frame, 
     97    *p_echo = NULL; 
     98 
     99    echo = pj_pool_zalloc(pool, sizeof(speex_ec)); 
     100    PJ_ASSERT_RETURN(echo != NULL, PJ_ENOMEM); 
     101 
     102    if (options & PJMEDIA_ECHO_NO_LOCK) { 
     103        status = pj_lock_create_null_mutex(pool, "aec%p", &echo->lock); 
     104        if (status != PJ_SUCCESS) 
     105            return status; 
     106    } else { 
     107        status = pj_lock_create_simple_mutex(pool, "aec%p", &echo->lock); 
     108        if (status != PJ_SUCCESS) 
     109            return status; 
     110    } 
     111 
     112    echo->samples_per_frame = samples_per_frame; 
     113    echo->options = options; 
     114 
     115    echo->state = speex_echo_state_init(samples_per_frame, 
    88116                                        clock_rate * tail_ms / 1000); 
    89     if (aec->state == NULL) { 
    90         pj_lock_destroy(aec->lock); 
     117    if (echo->state == NULL) { 
     118        pj_lock_destroy(echo->lock); 
    91119        return PJ_ENOMEM; 
    92120    } 
    93121 
    94     aec->preprocess = speex_preprocess_state_init(samples_per_frame,  
    95                                                   clock_rate); 
    96     if (aec->preprocess == NULL) { 
    97         speex_echo_state_destroy(aec->state); 
    98         pj_lock_destroy(aec->lock); 
     122    echo->preprocess = speex_preprocess_state_init(samples_per_frame,  
     123                                                   clock_rate); 
     124    if (echo->preprocess == NULL) { 
     125        speex_echo_state_destroy(echo->state); 
     126        pj_lock_destroy(echo->lock); 
    99127        return PJ_ENOMEM; 
    100128    } 
     129 
     130    /* Disable all preprocessing, we only want echo cancellation */ 
     131    disabled = 0; 
     132    speex_preprocess_ctl(echo->preprocess, SPEEX_PREPROCESS_SET_DENOISE,  
     133                         &disabled); 
     134    speex_preprocess_ctl(echo->preprocess, SPEEX_PREPROCESS_SET_AGC,  
     135                         &disabled); 
     136    speex_preprocess_ctl(echo->preprocess, SPEEX_PREPROCESS_SET_VAD,  
     137                         &disabled); 
     138    speex_preprocess_ctl(echo->preprocess, SPEEX_PREPROCESS_SET_DEREVERB,  
     139                         &disabled); 
    101140 
    102141    /* Set sampling rate */ 
    103142    sampling_rate = clock_rate; 
    104     speex_echo_ctl(aec->state, SPEEX_ECHO_SET_SAMPLING_RATE,  
     143    speex_echo_ctl(echo->state, SPEEX_ECHO_SET_SAMPLING_RATE,  
    105144                   &sampling_rate); 
    106145 
    107146    /* Create temporary frame for echo cancellation */ 
    108     aec->tmp_frame = pj_pool_zalloc(pool, 2 * samples_per_frame); 
    109     PJ_ASSERT_RETURN(aec->tmp_frame != NULL, PJ_ENOMEM); 
     147    echo->tmp_frame = pj_pool_zalloc(pool, 2 * samples_per_frame); 
     148    PJ_ASSERT_RETURN(echo->tmp_frame != NULL, PJ_ENOMEM); 
    110149 
    111150    /* Create temporary frame to receive residue */ 
    112     aec->residue = pj_pool_zalloc(pool, sizeof(spx_int32_t) *  
     151    echo->residue = pj_pool_zalloc(pool, sizeof(spx_int32_t) *  
    113152                                            samples_per_frame); 
    114     PJ_ASSERT_RETURN(aec->residue != NULL, PJ_ENOMEM); 
     153    PJ_ASSERT_RETURN(echo->residue != NULL, PJ_ENOMEM); 
    115154 
    116155    /* Create internal playback buffers */ 
    117156    for (i=0; i<BUF_COUNT; ++i) { 
    118         aec->frames[i].buf = pj_pool_zalloc(pool, samples_per_frame * 2); 
    119         PJ_ASSERT_RETURN(aec->frames[i].buf != NULL, PJ_ENOMEM); 
     157        echo->frames[i].buf = pj_pool_zalloc(pool, samples_per_frame * 2); 
     158        PJ_ASSERT_RETURN(echo->frames[i].buf != NULL, PJ_ENOMEM); 
    120159    } 
    121160 
    122161 
    123162    /* Done */ 
    124     *p_aec = aec; 
    125  
    126     PJ_LOG(4,(THIS_FILE, "Echo canceller/AEC created, clock_rate=%d, " 
     163    *p_echo = echo; 
     164 
     165    PJ_LOG(4,(THIS_FILE, "Speex Echo canceller/AEC created, clock_rate=%d, " 
    127166                         "samples per frame=%d, tail length=%d ms",  
    128167                         clock_rate, 
     
    137176 * Destroy AEC 
    138177 */ 
    139 PJ_DEF(pj_status_t) pjmedia_aec_destroy(pjmedia_aec *aec ) 
    140 { 
    141     PJ_ASSERT_RETURN(aec && aec->state, PJ_EINVAL); 
    142  
    143     if (aec->lock) 
    144         pj_lock_acquire(aec->lock); 
    145  
    146     if (aec->state) { 
    147         speex_echo_state_destroy(aec->state); 
    148         aec->state = NULL; 
    149     } 
    150  
    151     if (aec->preprocess) { 
    152         speex_preprocess_state_destroy(aec->preprocess); 
    153         aec->preprocess = NULL; 
    154     } 
    155  
    156     if (aec->lock) { 
    157         pj_lock_destroy(aec->lock); 
    158         aec->lock = NULL; 
     178PJ_DEF(pj_status_t) speex_aec_destroy(void *state ) 
     179{ 
     180    speex_ec *echo = state; 
     181 
     182    PJ_ASSERT_RETURN(echo && echo->state, PJ_EINVAL); 
     183 
     184    if (echo->lock) 
     185        pj_lock_acquire(echo->lock); 
     186 
     187    if (echo->state) { 
     188        speex_echo_state_destroy(echo->state); 
     189        echo->state = NULL; 
     190    } 
     191 
     192    if (echo->preprocess) { 
     193        speex_preprocess_state_destroy(echo->preprocess); 
     194        echo->preprocess = NULL; 
     195    } 
     196 
     197    if (echo->lock) { 
     198        pj_lock_destroy(echo->lock); 
     199        echo->lock = NULL; 
    159200    } 
    160201 
     
    166207 * Let the AEC knows that a frame has been played to the speaker. 
    167208 */ 
    168 PJ_DEF(pj_status_t) pjmedia_aec_playback(pjmedia_aec *aec, 
    169                                          pj_int16_t *play_frm ) 
    170 { 
     209PJ_DEF(pj_status_t) speex_aec_playback(void *state, 
     210                                       pj_int16_t *play_frm ) 
     211{ 
     212    speex_ec *echo = state; 
     213 
    171214    /* Sanity checks */ 
    172     PJ_ASSERT_RETURN(aec && play_frm, PJ_EINVAL); 
     215    PJ_ASSERT_RETURN(echo && play_frm, PJ_EINVAL); 
    173216 
    174217    /* The AEC must be configured to support internal playback buffer */ 
    175     PJ_ASSERT_RETURN(aec->frames[0].buf != NULL, PJ_EINVALIDOP); 
    176  
    177     pj_lock_acquire(aec->lock); 
     218    PJ_ASSERT_RETURN(echo->frames[0].buf != NULL, PJ_EINVALIDOP); 
     219 
     220    pj_lock_acquire(echo->lock); 
    178221 
    179222    /* Check for overflows */ 
    180     if (aec->wpos == aec->rpos) { 
    181         PJ_LOG(5,(THIS_FILE, "AEC overflow (playback runs faster, " 
     223    if (echo->wpos == echo->rpos) { 
     224        PJ_LOG(5,(THIS_FILE, "Speex AEC overflow (playback runs faster, " 
    182225                             "wpos=%d, rpos=%d)", 
    183                              aec->wpos, aec->rpos)); 
    184         aec->rpos = (aec->wpos - BUF_COUNT/2) % BUF_COUNT; 
    185         speex_echo_state_reset(aec->state); 
     226                             echo->wpos, echo->rpos)); 
     227        echo->rpos = (echo->wpos - BUF_COUNT/2) % BUF_COUNT; 
     228        speex_echo_state_reset(echo->state); 
    186229    } 
    187230 
    188231    /* Save fhe frame */ 
    189     pjmedia_copy_samples(aec->frames[aec->wpos].buf, 
    190                          play_frm, aec->samples_per_frame); 
    191     aec->wpos = (aec->wpos+1) % BUF_COUNT; 
    192  
    193     pj_lock_release(aec->lock); 
     232    pjmedia_copy_samples(echo->frames[echo->wpos].buf, 
     233                         play_frm, echo->samples_per_frame); 
     234    echo->wpos = (echo->wpos+1) % BUF_COUNT; 
     235 
     236    pj_lock_release(echo->lock); 
    194237 
    195238    return PJ_SUCCESS; 
     
    200243 * Let the AEC knows that a frame has been captured from the microphone. 
    201244 */ 
    202 PJ_DEF(pj_status_t) pjmedia_aec_capture( pjmedia_aec *aec, 
    203                                          pj_int16_t *rec_frm, 
    204                                          unsigned options ) 
    205 { 
     245PJ_DEF(pj_status_t) speex_aec_capture( void *state, 
     246                                       pj_int16_t *rec_frm, 
     247                                       unsigned options ) 
     248{ 
     249    speex_ec *echo = state; 
    206250    pj_status_t status; 
    207251 
    208252    /* Sanity checks */ 
    209     PJ_ASSERT_RETURN(aec && rec_frm, PJ_EINVAL); 
     253    PJ_ASSERT_RETURN(echo && rec_frm, PJ_EINVAL); 
    210254 
    211255    /* The AEC must be configured to support internal playback buffer */ 
    212     PJ_ASSERT_RETURN(aec->frames[0].buf != NULL, PJ_EINVALIDOP); 
     256    PJ_ASSERT_RETURN(echo->frames[0].buf != NULL, PJ_EINVALIDOP); 
    213257 
    214258    /* Lock mutex */ 
    215     pj_lock_acquire(aec->lock); 
     259    pj_lock_acquire(echo->lock); 
    216260 
    217261 
    218262    /* Check for underflow */ 
    219     if (aec->rpos == aec->wpos) { 
     263    if (echo->rpos == echo->wpos) { 
    220264        /* Return frame as it is */ 
    221         pj_lock_release(aec->lock); 
    222  
    223         PJ_LOG(5,(THIS_FILE, "AEC underflow (capture runs faster than " 
     265        pj_lock_release(echo->lock); 
     266 
     267        PJ_LOG(5,(THIS_FILE, "Speex AEC underflow (capture runs faster than " 
    224268                             "playback, wpos=%d, rpos=%d)",  
    225                              aec->wpos, aec->rpos)); 
    226         aec->rpos = (aec->wpos - BUF_COUNT/2) % BUF_COUNT; 
    227         speex_echo_state_reset(aec->state); 
     269                             echo->wpos, echo->rpos)); 
     270        echo->rpos = (echo->wpos - BUF_COUNT/2) % BUF_COUNT; 
     271        speex_echo_state_reset(echo->state); 
    228272 
    229273        return PJ_SUCCESS; 
     
    232276 
    233277    /* Cancel echo */ 
    234     status = pjmedia_aec_cancel_echo(aec, rec_frm,  
    235                                      aec->frames[aec->rpos].buf, options, 
    236                                      NULL); 
    237  
    238     aec->rpos = (aec->rpos + 1) % BUF_COUNT; 
    239  
    240     pj_lock_release(aec->lock); 
     278    status = speex_aec_cancel_echo(echo, rec_frm,  
     279                                   echo->frames[echo->rpos].buf, options, 
     280                                   NULL); 
     281 
     282    echo->rpos = (echo->rpos + 1) % BUF_COUNT; 
     283 
     284    pj_lock_release(echo->lock); 
    241285    return status; 
    242286} 
     
    246290 * Perform echo cancellation. 
    247291 */ 
    248 PJ_DEF(pj_status_t) pjmedia_aec_cancel_echo( pjmedia_aec *aec, 
    249                                              pj_int16_t *rec_frm, 
    250                                              const pj_int16_t *play_frm, 
    251                                              unsigned options, 
    252                                              void *reserved ) 
    253 { 
     292PJ_DEF(pj_status_t) speex_aec_cancel_echo( void *state, 
     293                                           pj_int16_t *rec_frm, 
     294                                           const pj_int16_t *play_frm, 
     295                                           unsigned options, 
     296                                           void *reserved ) 
     297{ 
     298    speex_ec *echo = state; 
     299 
    254300    /* Sanity checks */ 
    255     PJ_ASSERT_RETURN(aec && rec_frm && play_frm && options==0 && 
     301    PJ_ASSERT_RETURN(echo && rec_frm && play_frm && options==0 && 
    256302                     reserved==NULL, PJ_EINVAL); 
    257303 
    258304    /* Cancel echo, put output in temporary buffer */ 
    259     speex_echo_cancel(aec->state, (const spx_int16_t*)rec_frm,  
     305    speex_echo_cancel(echo->state, (const spx_int16_t*)rec_frm,  
    260306                      (const spx_int16_t*)play_frm,  
    261                       (spx_int16_t*)aec->tmp_frame,  
    262                       aec->residue); 
     307                      (spx_int16_t*)echo->tmp_frame,  
     308                      echo->residue); 
    263309 
    264310 
    265311    /* Preprocess output */ 
    266     speex_preprocess(aec->preprocess, (spx_int16_t*)aec->tmp_frame,  
    267                      aec->residue); 
     312    speex_preprocess(echo->preprocess, (spx_int16_t*)echo->tmp_frame,  
     313                     echo->residue); 
    268314 
    269315    /* Copy temporary buffer back to original rec_frm */ 
    270     pjmedia_copy_samples(rec_frm, aec->tmp_frame, aec->samples_per_frame); 
     316    pjmedia_copy_samples(rec_frm, echo->tmp_frame, echo->samples_per_frame); 
    271317 
    272318    return PJ_SUCCESS; 
  • pjproject/trunk/pjmedia/src/pjmedia/sound_port.c

    r650 r653  
    1818 */ 
    1919#include <pjmedia/sound_port.h> 
    20 #include <pjmedia/aec.h> 
     20#include <pjmedia/echo.h> 
    2121#include <pjmedia/errno.h> 
    2222#include <pjmedia/plc.h> 
     
    5757    unsigned             options; 
    5858 
    59     pjmedia_aec         *aec; 
     59    pjmedia_echo_state  *ec_state; 
    6060    unsigned             aec_tail_len; 
    6161    pjmedia_plc         *plc; 
     
    116116        pjmedia_plc_save(snd_port->plc, output); 
    117117 
    118     if (snd_port->aec) { 
    119         pjmedia_aec_playback(snd_port->aec, output); 
     118    if (snd_port->ec_state) { 
     119        pjmedia_echo_playback(snd_port->ec_state, output); 
    120120    } 
    121121 
     
    165165 
    166166    /* Cancel echo */ 
    167     if (snd_port->aec) { 
    168         pjmedia_aec_capture(snd_port->aec, input, 0); 
     167    if (snd_port->ec_state) { 
     168        pjmedia_echo_capture(snd_port->ec_state, input, 0); 
    169169    } 
    170170 
     
    252252    /* Create AEC only when direction is full duplex */ 
    253253    if (snd_port->dir == PJMEDIA_DIR_CAPTURE_PLAYBACK) { 
    254         status = pjmedia_snd_port_set_aec(snd_port, pool, AEC_TAIL); 
     254        status = pjmedia_snd_port_set_ec_tail(snd_port, pool, AEC_TAIL); 
    255255        if (status != PJ_SUCCESS) { 
    256256            PJ_LOG(4,(THIS_FILE, "Unable to create AEC")); 
    257             snd_port->aec = NULL; 
     257            snd_port->ec_state = NULL; 
    258258        } 
    259259    } 
     
    285285 
    286286    /* Destroy AEC */ 
    287     if (snd_port->aec) { 
    288         pjmedia_aec_destroy(snd_port->aec); 
    289         snd_port->aec = NULL; 
     287    if (snd_port->ec_state) { 
     288        pjmedia_echo_destroy(snd_port->ec_state); 
     289        snd_port->ec_state = NULL; 
    290290    } 
    291291 
     
    433433 * Enable AEC 
    434434 */ 
    435 PJ_DEF(pj_status_t) pjmedia_snd_port_set_aec( pjmedia_snd_port *snd_port, 
    436                                               pj_pool_t *pool, 
    437                                               unsigned tail_ms) 
     435PJ_DEF(pj_status_t) pjmedia_snd_port_set_ec_tail(pjmedia_snd_port *snd_port, 
     436                                                 pj_pool_t *pool, 
     437                                                 unsigned tail_ms) 
    438438{ 
    439439    pj_status_t status; 
     
    445445 
    446446    /* Destroy AEC */ 
    447     if (snd_port->aec) { 
    448         pjmedia_aec_destroy(snd_port->aec); 
    449         snd_port->aec = NULL; 
     447    if (snd_port->ec_state) { 
     448        pjmedia_echo_destroy(snd_port->ec_state); 
     449        snd_port->ec_state = NULL; 
    450450    } 
    451451 
     
    453453 
    454454    if (tail_ms != 0) { 
    455         status = pjmedia_aec_create(pool, snd_port->clock_rate,  
     455        status = pjmedia_echo_create(pool, snd_port->clock_rate,  
    456456                                    snd_port->samples_per_frame,  
    457                                     tail_ms, 0, &snd_port->aec); 
     457                                    tail_ms, 0, &snd_port->ec_state); 
    458458        if (status != PJ_SUCCESS) 
    459             snd_port->aec = NULL; 
     459            snd_port->ec_state = NULL; 
    460460    } else { 
    461         PJ_LOG(4,(THIS_FILE, "AEC disabled in the sound port")); 
     461        PJ_LOG(4,(THIS_FILE, "Echo canceller is now disabled in the " 
     462                             "sound port")); 
    462463        status = PJ_SUCCESS; 
    463464    } 
     
    468469 
    469470/* Get AEC tail length */ 
    470 PJ_DEF(pj_status_t) pjmedia_snd_port_get_aec_tail( pjmedia_snd_port *snd_port, 
    471                                                    unsigned *p_length) 
     471PJ_DEF(pj_status_t) pjmedia_snd_port_get_ec_tail( pjmedia_snd_port *snd_port, 
     472                                                  unsigned *p_length) 
    472473{ 
    473474    PJ_ASSERT_RETURN(snd_port && p_length, PJ_EINVAL); 
    474     *p_length =  snd_port->aec ? snd_port->aec_tail_len : 0; 
     475    *p_length =  snd_port->ec_state ? snd_port->aec_tail_len : 0; 
    475476    return PJ_SUCCESS; 
    476477} 
  • pjproject/trunk/pjsip-apps/build/Samples.mak

    r578 r653  
    2727                $(subst /,$(HOST_PSEP),$(PJMEDIA_CODEC_LIB)) \ 
    2828                $(subst /,$(HOST_PSEP),$(PJMEDIA_LIB)) \ 
     29                $(subst /,$(HOST_PSEP),$(PJMEDIA_CODEC_LIB)) \ 
    2930                $(subst /,$(HOST_PSEP),$(PJLIB_UTIL_LIB)) \ 
    3031                $(subst /,$(HOST_PSEP),$(PJLIB_LIB)) 
  • pjproject/trunk/pjsip/docs/PJSUA-TESTING.txt

    r648 r653  
    3030MULTIPLE ACCOUNTS (combo.cfg) 
    3131 
     32DIGEST with qop=auth (sipcenter?) 
    3233 
    3334AUDIO QUALITY 
  • pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h

    r651 r653  
    25032503 
    25042504/** 
    2505  * Configure the AEC settings of the sound port. 
     2505 * Configure the echo canceller tail length of the sound port. 
    25062506 * 
    25072507 * @param tail_ms       The tail length, in miliseconds. Set to zero to 
     
    25102510 * @return              PJ_SUCCESS on success. 
    25112511 */ 
    2512 PJ_DECL(pj_status_t) pjsua_set_aec(unsigned tail_ms); 
    2513  
    2514  
    2515 /** 
    2516  * Get current AEC tail length. 
     2512PJ_DECL(pj_status_t) pjsua_set_ec_tail(unsigned tail_ms); 
     2513 
     2514 
     2515/** 
     2516 * Get current echo canceller tail length. 
    25172517 * 
    25182518 * @param p_tail_ms     Pointer to receive the tail length, in miliseconds.  
     
    25212521 * @return              PJ_SUCCESS on success. 
    25222522 */ 
    2523 PJ_DECL(pj_status_t) pjsua_get_aec(unsigned *p_tail_ms); 
     2523PJ_DECL(pj_status_t) pjsua_get_ec_tail(unsigned *p_tail_ms); 
    25242524 
    25252525 
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c

    r649 r653  
    970970 
    971971    /* Set AEC */ 
    972     pjmedia_snd_port_set_aec(pjsua_var.snd_port, pjsua_var.pool,  
    973                              pjsua_var.media_cfg.ec_tail_len); 
     972    pjmedia_snd_port_set_ec_tail(pjsua_var.snd_port, pjsua_var.pool,  
     973                                 pjsua_var.media_cfg.ec_tail_len); 
    974974 
    975975    /* Connect sound port to the bridge */        
     
    10451045 * Configure the AEC settings of the sound port. 
    10461046 */ 
    1047 PJ_DEF(pj_status_t) pjsua_set_aec(unsigned tail_ms) 
     1047PJ_DEF(pj_status_t) pjsua_set_ec_tail(unsigned tail_ms) 
    10481048{ 
    10491049    pjsua_var.media_cfg.ec_tail_len = tail_ms; 
    10501050 
    10511051    if (pjsua_var.snd_port) 
    1052         return pjmedia_snd_port_set_aec(pjsua_var.snd_port, pjsua_var.pool, 
    1053                                         tail_ms); 
     1052        return pjmedia_snd_port_set_ec_tail(pjsua_var.snd_port, pjsua_var.pool, 
     1053                                            tail_ms); 
    10541054     
    10551055    return PJ_SUCCESS; 
     
    10601060 * Get current AEC tail length. 
    10611061 */ 
    1062 PJ_DEF(pj_status_t) pjsua_get_aec(unsigned *p_tail_ms) 
     1062PJ_DEF(pj_status_t) pjsua_get_ec_tail(unsigned *p_tail_ms) 
    10631063{ 
    10641064    *p_tail_ms = pjsua_var.media_cfg.ec_tail_len; 
Note: See TracChangeset for help on using the changeset viewer.