More ticket #774: added option to shift PCM input to encoder right by some value (default is 1) to make it compatible with some other app

git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@2620 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/pjmedia/include/pjmedia-codec/config.h b/pjmedia/include/pjmedia-codec/config.h
index 046c861..314506e 100644
--- a/pjmedia/include/pjmedia-codec/config.h
+++ b/pjmedia/include/pjmedia-codec/config.h
@@ -237,8 +237,22 @@
  * G.722.1 codec is disabled by default, it's currently under development.
  */
 #ifndef PJMEDIA_HAS_G7221_CODEC
-#   define PJMEDIA_HAS_G7221_CODEC    0
+#   define PJMEDIA_HAS_G7221_CODEC		0
 #endif
 
+/**
+ * Default G.722.1 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.
+ *
+ * This can be changed at run-time after initialization by calling
+ * #pjmedia_codec_g7221_set_pcm_shift().
+ */
+#ifndef PJMEDIA_G7221_DEFAULT_PCM_SHIFT
+#   define PJMEDIA_G7221_DEFAULT_PCM_SHIFT	1
+#endif
+
+
 
 #endif	/* __PJMEDIA_CODEC_CONFIG_H__ */
diff --git a/pjmedia/include/pjmedia-codec/g7221.h b/pjmedia/include/pjmedia-codec/g7221.h
index 11ec11f..8c7cbd2 100644
--- a/pjmedia/include/pjmedia-codec/g7221.h
+++ b/pjmedia/include/pjmedia-codec/g7221.h
@@ -93,6 +93,21 @@
 						  unsigned bitrate, 
 						  pj_bool_t enabled);
 
+/**
+ * Set the G.722.1 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_G7221_DEFAULT_PCM_SHIFT.
+ *
+ * @param val		The value
+ *
+ * @return		PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_codec_g7221_set_pcm_shift(int val);
+
+
 
 /**
  * Unregister G722.1 codecs factory from pjmedia endpoint.
diff --git a/pjmedia/src/pjmedia-codec/g7221.c b/pjmedia/src/pjmedia-codec/g7221.c
index e4eb1ae..fcaebde 100644
--- a/pjmedia/src/pjmedia-codec/g7221.c
+++ b/pjmedia/src/pjmedia-codec/g7221.c
@@ -137,6 +137,7 @@
     pj_pool_t		    *pool;	    /**< Codec factory pool.	    */
     pj_mutex_t		    *mutex;	    /**< Codec factory mutex.	    */
 
+    int			     pcm_shift;	    /**< Level adjustment	    */
     unsigned		     mode_count;    /**< Number of G722.1 modes.    */
     codec_mode		     modes[MAX_CODEC_MODES]; /**< The G722.1 modes. */
     unsigned		     mode_rsv_start;/**< Start index of G722.1 non-
@@ -164,8 +165,10 @@
     pj_uint16_t		 frame_size;	    /**< Coded frame size.	    */
     pj_uint16_t		 frame_size_bits;   /**< Coded frame size in bits.  */
     pj_uint16_t		 number_of_regions; /**< Number of regions.	    */
+    int			 pcm_shift;	    /**< Adjustment for PCM in/out  */
     
     /* Encoder specific state */
+    Word16		*enc_frame;	    /**< 16bit to 14bit buffer	    */
     Word16		*enc_old_frame;
     
     /* Decoder specific state */
@@ -251,6 +254,7 @@
 
     /* Initialize codec modes, by default all standard bitrates are enabled */
     codec_factory.mode_count = 0;
+    codec_factory.pcm_shift = PJMEDIA_G7221_DEFAULT_PCM_SHIFT;
 
     mode = &codec_factory.modes[codec_factory.mode_count++];
     mode->enabled = PJ_TRUE;
@@ -408,6 +412,15 @@
 
 
 /*
+ * Set level adjustment.
+ */
+PJ_DEF(pj_status_t)  pjmedia_codec_g7221_set_pcm_shift(int val)
+{
+    codec_factory.pcm_shift = val;
+    return PJ_SUCCESS;
+}
+
+/*
  * Unregister G722.1 codec factory from pjmedia endpoint.
  */
 PJ_DEF(pj_status_t) pjmedia_codec_g7221_deinit(void)
@@ -644,10 +657,12 @@
     codec_data->number_of_regions = (pj_uint16_t)
 				    (attr->info.clock_rate <= WB_SAMPLE_RATE?
 				     NUMBER_OF_REGIONS:MAX_NUMBER_OF_REGIONS);
+    codec_data->pcm_shift = codec_factory.pcm_shift;
 
     /* Initialize encoder state */
     tmp = codec_data->samples_per_frame << 1;
     codec_data->enc_old_frame = (Word16*)pj_pool_zalloc(pool, tmp);
+    codec_data->enc_frame = (Word16*)pj_pool_alloc(pool, tmp);
 
     /* Initialize decoder state */
     tmp = codec_data->samples_per_frame;
@@ -733,6 +748,7 @@
 				 struct pjmedia_frame *output)
 {
     codec_private_t *codec_data = (codec_private_t*) codec->codec_data;
+    const Word16 *pcm_input;
     Word16 mlt_coefs[MAX_SAMPLES_PER_FRAME];
     Word16 mag_shift;
 
@@ -772,8 +788,21 @@
 	}
     }
 
+    /* Encoder adjust the input signal level */
+    if (codec_data->pcm_shift) {
+	unsigned i;
+	pcm_input = (const Word16*)input->buf;
+	for (i=0; i<codec_data->samples_per_frame; ++i) {
+	    codec_data->enc_frame[i] = 
+		(pj_int16_t)(pcm_input[i] >> codec_data->pcm_shift);
+	}
+	pcm_input = codec_data->enc_frame;
+    } else {
+	pcm_input = (const Word16*)input->buf;
+    }
+
     /* Convert input samples to rmlt coefs */
-    mag_shift = samples_to_rmlt_coefs((Word16*)input->buf,
+    mag_shift = samples_to_rmlt_coefs(pcm_input,
 				      codec_data->enc_old_frame, 
 				      mlt_coefs, 
 				      codec_data->samples_per_frame);
@@ -855,6 +884,16 @@
 			  codec_data->samples_per_frame, 
 			  mag_shift);
 
+    /* Decoder adjust PCM signal */
+    if (codec_data->pcm_shift) {
+	unsigned i;
+	pj_int16_t *buf = (Word16*)output->buf;
+
+	for (i=0; i<codec_data->samples_per_frame; ++i) {
+	    buf[i] <<= codec_data->pcm_shift;
+	}
+    }
+
     output->type = PJMEDIA_FRAME_TYPE_AUDIO;
     output->size = codec_data->samples_per_frame << 1;
 
diff --git a/pjmedia/src/test/codec_vectors.c b/pjmedia/src/test/codec_vectors.c
index 7bf3b38..0c4b81c 100644
--- a/pjmedia/src/test/codec_vectors.c
+++ b/pjmedia/src/test/codec_vectors.c
@@ -572,6 +572,9 @@
 	pjmedia_endpt_destroy(endpt);
 	return -7;
     }
+
+    /* Set shift value to zero for the test vectors */
+    pjmedia_codec_g7221_set_pcm_shift(0);
 #endif
 
     PJ_LOG(3,(THIS_FILE,"  encode tests:"));
diff --git a/third_party/g7221/common/defs.h b/third_party/g7221/common/defs.h
index 2c4978e..40db16f 100644
--- a/third_party/g7221/common/defs.h
+++ b/third_party/g7221/common/defs.h
@@ -140,7 +140,7 @@
 	         Word16 *old_decoder_mlt_coefs,
 	         Word16 frame_error_flag);
 
-Word16  samples_to_rmlt_coefs(Word16 *new_samples,Word16 *history,Word16 *coefs,Word16 dct_length);
+Word16  samples_to_rmlt_coefs(const Word16 *new_samples,Word16 *history,Word16 *coefs,Word16 dct_length);
 void rmlt_coefs_to_samples(Word16 *coefs,     
                            Word16 *old_samples,           
                            Word16 *out_samples,           
diff --git a/third_party/g7221/encode/sam2coef.c b/third_party/g7221/encode/sam2coef.c
index fc369e0..3dd5b76 100644
--- a/third_party/g7221/encode/sam2coef.c
+++ b/third_party/g7221/encode/sam2coef.c
@@ -65,12 +65,13 @@
 				
 ***************************************************************************/
 
-Word16 samples_to_rmlt_coefs(Word16 *new_samples,Word16 *old_samples,Word16 *coefs,Word16 dct_length)
+Word16 samples_to_rmlt_coefs(const Word16 *new_samples,Word16 *old_samples,Word16 *coefs,Word16 dct_length)
 {
 
     Word16	index, vals_left,mag_shift,n;
     Word16	windowed_data[MAX_DCT_LENGTH];
-    Word16	*new_ptr, *old_ptr, *sam_low, *sam_high;
+    Word16	*old_ptr;
+    const Word16 *new_ptr, *sam_low, *sam_high;
     Word16	*win_low, *win_high;
     Word16	*dst_ptr;
     Word16  neg_win_low;