From 9d61f9ded11c24cef9c18962c65fda728e871568 Mon Sep 17 00:00:00 2001 From: Liong Sauw Ming Date: Sun, 15 May 2011 12:54:28 +0000 Subject: Fixed #1257: Option for using simple FIFO delay buffer in echo canceller. git-svn-id: http://svn.pjsip.org/repos/pjproject/branches/1.x@3567 74dad513-b988-da41-8d7b-12977e46ad98 --- pjmedia/include/pjmedia/delaybuf.h | 20 +++++++- pjmedia/include/pjmedia/echo.h | 10 +++- pjmedia/src/pjmedia/delaybuf.c | 97 ++++++++++++++++++++++---------------- pjmedia/src/pjmedia/echo_common.c | 5 +- 4 files changed, 88 insertions(+), 44 deletions(-) (limited to 'pjmedia') diff --git a/pjmedia/include/pjmedia/delaybuf.h b/pjmedia/include/pjmedia/delaybuf.h index 9dcad5ee..09b01bbb 100644 --- a/pjmedia/include/pjmedia/delaybuf.h +++ b/pjmedia/include/pjmedia/delaybuf.h @@ -63,6 +63,19 @@ PJ_BEGIN_DECL /** Opaque declaration for delay buffer. */ typedef struct pjmedia_delay_buf pjmedia_delay_buf; +/** + * Delay buffer options. + */ +typedef enum pjmedia_delay_buf_flag +{ + /** + * Use simple FIFO mechanism for the delay buffer, i.e. + * without WSOLA for expanding and shrinking audio samples. + */ + PJMEDIA_DELAY_BUF_SIMPLE_FIFO = 1 + +} pjmedia_delay_buf_flag; + /** * Create the delay buffer. Once the delay buffer is created, it will * enter learning state unless the delay argument is specified, which @@ -79,7 +92,12 @@ typedef struct pjmedia_delay_buf pjmedia_delay_buf; * in ms, if this value is negative or less than * one frame time, default maximum delay used is * 400 ms. - * @param options Option flags, must be zero for now. + * @param options Options. If PJMEDIA_DELAY_BUF_SIMPLE_FIFO is + * specified, then a simple FIFO mechanism + * will be used instead of the adaptive + * implementation (which uses WSOLA to expand + * or shrink audio samples). + * See #pjmedia_delay_buf_flag for other options. * @param p_b Pointer to receive the delay buffer instance. * * @return PJ_SUCCESS if the delay buffer has been diff --git a/pjmedia/include/pjmedia/echo.h b/pjmedia/include/pjmedia/echo.h index f2c2210c..ba7f8897 100644 --- a/pjmedia/include/pjmedia/echo.h +++ b/pjmedia/include/pjmedia/echo.h @@ -88,7 +88,15 @@ typedef enum pjmedia_echo_flag * for the echo canceller, but application will guarantee that echo * canceller will not be called by different threads at the same time. */ - PJMEDIA_ECHO_NO_LOCK = 16 + PJMEDIA_ECHO_NO_LOCK = 16, + + /** + * If PJMEDIA_ECHO_USE_SIMPLE_FIFO flag is specified, the delay buffer + * created for the echo canceller will use simple FIFO mechanism, i.e. + * without using WSOLA to expand and shrink audio samples. + */ + PJMEDIA_ECHO_USE_SIMPLE_FIFO = 32 + } pjmedia_echo_flag; diff --git a/pjmedia/src/pjmedia/delaybuf.c b/pjmedia/src/pjmedia/delaybuf.c index 39f0e618..82618275 100644 --- a/pjmedia/src/pjmedia/delaybuf.c +++ b/pjmedia/src/pjmedia/delaybuf.c @@ -99,9 +99,6 @@ PJ_DEF(pj_status_t) pjmedia_delay_buf_create( pj_pool_t *pool, PJ_ASSERT_RETURN(pool && samples_per_frame && clock_rate && channel_count && p_b, PJ_EINVAL); - PJ_ASSERT_RETURN(options==0, PJ_EINVAL); - - PJ_UNUSED_ARG(options); if (!name) { name = "delaybuf"; @@ -126,11 +123,16 @@ PJ_DEF(pj_status_t) pjmedia_delay_buf_create( pj_pool_t *pool, if (status != PJ_SUCCESS) return status; - /* Create WSOLA */ - status = pjmedia_wsola_create(pool, clock_rate, samples_per_frame, 1, - PJMEDIA_WSOLA_NO_FADING, &b->wsola); - if (status != PJ_SUCCESS) - return status; + if (!(options & PJMEDIA_DELAY_BUF_SIMPLE_FIFO)) { + /* Create WSOLA */ + status = pjmedia_wsola_create(pool, clock_rate, samples_per_frame, 1, + PJMEDIA_WSOLA_NO_FADING, &b->wsola); + if (status != PJ_SUCCESS) + return status; + PJ_LOG(5, (b->obj_name, "Using delay buffer with WSOLA.")); + } else { + PJ_LOG(5, (b->obj_name, "Using simple FIFO delay buffer.")); + } /* Finally, create mutex */ status = pj_lock_create_recursive_mutex(pool, b->obj_name, @@ -147,15 +149,17 @@ PJ_DEF(pj_status_t) pjmedia_delay_buf_create( pj_pool_t *pool, PJ_DEF(pj_status_t) pjmedia_delay_buf_destroy(pjmedia_delay_buf *b) { - pj_status_t status; + pj_status_t status = PJ_SUCCESS; PJ_ASSERT_RETURN(b, PJ_EINVAL); pj_lock_acquire(b->lock); - status = pjmedia_wsola_destroy(b->wsola); - if (status == PJ_SUCCESS) - b->wsola = NULL; + if (b->wsola) { + status = pjmedia_wsola_destroy(b->wsola); + if (status == PJ_SUCCESS) + b->wsola = NULL; + } pj_lock_release(b->lock); @@ -264,12 +268,14 @@ PJ_DEF(pj_status_t) pjmedia_delay_buf_put(pjmedia_delay_buf *b, pj_lock_acquire(b->lock); - update(b, OP_PUT); + if (b->wsola) { + update(b, OP_PUT); - status = pjmedia_wsola_save(b->wsola, frame, PJ_FALSE); - if (status != PJ_SUCCESS) { - pj_lock_release(b->lock); - return status; + status = pjmedia_wsola_save(b->wsola, frame, PJ_FALSE); + if (status != PJ_SUCCESS) { + pj_lock_release(b->lock); + return status; + } } /* Overflow checking */ @@ -277,13 +283,15 @@ PJ_DEF(pj_status_t) pjmedia_delay_buf_put(pjmedia_delay_buf *b, b->max_cnt) { unsigned erase_cnt; - - /* shrink one frame or just the diff? */ - //erase_cnt = b->samples_per_frame; - erase_cnt = pjmedia_circ_buf_get_len(b->circ_buf) + - b->samples_per_frame - b->max_cnt; - shrink_buffer(b, erase_cnt); + if (b->wsola) { + /* shrink one frame or just the diff? */ + //erase_cnt = b->samples_per_frame; + erase_cnt = pjmedia_circ_buf_get_len(b->circ_buf) + + b->samples_per_frame - b->max_cnt; + + shrink_buffer(b, erase_cnt); + } /* Check if shrinking failed or erased count is less than requested, * delaybuf needs to drop eldest samples, this is bad since the voice @@ -297,9 +305,9 @@ PJ_DEF(pj_status_t) pjmedia_delay_buf_put(pjmedia_delay_buf *b, pjmedia_circ_buf_adv_read_ptr(b->circ_buf, erase_cnt); - PJ_LOG(4,(b->obj_name,"Shrinking failed or insufficient, dropping" - " %d eldest samples, buf_cnt=%d", erase_cnt, - pjmedia_circ_buf_get_len(b->circ_buf))); + PJ_LOG(4,(b->obj_name,"%sDropping %d eldest samples, buf_cnt=%d", + (b->wsola? "Shrinking failed or insufficient. ": ""), + erase_cnt, pjmedia_circ_buf_get_len(b->circ_buf))); } } @@ -312,13 +320,14 @@ PJ_DEF(pj_status_t) pjmedia_delay_buf_put(pjmedia_delay_buf *b, PJ_DEF(pj_status_t) pjmedia_delay_buf_get( pjmedia_delay_buf *b, pj_int16_t frame[]) { - pj_status_t status; + pj_status_t status = PJ_SUCCESS; PJ_ASSERT_RETURN(b && frame, PJ_EINVAL); pj_lock_acquire(b->lock); - update(b, OP_GET); + if (b->wsola) + update(b, OP_GET); /* Starvation checking */ if (pjmedia_circ_buf_get_len(b->circ_buf) < b->samples_per_frame) { @@ -326,24 +335,29 @@ PJ_DEF(pj_status_t) pjmedia_delay_buf_get( pjmedia_delay_buf *b, PJ_LOG(4,(b->obj_name,"Underflow, buf_cnt=%d, will generate 1 frame", pjmedia_circ_buf_get_len(b->circ_buf))); - status = pjmedia_wsola_generate(b->wsola, frame); + if (b->wsola) { + status = pjmedia_wsola_generate(b->wsola, frame); - if (status == PJ_SUCCESS) { - TRACE__((b->obj_name,"Successfully generate 1 frame")); - if (pjmedia_circ_buf_get_len(b->circ_buf) == 0) { - pj_lock_release(b->lock); - return PJ_SUCCESS; - } + if (status == PJ_SUCCESS) { + TRACE__((b->obj_name,"Successfully generate 1 frame")); + if (pjmedia_circ_buf_get_len(b->circ_buf) == 0) { + pj_lock_release(b->lock); + return PJ_SUCCESS; + } - /* Put generated frame into buffer */ - pjmedia_circ_buf_write(b->circ_buf, frame, b->samples_per_frame); + /* Put generated frame into buffer */ + pjmedia_circ_buf_write(b->circ_buf, frame, + b->samples_per_frame); + } + } - } else { + if (!b->wsola || status != PJ_SUCCESS) { unsigned buf_len = pjmedia_circ_buf_get_len(b->circ_buf); /* Give all what delay buffer has, then pad with zeroes */ - PJ_LOG(4,(b->obj_name,"Error generating frame, status=%d", - status)); + if (b->wsola) + PJ_LOG(4,(b->obj_name,"Error generating frame, status=%d", + status)); pjmedia_circ_buf_read(b->circ_buf, frame, buf_len); pjmedia_zero_samples(&frame[buf_len], @@ -378,7 +392,8 @@ PJ_DEF(pj_status_t) pjmedia_delay_buf_reset(pjmedia_delay_buf *b) pjmedia_circ_buf_reset(b->circ_buf); /* Reset WSOLA */ - pjmedia_wsola_reset(b->wsola, 0); + if (b->wsola) + pjmedia_wsola_reset(b->wsola, 0); pj_lock_release(b->lock); diff --git a/pjmedia/src/pjmedia/echo_common.c b/pjmedia/src/pjmedia/echo_common.c index 1cb2e311..532c37be 100644 --- a/pjmedia/src/pjmedia/echo_common.c +++ b/pjmedia/src/pjmedia/echo_common.c @@ -144,6 +144,7 @@ PJ_DEF(pj_status_t) pjmedia_echo_create2(pj_pool_t *pool, pjmedia_echo_state **p_echo ) { unsigned ptime, lat_cnt; + unsigned delay_buf_opt = 0; pjmedia_echo_state *ec; pj_status_t status; @@ -211,10 +212,12 @@ PJ_DEF(pj_status_t) pjmedia_echo_create2(pj_pool_t *pool, } /* Create delay buffer to compensate drifts */ + if (options & PJMEDIA_ECHO_USE_SIMPLE_FIFO) + delay_buf_opt |= PJMEDIA_DELAY_BUF_SIMPLE_FIFO; status = pjmedia_delay_buf_create(ec->pool, ec->obj_name, clock_rate, samples_per_frame, channel_count, (PJMEDIA_SOUND_BUFFER_COUNT+1) * ptime, - 0, &ec->delay_buf); + delay_buf_opt, &ec->delay_buf); if (status != PJ_SUCCESS) { pj_pool_release(pool); return status; -- cgit v1.2.3