From a1fbbe2cf8eef34d0b2fda5c5a3d12680dca8136 Mon Sep 17 00:00:00 2001 From: Nanang Izzuddin Date: Tue, 26 Aug 2008 20:09:03 +0000 Subject: Added PLC & VAD features to codec L16. git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@2247 74dad513-b988-da41-8d7b-12977e46ad98 --- pjmedia/src/pjmedia-codec/l16.c | 165 +++++++++++++++++++++++++++++++--------- 1 file changed, 127 insertions(+), 38 deletions(-) diff --git a/pjmedia/src/pjmedia-codec/l16.c b/pjmedia/src/pjmedia-codec/l16.c index 1c077dfa..26253c2f 100644 --- a/pjmedia/src/pjmedia-codec/l16.c +++ b/pjmedia/src/pjmedia-codec/l16.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include #include #include @@ -31,6 +33,8 @@ */ #if defined(PJMEDIA_HAS_L16_CODEC) && PJMEDIA_HAS_L16_CODEC != 0 +#define PLC_DISABLED 0 + static const pj_str_t STR_L16 = { "L16", 3 }; @@ -77,6 +81,11 @@ static pj_status_t l16_decode( pjmedia_codec *codec, const struct pjmedia_frame *input, unsigned output_buf_len, struct pjmedia_frame *output); +#if !PLC_DISABLED +static pj_status_t l16_recover(pjmedia_codec *codec, + unsigned output_buf_len, + struct pjmedia_frame *output); +#endif /* Definition for L16 codec operations. */ static pjmedia_codec_op l16_op = @@ -87,7 +96,8 @@ static pjmedia_codec_op l16_op = &l16_modify, &l16_parse, &l16_encode, - &l16_decode + &l16_decode, + &l16_recover }; /* Definition for L16 codec factory operations. */ @@ -107,14 +117,23 @@ static struct l16_factory pjmedia_endpt *endpt; pj_pool_t *pool; pj_mutex_t *mutex; - pjmedia_codec codec_list; } l16_factory; /* L16 codec private data. */ struct l16_data { - unsigned frame_size; /* Frame size, in bytes */ + pj_pool_t *pool; + unsigned frame_size; /* Frame size, in bytes */ + unsigned clock_rate; /* Clock rate */ + + pj_bool_t plc_enabled; +#if !PLC_DISABLED + pjmedia_plc *plc; +#endif + pj_bool_t vad_enabled; + pjmedia_silence_det *vad; + pj_timestamp last_tx; }; @@ -139,8 +158,6 @@ PJ_DEF(pj_status_t) pjmedia_codec_l16_init(pjmedia_endpt *endpt, l16_factory.base.factory_data = NULL; l16_factory.endpt = endpt; - pj_list_init(&l16_factory.codec_list); - /* Create pool */ l16_factory.pool = pjmedia_endpt_create_pool(endpt, "l16", 4000, 4000); if (!l16_factory.pool) @@ -252,7 +269,10 @@ static pj_status_t l16_default_attr( pjmedia_codec_factory *factory, attr->setting.frm_per_pkt = 1; - /* Default all flag bits disabled. */ + attr->setting.vad = 1; +#if !PLC_DISABLED + attr->setting.plc = 1; +#endif return PJ_SUCCESS; } @@ -420,33 +440,48 @@ static pj_status_t l16_alloc_codec( pjmedia_codec_factory *factory, pjmedia_codec *codec = NULL; struct l16_data *data; unsigned ptime; + pj_pool_t *pool; + + pj_status_t status; PJ_ASSERT_RETURN(factory==&l16_factory.base, PJ_EINVAL); /* Lock mutex. */ pj_mutex_lock(l16_factory.mutex); - /* Allocate new codec if no more is available */ - if (pj_list_empty(&l16_factory.codec_list)) { - - codec = PJ_POOL_ALLOC_T(l16_factory.pool, pjmedia_codec); - codec->codec_data = pj_pool_alloc(l16_factory.pool, - sizeof(struct l16_data)); - codec->factory = factory; - codec->op = &l16_op; - } else { - codec = l16_factory.codec_list.next; - pj_list_erase(codec); - } + pool = pjmedia_endpt_create_pool(l16_factory.endpt, "l16", 4000, 4000); + codec = PJ_POOL_ZALLOC_T(pool, pjmedia_codec); + codec->codec_data = pj_pool_alloc(pool, sizeof(struct l16_data)); + codec->factory = factory; + codec->op = &l16_op; /* Init private data */ ptime = GET_PTIME(id->clock_rate); data = (struct l16_data*) codec->codec_data; data->frame_size = ptime * id->clock_rate * id->channel_cnt * 2 / 1000; + data->clock_rate = id->clock_rate; + data->pool = pool; + +#if !PLC_DISABLED + /* Create PLC */ + status = pjmedia_plc_create(pool, id->clock_rate, + data->frame_size >> 1, 0, + &data->plc); + if (status != PJ_SUCCESS) { + pj_mutex_unlock(l16_factory.mutex); + return status; + } +#endif - /* Zero the list, for error detection in l16_dealloc_codec */ - codec->next = codec->prev = NULL; + /* Create silence detector */ + status = pjmedia_silence_det_create(pool, id->clock_rate, + data->frame_size >> 1, + &data->vad); + if (status != PJ_SUCCESS) { + pj_mutex_unlock(l16_factory.mutex); + return status; + } *p_codec = codec; @@ -459,20 +494,18 @@ static pj_status_t l16_alloc_codec( pjmedia_codec_factory *factory, static pj_status_t l16_dealloc_codec(pjmedia_codec_factory *factory, pjmedia_codec *codec ) { - - PJ_ASSERT_RETURN(factory==&l16_factory.base, PJ_EINVAL); + struct l16_data *data; - /* Check that this node has not been deallocated before */ - pj_assert (codec->next==NULL && codec->prev==NULL); - if (codec->next!=NULL || codec->prev!=NULL) { - return PJ_EINVALIDOP; - } + PJ_ASSERT_RETURN(factory && codec, PJ_EINVAL); + PJ_ASSERT_RETURN(factory==&l16_factory.base, PJ_EINVAL); /* Lock mutex. */ pj_mutex_lock(l16_factory.mutex); - /* Insert at the back of the list */ - pj_list_insert_before(&l16_factory.codec_list, codec); + /* Just release codec data pool */ + data = (struct l16_data*) codec->codec_data; + pj_assert(data); + pj_pool_release(data->pool); /* Unlock mutex. */ pj_mutex_unlock(l16_factory.mutex); @@ -508,10 +541,14 @@ static pj_status_t l16_close( pjmedia_codec *codec ) static pj_status_t l16_modify(pjmedia_codec *codec, const pjmedia_codec_param *attr ) { - /* Don't want to do anything. */ - PJ_UNUSED_ARG(codec); - PJ_UNUSED_ARG(attr); - return PJ_EINVALIDOP; + struct l16_data *data = (struct l16_data*) codec->codec_data; + + pj_assert(data != NULL); + + data->vad_enabled = (attr->setting.vad != 0); + data->plc_enabled = (attr->setting.plc != 0); + + return PJ_SUCCESS; } static pj_status_t l16_parse( pjmedia_codec *codec, @@ -548,18 +585,43 @@ static pj_status_t l16_encode(pjmedia_codec *codec, unsigned output_buf_len, struct pjmedia_frame *output) { + struct l16_data *data = (struct l16_data*) codec->codec_data; const pj_int16_t *samp = (const pj_int16_t*) input->buf; const pj_int16_t *samp_end = samp + input->size/sizeof(pj_int16_t); pj_int16_t *samp_out = (pj_int16_t*) output->buf; - - PJ_UNUSED_ARG(codec); - + pj_assert(data && input && output); /* Check output buffer length */ if (output_buf_len < input->size) return PJMEDIA_CODEC_EFRMTOOSHORT; + /* Detect silence */ + if (data->vad_enabled) { + pj_bool_t is_silence; + pj_int32_t silence_duration; + + silence_duration = pj_timestamp_diff32(&data->last_tx, + &input->timestamp); + + is_silence = pjmedia_silence_det_detect(data->vad, + (const pj_int16_t*) input->buf, + (input->size >> 1), + NULL); + if (is_silence && + PJMEDIA_CODEC_MAX_SILENCE_PERIOD != -1 && + silence_duration < PJMEDIA_CODEC_MAX_SILENCE_PERIOD* + (int)data->clock_rate/1000) + { + output->type = PJMEDIA_FRAME_TYPE_NONE; + output->buf = NULL; + output->size = 0; + output->timestamp = input->timestamp; + return PJ_SUCCESS; + } else { + data->last_tx = input->timestamp; + } + } /* Encode */ #if defined(PJ_IS_LITTLE_ENDIAN) && PJ_IS_LITTLE_ENDIAN!=0 @@ -582,12 +644,13 @@ static pj_status_t l16_decode(pjmedia_codec *codec, unsigned output_buf_len, struct pjmedia_frame *output) { + struct l16_data *l16_data = (struct l16_data*) codec->codec_data; const pj_int16_t *samp = (const pj_int16_t*) input->buf; const pj_int16_t *samp_end = samp + input->size/sizeof(pj_int16_t); pj_int16_t *samp_out = (pj_int16_t*) output->buf; - - PJ_UNUSED_ARG(codec); + pj_assert(l16_data != NULL); + PJ_ASSERT_RETURN(input && output, PJ_EINVAL); /* Check output buffer length */ @@ -607,9 +670,35 @@ static pj_status_t l16_decode(pjmedia_codec *codec, output->type = PJMEDIA_FRAME_TYPE_AUDIO; output->size = input->size; +#if !PLC_DISABLED + if (l16_data->plc_enabled) + pjmedia_plc_save( l16_data->plc, (pj_int16_t*)output->buf); +#endif + return PJ_SUCCESS; } +#if !PLC_DISABLED +/* + * Recover lost frame. + */ +static pj_status_t l16_recover(pjmedia_codec *codec, + unsigned output_buf_len, + struct pjmedia_frame *output) +{ + struct l16_data *data = (struct l16_data*) codec->codec_data; + + PJ_ASSERT_RETURN(data->plc_enabled, PJ_EINVALIDOP); + + PJ_ASSERT_RETURN(output_buf_len >= data->frame_size, + PJMEDIA_CODEC_EPCMTOOSHORT); + + pjmedia_plc_generate(data->plc, (pj_int16_t*)output->buf); + output->size = data->frame_size; + + return PJ_SUCCESS; +} +#endif #endif /* PJMEDIA_HAS_L16_CODEC */ -- cgit v1.2.3