- Added iLBC codec (experimental) with the following features:
   - configurable default decoder mode (20 or 30),
   - encoder mode follows the mode specified in SDP fmtp from
     the remote's SDP,
   - silence detector uses pjmedia's,
   - PLC uses iLBC's PLC,
   - perceptual enhancement (penh) is configurable via codec
     param, as usual.

- iLBC mode is configurable in pjsua with --ilbc-mode option.

- Added packet lost simulation in pjmedia's UDP transport and
  in pjsua (with --rx-drop-pct and --tx-drop-pct options).

- Increase default buffer count in DirectSound to 32 frames
  to make it more resilient to CPU disruption.

- Specify and parse fmtp mode in SDP for codecs that need it.




git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@637 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/pjmedia/build/Makefile b/pjmedia/build/Makefile
index 7e18350..c0465f1 100644
--- a/pjmedia/build/Makefile
+++ b/pjmedia/build/Makefile
@@ -11,7 +11,7 @@
 # E.g., to exclude Speex, we need to exclude SPEEX_OBJS from CODEC_OBJS, AND specify
 #       "#define PJMEDIA_HAS_SPEEX_CODEC 0" in pj/config_site.h.
 #
-export CODEC_OBJS = $(GSM_OBJS) $(SPEEX_OBJS)
+export CODEC_OBJS = $(GSM_OBJS) $(SPEEX_OBJS) $(ILBC_OBJS)
 
 
 include ../../build/common.mak
@@ -106,11 +106,23 @@
 		speex/stereo.o speex/vbr.o speex/vq.o speex/window.o
 SPEEX_CFLAGS := -DHAVE_CONFIG_H=1 -I../src/pjmedia-codec
 
+ILBC_OBJS := 	ilbc.o \
+		ilbc/FrameClassify.o ilbc/LPCdecode.o ilbc/LPCencode.o \
+		ilbc/StateConstructW.o ilbc/StateSearchW.o ilbc/anaFilter.o \
+		ilbc/constants.o ilbc/createCB.o ilbc/doCPLC.o \
+		ilbc/enhancer.o ilbc/filter.o ilbc/gainquant.o \
+		ilbc/getCBvec.o ilbc/helpfun.o ilbc/hpInput.o \
+		ilbc/hpOutput.o ilbc/iCBConstruct.o ilbc/iCBSearch.o \
+		ilbc/iLBC_decode.o ilbc/iLBC_encode.o ilbc/lsf.o \
+		ilbc/packing.o ilbc/syntFilter.o
+ILBC_CFLAGS :=
+
 export PJMEDIA_CODEC_SRCDIR = ../src/pjmedia-codec
 export PJMEDIA_CODEC_OBJS += l16.o \
 			$(OS_OBJS) $(M_OBJS) $(CC_OBJS) $(HOST_OBJS) \
 			$(CODEC_OBJS)
-export PJMEDIA_CODEC_CFLAGS += $(_CFLAGS) $(GSM_CFLAGS) $(SPEEX_CFLAGS)
+export PJMEDIA_CODEC_CFLAGS += $(_CFLAGS) $(GSM_CFLAGS) $(SPEEX_CFLAGS) \
+			$(ILBC_CFLAGS)
 
 
 ###############################################################################
diff --git a/pjmedia/build/pjmedia_codec.dsp b/pjmedia/build/pjmedia_codec.dsp
index a1bd308..42490a1 100644
--- a/pjmedia/build/pjmedia_codec.dsp
+++ b/pjmedia/build/pjmedia_codec.dsp
@@ -100,6 +100,10 @@
 # End Source File
 # Begin Source File
 
+SOURCE="..\src\pjmedia-codec\ilbc.c"
+# End Source File
+# Begin Source File
+
 SOURCE="..\src\pjmedia-codec\l16.c"
 
 !IF  "$(CFG)" == "pjmedia_codec - Win32 Release"
@@ -138,6 +142,10 @@
 # End Source File
 # Begin Source File
 
+SOURCE="..\include\pjmedia-codec\ilbc.h"
+# End Source File
+# Begin Source File
+
 SOURCE="..\include\pjmedia-codec\l16.h"
 # End Source File
 # Begin Source File
@@ -663,5 +671,202 @@
 # End Source File
 # End Group
 # End Group
+# Begin Group "iLBC Codec"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\anaFilter.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\anaFilter.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\constants.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\constants.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\createCB.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\createCB.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\doCPLC.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\doCPLC.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\enhancer.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\enhancer.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\filter.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\filter.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\FrameClassify.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\FrameClassify.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\gainquant.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\gainquant.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\getCBvec.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\getCBvec.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\helpfun.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\helpfun.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\hpInput.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\hpInput.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\hpOutput.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\hpOutput.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\iCBConstruct.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\iCBConstruct.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\iCBSearch.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\iCBSearch.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\iLBC_decode.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\iLBC_decode.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\iLBC_define.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\iLBC_encode.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\iLBC_encode.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\iLBC_test.c"
+# PROP Exclude_From_Build 1
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\LPCdecode.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\LPCdecode.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\LPCencode.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\LPCencode.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\lsf.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\lsf.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\packing.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\packing.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\StateConstructW.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\StateConstructW.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\StateSearchW.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\StateSearchW.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\syntFilter.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\ilbc\syntFilter.h"
+# End Source File
+# End Group
 # End Target
 # End Project
diff --git a/pjmedia/include/pjmedia-codec.h b/pjmedia/include/pjmedia-codec.h
index 3658cb1..f220fd1 100644
--- a/pjmedia/include/pjmedia-codec.h
+++ b/pjmedia/include/pjmedia-codec.h
@@ -27,6 +27,7 @@
 #include <pjmedia-codec/l16.h>
 #include <pjmedia-codec/gsm.h>
 #include <pjmedia-codec/speex.h>
+#include <pjmedia-codec/ilbc.h>
 
 
 #endif	/* __PJMEDIA_CODEC_PJMEDIA_CODEC_H__ */
diff --git a/pjmedia/include/pjmedia-codec/config.h b/pjmedia/include/pjmedia-codec/config.h
index 2006528..85bd778 100644
--- a/pjmedia/include/pjmedia-codec/config.h
+++ b/pjmedia/include/pjmedia-codec/config.h
@@ -46,5 +46,13 @@
 #endif
 
 
+/**
+ * Unless specified otherwise, iLBC codec is included by default.
+ */
+#ifndef PJMEDIA_HAS_ILBC_CODEC
+#   define PJMEDIA_HAS_ILBC_CODEC    1
+#endif
+
+
 
 #endif	/* __PJMEDIA_CODEC_CONFIG_H__ */
diff --git a/pjmedia/include/pjmedia-codec/types.h b/pjmedia/include/pjmedia-codec/types.h
index a738fb6..18c7bfa 100644
--- a/pjmedia/include/pjmedia-codec/types.h
+++ b/pjmedia/include/pjmedia-codec/types.h
@@ -48,7 +48,8 @@
     PJMEDIA_RTP_PT_L16_32KHZ_MONO,		/**< L16 @ 32KHz, mono	    */
     PJMEDIA_RTP_PT_L16_32KHZ_STEREO,		/**< L16 @ 32KHz, stereo    */
     PJMEDIA_RTP_PT_L16_48KHZ_MONO,		/**< L16 @ 48KHz, mono	    */
-    PJMEDIA_RTP_PT_L16_48KHZ_STEREO		/**< L16 @ 48KHz, stereo    */
+    PJMEDIA_RTP_PT_L16_48KHZ_STEREO,		/**< L16 @ 48KHz, stereo    */
+    PJMEDIA_RTP_PT_ILBC				/**< iLBC (13.3/15.2Kbps)   */
 };
 
 
diff --git a/pjmedia/include/pjmedia/codec.h b/pjmedia/include/pjmedia/codec.h
index 844f886..dd611f2 100644
--- a/pjmedia/include/pjmedia/codec.h
+++ b/pjmedia/include/pjmedia/codec.h
@@ -271,11 +271,11 @@
 	pj_uint8_t  frm_per_pkt;    /**< Number of frames per packet.	*/
 	unsigned    vad:1;	    /**< Voice Activity Detector.	*/
 	unsigned    cng:1;	    /**< Comfort Noise Generator.	*/
-	unsigned    lpf:1;	    /**< Low pass filter		*/
-	unsigned    hpf:1;	    /**< High pass filter		*/
 	unsigned    penh:1;	    /**< Perceptual Enhancement		*/
 	unsigned    plc:1;	    /**< Packet loss concealment	*/
 	unsigned    reserved:1;	    /**< Reserved, must be zero.	*/
+	pj_uint8_t  enc_fmtp_mode;  /**< Mode param in fmtp (def:0)	*/
+	pj_uint8_t  dec_fmtp_mode;  /**< Mode param in fmtp (def:0)	*/
     } setting;
 } pjmedia_codec_param;
 
diff --git a/pjmedia/include/pjmedia/errno.h b/pjmedia/include/pjmedia/errno.h
index c9c6bae..03608f9 100644
--- a/pjmedia/include/pjmedia/errno.h
+++ b/pjmedia/include/pjmedia/errno.h
@@ -298,6 +298,16 @@
  * Invalid codec frame length.
  */
 #define PJMEDIA_CODEC_EFRMINLEN	    (PJMEDIA_ERRNO_START+84)    /* 220084 */
+/**
+ * @hideinitializer
+ * Invalid PCM frame length.
+ */
+#define PJMEDIA_CODEC_EPCMFRMINLEN  (PJMEDIA_ERRNO_START+85)    /* 220085 */
+/**
+ * @hideinitializer
+ * Invalid mode.
+ */
+#define PJMEDIA_CODEC_EINMODE	    (PJMEDIA_ERRNO_START+86)    /* 220086 */
 
 
 /************************************************************
diff --git a/pjmedia/include/pjmedia/transport_udp.h b/pjmedia/include/pjmedia/transport_udp.h
index 860ea7e..5a348d3 100644
--- a/pjmedia/include/pjmedia/transport_udp.h
+++ b/pjmedia/include/pjmedia/transport_udp.h
@@ -144,8 +144,30 @@
 
 
 /**
+ * Simulate packet lost in the specified direction (for testing purposes).
+ * When enabled, the transport will randomly drop packets to the specified
+ * direction.
+ *
+ * @param tp	    The UDP media transport.
+ * @param dir	    Media direction to which packets will be randomly dropped.
+ * @param pct_lost  Percent lost (0-100). Set to zero to disable packet
+ *		    lost simulation.
+ *
+ * @return	    PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_transport_udp_simulate_lost(pjmedia_transport *tp,
+							 pjmedia_dir dir,
+							 unsigned pct_lost);
+
+
+
+/**
  * Close UDP transport. Application can also use the "destroy" member of
  * media transport interface to close the UDP transport.
+ *
+ * @param tp	    The UDP media transport.
+ *
+ * @return	    PJ_SUCCESS on success.
  */
 PJ_DECL(pj_status_t) pjmedia_transport_udp_close(pjmedia_transport *tp);
 
diff --git a/pjmedia/src/pjmedia-codec/speex_codec.c b/pjmedia/src/pjmedia-codec/speex_codec.c
index b434ee8..e4dda97 100644
--- a/pjmedia/src/pjmedia-codec/speex_codec.c
+++ b/pjmedia/src/pjmedia-codec/speex_codec.c
@@ -408,8 +408,6 @@
     /* Default flags. */
     attr->setting.cng = 1;
     attr->setting.plc = 1;
-    attr->setting.hpf = 1;
-    attr->setting.lpf =1 ;
     attr->setting.penh =1 ;
     attr->setting.vad = 1;
 
diff --git a/pjmedia/src/pjmedia/dsound.c b/pjmedia/src/pjmedia/dsound.c
index e452fa5..bf29299 100644
--- a/pjmedia/src/pjmedia/dsound.c
+++ b/pjmedia/src/pjmedia/dsound.c
@@ -44,7 +44,7 @@
 #define BYTES_PER_SAMPLE    (BITS_PER_SAMPLE/8)
 
 #define MAX_PACKET_BUFFER_COUNT	    32
-#define DEFAULT_BUFFER_COUNT	    16
+#define DEFAULT_BUFFER_COUNT	    32
 
 #define MAX_HARDWARE		    16
 
diff --git a/pjmedia/src/pjmedia/endpoint.c b/pjmedia/src/pjmedia/endpoint.c
index 5e098c4..eb9d894 100644
--- a/pjmedia/src/pjmedia/endpoint.c
+++ b/pjmedia/src/pjmedia/endpoint.c
@@ -346,19 +346,22 @@
     }
 #endif
 
-    /* Add format and rtpmap for each codec */
+    /* Add format, rtpmap, and fmtp (when applicable) for each codec */
     for (i=0; i<endpt->codec_mgr.codec_cnt; ++i) {
 
 	pjmedia_codec_info *codec_info;
 	pjmedia_sdp_rtpmap rtpmap;
 	char tmp_param[3];
 	pjmedia_sdp_attr *attr;
+	pjmedia_codec_param codec_param;
 	pj_str_t *fmt;
 
 	if (endpt->codec_mgr.codec_desc[i].prio == PJMEDIA_CODEC_PRIO_DISABLED)
 	    break;
 
 	codec_info = &endpt->codec_mgr.codec_desc[i].info;
+	pjmedia_codec_mgr_get_default_param(&endpt->codec_mgr, codec_info,
+					    &codec_param);
 	fmt = &m->desc.fmt[m->desc.fmt_count++];
 
 	fmt->ptr = pj_pool_alloc(pool, 8);
@@ -390,6 +393,20 @@
 	pjmedia_sdp_rtpmap_to_attr(pool, &rtpmap, &attr);
 	m->attr[m->attr_count++] = attr;
 
+	/* Add fmtp mode where applicable */
+	if (codec_param.setting.dec_fmtp_mode != 0) {
+	    const pj_str_t fmtp = { "fmtp", 4 };
+	    attr = pj_pool_zalloc(pool, sizeof(pjmedia_sdp_attr));
+
+	    attr->name = fmtp;
+	    attr->value.ptr = pj_pool_alloc(pool, 32);
+	    attr->value.slen = 
+		pj_ansi_snprintf( attr->value.ptr, 32,
+				  ":%d mode=%d",
+				  codec_info->pt,
+				  codec_param.setting.dec_fmtp_mode);
+	    m->attr[m->attr_count++] = attr;
+	}
     }
 
     /* Add sendrecv attribute. */
diff --git a/pjmedia/src/pjmedia/errno.c b/pjmedia/src/pjmedia/errno.c
index 3d62e06..9305cd6 100644
--- a/pjmedia/src/pjmedia/errno.c
+++ b/pjmedia/src/pjmedia/errno.c
@@ -89,6 +89,8 @@
     PJ_BUILD_ERR( PJMEDIA_CODEC_EFRMTOOSHORT,   "Codec frame is too short" ),
     PJ_BUILD_ERR( PJMEDIA_CODEC_EPCMTOOSHORT,   "PCM frame is too short" ),
     PJ_BUILD_ERR( PJMEDIA_CODEC_EFRMINLEN,      "Invalid codec frame length" ),
+    PJ_BUILD_ERR( PJMEDIA_CODEC_EPCMFRMINLEN,   "Invalid PCM frame length" ),
+    PJ_BUILD_ERR( PJMEDIA_CODEC_EINMODE,	"Invalid codec mode (no fmtp?)" ),
 
     /* Media errors. */
     PJ_BUILD_ERR( PJMEDIA_EINVALIDIP,	    "Invalid remote media (IP) address" ),
diff --git a/pjmedia/src/pjmedia/session.c b/pjmedia/src/pjmedia/session.c
index b629219..870576d 100644
--- a/pjmedia/src/pjmedia/session.c
+++ b/pjmedia/src/pjmedia/session.c
@@ -58,6 +58,55 @@
 
 
 /*
+ * Get fmtp mode parameter associated with the codec.
+ */
+static pj_status_t get_fmtp_mode(const pjmedia_sdp_media *m,
+				 const pj_str_t *fmt,
+				 int *p_mode)
+{
+    const pjmedia_sdp_attr *attr;
+    pjmedia_sdp_fmtp fmtp;
+    const pj_str_t str_mode = { "mode=", 5 };
+    char *pos;
+
+    /* Get "fmtp" attribute for the format */
+    attr = pjmedia_sdp_media_find_attr2(m, "fmtp", fmt);
+    if (attr == NULL)
+	return -1;
+
+    /* Parse "fmtp" attribute */
+    if (pjmedia_sdp_attr_get_fmtp(attr, &fmtp) != PJ_SUCCESS)
+	return -1;
+
+    /* Look for "mode=" string in the fmtp */
+    while (fmtp.fmt_param.slen >= str_mode.slen + 1) {
+	if (pj_strnicmp(&fmtp.fmt_param, &str_mode, str_mode.slen)==0) {
+	    /* Found "mode=" string */
+	    break;
+	}
+
+	fmtp.fmt_param.ptr++;
+	fmtp.fmt_param.slen--;
+    }
+
+    if (fmtp.fmt_param.slen < str_mode.slen + 1) {
+	/* "mode=" param not found */
+	return -1;
+    }
+
+    /* Get the mode */
+    pos = fmtp.fmt_param.ptr + str_mode.slen;
+    *p_mode = 0;
+    while (pj_isdigit(*pos)) {
+	*p_mode = *p_mode * 10 + (*pos - '0');
+	++pos;
+    }
+
+    return PJ_SUCCESS;
+}
+
+
+/*
  * Create stream info from SDP media line.
  */
 PJ_DEF(pj_status_t) pjmedia_stream_info_from_sdp(
@@ -75,6 +124,7 @@
     const pjmedia_sdp_conn *local_conn;
     const pjmedia_sdp_conn *rem_conn;
     pjmedia_sdp_rtpmap *rtpmap;
+    int local_fmtp_mode = 0, rem_fmtp_mode = 0;
     unsigned i, pt;
     pj_status_t status;
 
@@ -270,6 +320,7 @@
 	si->tx_pt = pt;
 
     } else {
+
 	attr = pjmedia_sdp_media_find_attr(local_m, &ID_RTPMAP, 
 					   &local_m->desc.fmt[0]);
 	if (attr == NULL)
@@ -304,6 +355,9 @@
 	    si->fmt.channel_cnt = 1;
 	}
 
+	/* Get fmtp mode= param in local SDP, if any */
+	get_fmtp_mode(local_m, &local_m->desc.fmt[0], &local_fmtp_mode);
+
 	/* Determine payload type for outgoing channel, by finding
 	 * dynamic payload type in remote SDP that matches the answer.
 	 */
@@ -330,6 +384,10 @@
 	    {
 		/* Found matched codec. */
 		si->tx_pt = rpt;
+
+		/* Get fmtp mode param in remote SDP, if any */
+		get_fmtp_mode(rem_m, &rtpmap->pt, &rem_fmtp_mode);
+
 		break;
 	    }
 	}
@@ -345,6 +403,13 @@
     if (status != PJ_SUCCESS)
 	return status;
 
+    /* Set fmtp mode for both local and remote */
+    if (local_fmtp_mode != 0)
+	si->param->setting.dec_fmtp_mode = (pj_int8_t)local_fmtp_mode;
+    if (rem_fmtp_mode != 0)
+	si->param->setting.enc_fmtp_mode = (pj_int8_t)rem_fmtp_mode;
+
+
     /* Get incomming payload type for telephone-events */
     si->rx_event_pt = -1;
     for (i=0; i<local_m->attr_count; ++i) {
diff --git a/pjmedia/src/pjmedia/transport_udp.c b/pjmedia/src/pjmedia/transport_udp.c
index edfabbb..4928c0c 100644
--- a/pjmedia/src/pjmedia/transport_udp.c
+++ b/pjmedia/src/pjmedia/transport_udp.c
@@ -21,6 +21,7 @@
 #include <pj/errno.h>
 #include <pj/ioqueue.h>
 #include <pj/log.h>
+#include <pj/rand.h>
 #include <pj/string.h>
 
 
@@ -58,6 +59,9 @@
 			const void*,
 			pj_ssize_t);
 
+    unsigned		tx_drop_pct;	/**< Percent of tx pkts to drop.    */
+    unsigned		rx_drop_pct;	/**< Percent of rx pkts to drop.    */
+
     pj_sock_t	        rtp_sock;	/**< RTP socket			    */
     pj_sockaddr_in	rtp_addr_name;	/**< Published RTP address.	    */
     pj_ioqueue_key_t   *rtp_key;	/**< RTP socket key in ioqueue	    */
@@ -371,6 +375,17 @@
 	cb = udp->rtp_cb;
 	user_data = udp->user_data;
 
+	/* Simulate packet lost on RX direction */
+	if (udp->rx_drop_pct) {
+	    if ((pj_rand() % 100) <= (int)udp->rx_drop_pct) {
+		PJ_LOG(5,(udp->base.name, 
+			  "RX RTP packet dropped because of pkt lost "
+			  "simulation"));
+		goto read_next_packet;
+	    }
+	}
+
+
 	if (udp->attached && cb)
 	    (*cb)(user_data, udp->rtp_pkt, bytes_read);
 
@@ -425,6 +440,7 @@
 	    }
 	}
 
+read_next_packet:
 	bytes_read = sizeof(udp->rtp_pkt);
 	udp->rtp_addrlen = sizeof(pj_sockaddr_in);
 	status = pj_ioqueue_recvfrom(udp->rtp_key, &udp->rtp_read_op,
@@ -581,6 +597,17 @@
     /* Check that the size is supported */
     PJ_ASSERT_RETURN(size <= RTP_LEN, PJ_ETOOBIG);
 
+    /* Simulate packet lost on TX direction */
+    if (udp->tx_drop_pct) {
+	if ((pj_rand() % 100) <= (int)udp->tx_drop_pct) {
+	    PJ_LOG(5,(udp->base.name, 
+		      "TX RTP packet dropped because of pkt lost "
+		      "simulation"));
+	    return PJ_SUCCESS;
+	}
+    }
+
+
     id = udp->rtp_write_op_id;
     pw = &udp->rtp_pending_write[id];
 
@@ -628,3 +655,24 @@
     return status;
 }
 
+
+PJ_DEF(pj_status_t) pjmedia_transport_udp_simulate_lost(pjmedia_transport *tp,
+							pjmedia_dir dir,
+							unsigned pct_lost)
+{
+    struct transport_udp *udp = (struct transport_udp*)tp;
+
+    PJ_ASSERT_RETURN(tp && 
+		     (dir==PJMEDIA_DIR_ENCODING||dir==PJMEDIA_DIR_DECODING) &&
+		     pct_lost <= 100, PJ_EINVAL);
+
+    if (dir == PJMEDIA_DIR_ENCODING)
+	udp->tx_drop_pct = pct_lost;
+    else if (dir == PJMEDIA_DIR_DECODING)
+	udp->rx_drop_pct = pct_lost;
+    else
+	return PJ_EINVAL;
+
+    return PJ_SUCCESS;
+}
+
diff --git a/pjsip-apps/src/pjsua/pjsua_app.c b/pjsip-apps/src/pjsua/pjsua_app.c
index d8d30dc..526a600 100644
--- a/pjsip-apps/src/pjsua/pjsua_app.c
+++ b/pjsip-apps/src/pjsua/pjsua_app.c
@@ -123,9 +123,13 @@
     puts  ("  --auto-play         Automatically play the file (to incoming calls only)");
     puts  ("  --auto-loop         Automatically loop incoming RTP to outgoing RTP");
     puts  ("  --rtp-port=N        Base port to try for RTP (default=4000)");
-    puts  ("  --quality=N	  Specify media quality (0-10, default=10)");
+    puts  ("  --quality=N         Specify media quality (0-10, default=6)");
     puts  ("  --ptime=MSEC        Override codec ptime to MSEC (default=specific)");
     puts  ("  --no-vad            Disable VAD/silence detector (default=vad enabled)");
+    puts  ("  --ilbc-mode=MODE    Set iLBC codec mode (20 or 30, default is 20)");
+    puts  ("  --rx-drop-pct=PCT   Drop PCT percent of RX RTP (for pkt lost sim, default: 0)");
+    puts  ("  --tx-drop-pct=PCT   Drop PCT percent of TX RTP (for pkt lost sim, default: 0)");
+
 
     puts  ("");
     puts  ("Buddy List (can be more than one):");
@@ -255,8 +259,9 @@
 	   OPT_ADD_BUDDY, OPT_OFFER_X_MS_MSG, OPT_NO_PRESENCE,
 	   OPT_AUTO_ANSWER, OPT_AUTO_HANGUP, OPT_AUTO_PLAY, OPT_AUTO_LOOP,
 	   OPT_AUTO_CONF, OPT_CLOCK_RATE,
-	   OPT_PLAY_FILE, OPT_RTP_PORT, OPT_ADD_CODEC,
+	   OPT_PLAY_FILE, OPT_RTP_PORT, OPT_ADD_CODEC, OPT_ILBC_MODE,
 	   OPT_COMPLEXITY, OPT_QUALITY, OPT_PTIME, OPT_NO_VAD,
+	   OPT_RX_DROP_PCT, OPT_TX_DROP_PCT,
 	   OPT_NEXT_ACCOUNT, OPT_NEXT_CRED, OPT_MAX_CALLS, 
 	   OPT_DURATION, OPT_NO_TCP, OPT_NO_UDP,
     };
@@ -298,6 +303,9 @@
 	{ "quality",	1, 0, OPT_QUALITY},
 	{ "ptime",      1, 0, OPT_PTIME},
 	{ "no-vad",     0, 0, OPT_NO_VAD},
+	{ "ilbc-mode",	1, 0, OPT_ILBC_MODE},
+	{ "rx-drop-pct",1, 0, OPT_RX_DROP_PCT},
+	{ "tx-drop-pct",1, 0, OPT_TX_DROP_PCT},
 	{ "next-account",0,0, OPT_NEXT_ACCOUNT},
 	{ "next-cred",	0, 0, OPT_NEXT_CRED},
 	{ "max-calls",	1, 0, OPT_MAX_CALLS},
@@ -624,6 +632,33 @@
 	    }
 	    break;
 
+	case OPT_ILBC_MODE:
+	    cfg->media_cfg.ilbc_mode = my_atoi(pj_optarg);
+	    if (cfg->media_cfg.ilbc_mode!=20 && cfg->media_cfg.ilbc_mode!=30) {
+		PJ_LOG(1,(THIS_FILE,
+			  "Error: invalid --ilbc-mode (expecting 20 or 30"));
+		return -1;
+	    }
+	    break;
+
+	case OPT_RX_DROP_PCT:
+	    cfg->media_cfg.rx_drop_pct = my_atoi(pj_optarg);
+	    if (cfg->media_cfg.rx_drop_pct > 100) {
+		PJ_LOG(1,(THIS_FILE,
+			  "Error: invalid --rx-drop-pct (expecting <= 100"));
+		return -1;
+	    }
+	    break;
+	    
+	case OPT_TX_DROP_PCT:
+	    cfg->media_cfg.tx_drop_pct = my_atoi(pj_optarg);
+	    if (cfg->media_cfg.tx_drop_pct > 100) {
+		PJ_LOG(1,(THIS_FILE,
+			  "Error: invalid --tx-drop-pct (expecting <= 100"));
+		return -1;
+	    }
+	    break;
+
 	case OPT_AUTO_ANSWER:
 	    cfg->auto_answer = my_atoi(pj_optarg);
 	    if (cfg->auto_answer < 100 || cfg->auto_answer > 699) {
diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h
index 6958bc4..fe1b1a7 100644
--- a/pjsip/include/pjsua-lib/pjsua.h
+++ b/pjsip/include/pjsua-lib/pjsua.h
@@ -2087,7 +2087,7 @@
      * The media quality also sets speex codec quality/complexity to the
      * number.
      *
-     * Default: 5.
+     * Default: 6.
      */
     unsigned		quality;
 
@@ -2104,6 +2104,30 @@
      * Default: 0 (no (meaning VAD is enabled))
      */
     pj_bool_t		no_vad;
+
+    /**
+     * iLBC mode (20 or 30).
+     *
+     * Default: 20
+     */
+    unsigned		ilbc_mode;
+
+    /**
+     * Percentage of RTP packet to drop in TX direction
+     * (to simulate packet lost).
+     *
+     * Default: 0
+     */
+    unsigned		tx_drop_pct;
+
+    /**
+     * Percentage of RTP packet to drop in RX direction
+     * (to simulate packet lost).
+     *
+     * Default: 0
+     */
+    unsigned		rx_drop_pct;
+
 };
 
 
@@ -2120,7 +2144,8 @@
     cfg->max_media_ports = 32;
     cfg->has_ioqueue = PJ_TRUE;
     cfg->thread_cnt = 1;
-    cfg->quality = 5;
+    cfg->quality = 6;
+    cfg->ilbc_mode = 20;
 }
 
 
diff --git a/pjsip/src/pjsua-lib/pjsua_call.c b/pjsip/src/pjsua-lib/pjsua_call.c
index d5b021f..31d7f6c 100644
--- a/pjsip/src/pjsua-lib/pjsua_call.c
+++ b/pjsip/src/pjsua-lib/pjsua_call.c
@@ -941,6 +941,7 @@
     }
 
     /* Create SDP */
+    PJ_UNUSED_ARG(unhold);
     PJ_TODO(create_active_inactive_sdp_based_on_unhold_arg);
     status = pjmedia_endpt_create_sdp( pjsua_var.med_endpt, call->inv->pool, 
 				       1, &call->skinfo, &sdp);
@@ -1853,8 +1854,8 @@
 
 	/* Override ptime, if this option is specified. */
 	if (pjsua_var.media_cfg.ptime != 0) {
-	    sess_info.stream_info[0].param->setting.frm_per_pkt = 
-		pjsua_var.media_cfg.ptime / sess_info.stream_info[0].param->info.frm_ptime;
+	    sess_info.stream_info[0].param->setting.frm_per_pkt = (pj_uint8_t)
+		(pjsua_var.media_cfg.ptime / sess_info.stream_info[0].param->info.frm_ptime);
 	    if (sess_info.stream_info[0].param->setting.frm_per_pkt == 0)
 		sess_info.stream_info[0].param->setting.frm_per_pkt = 1;
 	}
diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c
index 930543e..faafe2b 100644
--- a/pjsip/src/pjsua-lib/pjsua_core.c
+++ b/pjsip/src/pjsua-lib/pjsua_core.c
@@ -1114,7 +1114,7 @@
 
 
     /* To be done!! */
-
+    PJ_UNUSED_ARG(force);
 
     PJ_TODO(pjsua_transport_close);
 
diff --git a/pjsip/src/pjsua-lib/pjsua_media.c b/pjsip/src/pjsua-lib/pjsua_media.c
index c8c2049..d92d0cb 100644
--- a/pjsip/src/pjsua-lib/pjsua_media.c
+++ b/pjsip/src/pjsua-lib/pjsua_media.c
@@ -85,6 +85,17 @@
     }
 #endif /* PJMEDIA_HAS_SPEEX_CODEC */
 
+#if PJMEDIA_HAS_ILBC_CODEC
+    /* Register iLBC. */
+    status = pjmedia_codec_ilbc_init( pjsua_var.med_endpt, 
+				      pjsua_var.media_cfg.ilbc_mode);
+    if (status != PJ_SUCCESS) {
+	pjsua_perror(THIS_FILE, "Error initializing iLBC codec",
+		     status);
+	return status;
+    }
+#endif /* PJMEDIA_HAS_ILBC_CODEC */
+
 #if PJMEDIA_HAS_GSM_CODEC
     /* Register GSM */
     status = pjmedia_codec_gsm_init(pjsua_var.med_endpt);
@@ -484,6 +495,15 @@
 		         status);
 	    goto on_error;
 	}
+
+	pjmedia_transport_udp_simulate_lost(pjsua_var.calls[i].med_tp,
+					    PJMEDIA_DIR_ENCODING,
+					    pjsua_var.media_cfg.tx_drop_pct);
+
+	pjmedia_transport_udp_simulate_lost(pjsua_var.calls[i].med_tp,
+					    PJMEDIA_DIR_DECODING,
+					    pjsua_var.media_cfg.rx_drop_pct);
+
     }
 
     PJSUA_UNLOCK();
@@ -660,7 +680,7 @@
     status = pjmedia_wav_player_port_create(pjsua_var.pool, path,
 					    pjsua_var.mconf_cfg.samples_per_frame *
 					      1000 / pjsua_var.media_cfg.clock_rate, 
-					    0, 0, &port);
+					    options, 0, &port);
     if (status != PJ_SUCCESS) {
 	PJSUA_UNLOCK();
 	pjsua_perror(THIS_FILE, "Unable to open file for playback", status);
@@ -758,6 +778,15 @@
     pjmedia_port *port;
     pj_status_t status;
 
+    /* Don't support max_size at present */
+    PJ_ASSERT_RETURN(max_size == 0, PJ_EINVAL);
+
+    /* Don't support file format at present */
+    PJ_ASSERT_RETURN(file_format == 0, PJ_EINVAL);
+
+    /* Don't support encoding at present */
+    PJ_ASSERT_RETURN(encoding == NULL, PJ_EINVAL);
+
     if (pjsua_var.rec_cnt >= PJ_ARRAY_SIZE(pjsua_var.recorder))
 	return PJ_ETOOMANY;
 
@@ -782,7 +811,7 @@
 					    pjsua_var.mconf_cfg.channel_count,
 					    pjsua_var.mconf_cfg.samples_per_frame,
 					    pjsua_var.mconf_cfg.bits_per_sample, 
-					    0, 0, &port);
+					    options, 0, &port);
     if (status != PJ_SUCCESS) {
 	PJSUA_UNLOCK();
 	pjsua_perror(THIS_FILE, "Unable to open file for recording", status);
@@ -1092,8 +1121,8 @@
 PJ_DEF(pj_status_t) pjsua_codec_set_param( const pj_str_t *id,
 					   const pjmedia_codec_param *param)
 {
+    PJ_UNUSED_ARG(id);
+    PJ_UNUSED_ARG(param);
     PJ_TODO(set_codec_param);
     return PJ_SUCCESS;
 }
-
-