From 478d7fed9b2d5713500c91dd296356b7ea939502 Mon Sep 17 00:00:00 2001 From: Nanang Izzuddin Date: Fri, 11 Jun 2010 13:38:42 +0000 Subject: Close #1072: - Added API pjmedia_codec_g722_set_pcm_shift() to enable configurable level-adjusment setting. - Also added macro PJMEDIA_G722_DEFAULT_PCM_SHIFT (default value is 2) to accomplish 14-16 bit PCM conversion for G722 input/output. - Added a feature in G722 to stop level-adjusment/PCM-shifting when clipping occured, compile-time configurable via PJMEDIA_G722_STOP_PCM_SHIFT_ON_CLIPPING macro. git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@3202 74dad513-b988-da41-8d7b-12977e46ad98 --- pjmedia/include/pjmedia-codec/config.h | 34 ++++++++++++++++++++++ pjmedia/include/pjmedia-codec/g722.h | 15 ++++++++++ pjmedia/src/pjmedia-codec/g722.c | 48 +++++++++++++++++++++++++++++++ pjmedia/src/pjmedia-codec/g722/g722_dec.c | 5 +--- pjmedia/src/pjmedia-codec/g722/g722_enc.c | 2 +- 5 files changed, 99 insertions(+), 5 deletions(-) (limited to 'pjmedia') diff --git a/pjmedia/include/pjmedia-codec/config.h b/pjmedia/include/pjmedia-codec/config.h index 79322bb2..3dbb5c56 100644 --- a/pjmedia/include/pjmedia-codec/config.h +++ b/pjmedia/include/pjmedia-codec/config.h @@ -97,6 +97,40 @@ #endif +/** + * Default G.722 codec encoder and decoder level adjustment. The G.722 + * specifies that it uses 14 bit PCM for input and output, while PJMEDIA + * normally uses 16 bit PCM, so the conversion is done by applying + * level adjustment. If the value is non-zero, then PCM input samples to + * the encoder will be shifted right by this value, and similarly PCM + * output samples from the decoder will be shifted left by this value. + * + * This can be changed at run-time after initialization by calling + * #pjmedia_codec_g722_set_pcm_shift(). + * + * Default: 2. + */ +#ifndef PJMEDIA_G722_DEFAULT_PCM_SHIFT +# define PJMEDIA_G722_DEFAULT_PCM_SHIFT 2 +#endif + + +/** + * Specifies whether G.722 PCM shifting should be stopped when clipping + * detected in the decoder. Enabling this feature can be useful when + * talking to G.722 implementation that uses 16 bit PCM for G.722 input/ + * output (for any reason it seems to work) and the PCM shifting causes + * audio clipping. + * + * See also #PJMEDIA_G722_DEFAULT_PCM_SHIFT. + * + * Default: enabled. + */ +#ifndef PJMEDIA_G722_STOP_PCM_SHIFT_ON_CLIPPING +# define PJMEDIA_G722_STOP_PCM_SHIFT_ON_CLIPPING 1 +#endif + + /** * Enable the features provided by Intel IPP libraries, for example * codecs such as G.729, G.723.1, G.726, G.728, G.722.1, and AMR. diff --git a/pjmedia/include/pjmedia-codec/g722.h b/pjmedia/include/pjmedia-codec/g722.h index 71a5bb5b..594d5a5e 100644 --- a/pjmedia/include/pjmedia-codec/g722.h +++ b/pjmedia/include/pjmedia-codec/g722.h @@ -78,6 +78,21 @@ PJ_DECL(pj_status_t) pjmedia_codec_g722_init(pjmedia_endpt *endpt); PJ_DECL(pj_status_t) pjmedia_codec_g722_deinit(void); +/** + * Set the G.722 codec encoder and decoder level adjustment. + * If the value is non-zero, then PCM input samples to the encoder will + * be shifted right by this value, and similarly PCM output samples from + * the decoder will be shifted left by this value. + * + * Default value is PJMEDIA_G722_DEFAULT_PCM_SHIFT. + * + * @param val The value + * + * @return PJ_SUCCESS on success. + */ +PJ_DECL(pj_status_t) pjmedia_codec_g722_set_pcm_shift(unsigned val); + + PJ_END_DECL diff --git a/pjmedia/src/pjmedia-codec/g722.c b/pjmedia/src/pjmedia-codec/g722.c index 04135f6c..842612c9 100644 --- a/pjmedia/src/pjmedia-codec/g722.c +++ b/pjmedia/src/pjmedia-codec/g722.c @@ -133,6 +133,7 @@ static struct g722_codec_factory pj_pool_t *pool; pj_mutex_t *mutex; pjmedia_codec codec_list; + unsigned pcm_shift; } g722_codec_factory; @@ -141,6 +142,8 @@ struct g722_data { g722_enc_t encoder; g722_dec_t decoder; + unsigned pcm_shift; + pj_int16_t pcm_clip_mask; pj_bool_t plc_enabled; pj_bool_t vad_enabled; pjmedia_silence_det *vad; @@ -167,6 +170,7 @@ PJ_DEF(pj_status_t) pjmedia_codec_g722_init( pjmedia_endpt *endpt ) g722_codec_factory.base.op = &g722_factory_op; g722_codec_factory.base.factory_data = NULL; g722_codec_factory.endpt = endpt; + g722_codec_factory.pcm_shift = PJMEDIA_G722_DEFAULT_PCM_SHIFT; g722_codec_factory.pool = pjmedia_endpt_create_pool(endpt, "g722", 1000, 1000); @@ -240,6 +244,17 @@ PJ_DEF(pj_status_t) pjmedia_codec_g722_deinit(void) return status; } + +/* + * Set level adjustment. + */ +PJ_DEF(pj_status_t) pjmedia_codec_g722_set_pcm_shift(unsigned val) +{ + g722_codec_factory.pcm_shift = val; + return PJ_SUCCESS; +} + + /* * Check if factory can allocate the specified codec. */ @@ -446,6 +461,9 @@ static pj_status_t g722_codec_open(pjmedia_codec *codec, g722_data->vad_enabled = (attr->setting.vad != 0); g722_data->plc_enabled = (attr->setting.plc != 0); + g722_data->pcm_shift = g722_codec_factory.pcm_shift; + g722_data->pcm_clip_mask = (pj_int16_t)(1<pcm_clip_mask <<= (16-g722_codec_factory.pcm_shift); TRACE_((THIS_FILE, "G722 codec opened: vad=%d, plc=%d", g722_data->vad_enabled, g722_data->plc_enabled)); @@ -565,6 +583,17 @@ static pj_status_t g722_codec_encode(pjmedia_codec *codec, } } + /* Adjust input signal level from 16-bit to 14-bit */ + if (g722_data->pcm_shift) { + pj_int16_t *p, *end; + + p = (pj_int16_t*)input->buf; + end = p + input->size; + while (p < end) { + *p++ >>= g722_data->pcm_shift; + } + } + /* Encode to temporary buffer */ output->size = output_buf_len; status = g722_enc_encode(&g722_data->encoder, (pj_int16_t*)input->buf, @@ -623,6 +652,25 @@ static pj_status_t g722_codec_decode(pjmedia_codec *codec, } pj_assert(output->size == SAMPLES_PER_FRAME); + + /* Adjust input signal level from 14-bit to 16-bit */ + if (g722_data->pcm_shift) { + pj_int16_t *p, *end; + + p = (pj_int16_t*)output->buf; + end = p + output->size; + while (p < end) { +#if PJMEDIA_G722_STOP_PCM_SHIFT_ON_CLIPPING + /* If there is clipping, stop the PCM shifting */ + if (*p & g722_data->pcm_clip_mask) { + g722_data->pcm_shift = 0; + break; + } +#endif + *p++ <<= g722_data->pcm_shift; + } + } + output->size = SAMPLES_PER_FRAME * 2; output->type = PJMEDIA_FRAME_TYPE_AUDIO; output->timestamp = input->timestamp; diff --git a/pjmedia/src/pjmedia-codec/g722/g722_dec.c b/pjmedia/src/pjmedia-codec/g722/g722_dec.c index 887fcb93..1579d06e 100644 --- a/pjmedia/src/pjmedia-codec/g722/g722_dec.c +++ b/pjmedia/src/pjmedia-codec/g722/g722_dec.c @@ -504,7 +504,6 @@ PJ_DEF(pj_status_t) g722_dec_decode( g722_dec_t *dec, unsigned i; int ilowr, ylow, rlow, dlowt; int ihigh, rhigh, dhigh; - int pcm1, pcm2; pj_uint8_t *in_ = (pj_uint8_t*) in; PJ_ASSERT_RETURN(dec && in && in_size && out && nsamples, PJ_EINVAL); @@ -529,9 +528,7 @@ PJ_DEF(pj_status_t) g722_dec_decode( g722_dec_t *dec, dec->shigh = block4h (dec, dhigh) ; /* rhigh <= output high band pcm */ - rx_qmf(dec, rlow, rhigh, &pcm1, &pcm2); - out[i*2] = (pj_int16_t)(pcm1 << 2); - out[i*2+1] = (pj_int16_t)(pcm2 << 2); + rx_qmf(dec, rlow, rhigh, &out[i*2], &out[i*2+1]); } *nsamples = in_size << 1; diff --git a/pjmedia/src/pjmedia-codec/g722/g722_enc.c b/pjmedia/src/pjmedia-codec/g722/g722_enc.c index b4ca63ce..d4b5ab87 100644 --- a/pjmedia/src/pjmedia-codec/g722/g722_enc.c +++ b/pjmedia/src/pjmedia-codec/g722/g722_enc.c @@ -543,7 +543,7 @@ PJ_DEF(pj_status_t) g722_enc_encode( g722_enc_t *enc, PJ_ASSERT_RETURN(*out_size >= (nsamples >> 1), PJ_ETOOSMALL); for(i = 0; i < nsamples; i += 2) { - tx_qmf(enc, in[i]>>2, in[i+1]>>2, &xlow, &xhigh); + tx_qmf(enc, in[i], in[i+1], &xlow, &xhigh); /* low band encoder */ ilow = block1l (xlow, enc->slow, enc->detlow) ; -- cgit v1.2.3