Index: pjproject/trunk/pjmedia/src/pjmedia-codec/l16.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia-codec/l16.c	(revision 2246)
+++ pjproject/trunk/pjmedia/src/pjmedia-codec/l16.c	(revision 2247)
@@ -21,4 +21,6 @@
 #include <pjmedia/errno.h>
 #include <pjmedia/endpoint.h>
+#include <pjmedia/plc.h>
+#include <pjmedia/silencedet.h>
 #include <pj/assert.h>
 #include <pj/pool.h>
@@ -31,4 +33,6 @@
  */
 #if defined(PJMEDIA_HAS_L16_CODEC) && PJMEDIA_HAS_L16_CODEC != 0
+
+#define PLC_DISABLED	0
 
 
@@ -78,4 +82,9 @@
 				 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. */
@@ -88,5 +97,6 @@
     &l16_parse,
     &l16_encode,
-    &l16_decode
+    &l16_decode,
+    &l16_recover
 };
 
@@ -108,5 +118,4 @@
     pj_pool_t		       *pool;
     pj_mutex_t		       *mutex;
-    pjmedia_codec		codec_list;
 } l16_factory;
 
@@ -115,5 +124,15 @@
 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,6 +158,4 @@
     l16_factory.base.factory_data = NULL;
     l16_factory.endpt = endpt;
-
-    pj_list_init(&l16_factory.codec_list);
 
     /* Create pool */
@@ -253,5 +270,8 @@
     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;
@@ -421,4 +441,7 @@
     struct l16_data *data;
     unsigned ptime;
+    pj_pool_t *pool;
+
+    pj_status_t status;
 
     PJ_ASSERT_RETURN(factory==&l16_factory.base, PJ_EINVAL);
@@ -427,17 +450,10 @@
     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 */
@@ -445,7 +461,26 @@
     data = (struct l16_data*) codec->codec_data;
     data->frame_size = ptime * id->clock_rate * id->channel_cnt * 2 / 1000;
-
-    /* Zero the list, for error detection in l16_dealloc_codec */
-    codec->next = codec->prev = NULL;
+    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
+
+    /* 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;
@@ -460,18 +495,16 @@
 				     pjmedia_codec *codec )
 {
-    
+    struct l16_data *data;
+
+    PJ_ASSERT_RETURN(factory && codec, PJ_EINVAL);
     PJ_ASSERT_RETURN(factory==&l16_factory.base, PJ_EINVAL);
-
-    /* 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;
-    }
 
     /* 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. */
@@ -509,8 +542,12 @@
 			       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;
 }
 
@@ -549,11 +586,10 @@
 			      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 */
@@ -561,4 +597,30 @@
 	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 */
@@ -583,10 +645,11 @@
 			      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);
 
 
@@ -608,7 +671,33 @@
     output->size = input->size;
 
-    return PJ_SUCCESS;
-}
-
+#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 */
