Index: pjproject/trunk/pjmedia/include/pjmedia-codec/config.h
===================================================================
--- pjproject/trunk/pjmedia/include/pjmedia-codec/config.h	(revision 3201)
+++ pjproject/trunk/pjmedia/include/pjmedia-codec/config.h	(revision 3202)
@@ -95,4 +95,38 @@
 #ifndef PJMEDIA_HAS_G722_CODEC
 #   define PJMEDIA_HAS_G722_CODEC    1
+#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
 
Index: pjproject/trunk/pjmedia/include/pjmedia-codec/g722.h
===================================================================
--- pjproject/trunk/pjmedia/include/pjmedia-codec/g722.h	(revision 3201)
+++ pjproject/trunk/pjmedia/include/pjmedia-codec/g722.h	(revision 3202)
@@ -79,4 +79,19 @@
 
 
+/**
+ * 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
 
Index: pjproject/trunk/pjmedia/src/pjmedia-codec/g722.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia-codec/g722.c	(revision 3201)
+++ pjproject/trunk/pjmedia/src/pjmedia-codec/g722.c	(revision 3202)
@@ -134,4 +134,5 @@
     pj_mutex_t		    *mutex;
     pjmedia_codec	     codec_list;
+    unsigned		     pcm_shift;
 } g722_codec_factory;
 
@@ -142,4 +143,6 @@
     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;
@@ -168,4 +171,5 @@
     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, 
@@ -240,4 +244,15 @@
     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;
+}
+
 
 /* 
@@ -447,4 +462,7 @@
     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<<g722_codec_factory.pcm_shift)-1;
+    g722_data->pcm_clip_mask <<= (16-g722_codec_factory.pcm_shift);
 
     TRACE_((THIS_FILE, "G722 codec opened: vad=%d, plc=%d",
@@ -566,4 +584,15 @@
     }
 
+    /* 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;
@@ -624,4 +653,23 @@
 
     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;
Index: pjproject/trunk/pjmedia/src/pjmedia-codec/g722/g722_dec.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia-codec/g722/g722_dec.c	(revision 3201)
+++ pjproject/trunk/pjmedia/src/pjmedia-codec/g722/g722_dec.c	(revision 3202)
@@ -505,5 +505,4 @@
     int ilowr, ylow, rlow, dlowt;
     int ihigh, rhigh, dhigh;
-    int pcm1, pcm2;
     pj_uint8_t *in_ = (pj_uint8_t*) in;
 
@@ -530,7 +529,5 @@
 	/* 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]);
     }
 
Index: pjproject/trunk/pjmedia/src/pjmedia-codec/g722/g722_enc.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia-codec/g722/g722_enc.c	(revision 3201)
+++ pjproject/trunk/pjmedia/src/pjmedia-codec/g722/g722_enc.c	(revision 3202)
@@ -544,5 +544,5 @@
     
     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 */
