Index: pjproject/trunk/pjlib/src/pj/ioqueue_common_abs.c
===================================================================
--- pjproject/trunk/pjlib/src/pj/ioqueue_common_abs.c	(revision 437)
+++ pjproject/trunk/pjlib/src/pj/ioqueue_common_abs.c	(revision 438)
@@ -71,4 +71,6 @@
     pj_status_t rc;
     int optlen;
+
+    PJ_UNUSED_ARG(pool);
 
     key->ioqueue = ioqueue;
Index: pjproject/trunk/pjmedia/include/pjmedia/codec.h
===================================================================
--- pjproject/trunk/pjmedia/include/pjmedia/codec.h	(revision 437)
+++ pjproject/trunk/pjmedia/include/pjmedia/codec.h	(revision 438)
@@ -111,20 +111,36 @@
 struct pjmedia_codec_param
 {
-    unsigned	clock_rate;	    /**< Sampling rate in Hz		*/
-    unsigned	channel_cnt;	    /**< Channel count.			*/
-    pj_uint32_t	avg_bps;	    /**< Average bandwidth in bits/sec	*/
-
-    pj_uint16_t	ptime;		    /**< Packet time in miliseconds	*/
-    pj_uint8_t	pcm_bits_per_sample;/**< Bits/sample in the PCM side	*/
-
-    unsigned	pt:8;		    /**< Payload type.			*/
-    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    concl:1;	    /**< Packet loss concealment	*/
-    unsigned    reserved:1;	    /**< Reserved, must be NULL.	*/
-
+    /**
+     * The "info" part of codec param describes the capability of the codec,
+     * and the value should NOT be changed by application.
+     */
+    struct {
+       unsigned	   clock_rate;		/**< Sampling rate in Hz	    */
+       unsigned	   channel_cnt;		/**< Channel count.		    */
+       pj_uint32_t avg_bps;		/**< Average bandwidth in bits/sec  */
+       pj_uint16_t frm_ptime;		/**< Base frame ptime in msec.	    */
+       pj_uint8_t  pcm_bits_per_sample;	/**< Bits/sample in the PCM side    */
+       pj_uint8_t  pt;			/**< Payload type.		    */
+    } info;
+
+    /**
+     * The "setting" part of codec param describes various settings to be
+     * applied to the codec. When the codec param is retrieved from the codec
+     * or codec factory, the values of these will be filled by the capability
+     * of the codec. Any features that are supported by the codec (e.g. vad
+     * or plc) will be turned on, so that application can query which 
+     * capabilities are supported by the codec. Application may change the
+     * settings here before instantiating the codec/stream.
+     */
+    struct {
+	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.	*/
+    } setting;
 };
 
@@ -183,9 +199,12 @@
     /**
      * Instruct the codec to inspect the specified payload/packet and
-     * split the packet info individual frames.
+     * split the packet into individual base frames. Each output frames will
+     * have ptime that is equal to basic frame ptime (i.e. the value of
+     * info.frm_ptime in #pjmedia_codec_param).
      *
      * @param codec	The codec instance
      * @param pkt	The input packet.
      * @param pkt_size	Size of the packet.
+     * @param timestamp	The timestamp of the first sample in the packet.
      * @param frame_cnt	On input, specifies the maximum number of frames
      *			in the array. On output, the codec must fill
@@ -196,12 +215,15 @@
      * @return		PJ_SUCCESS on success.
      */
-    pj_status_t (*get_frames)(pjmedia_codec *codec,
-			      void *pkt,
-			      pj_size_t pkt_size,
-			      unsigned *frame_cnt,
-			      pjmedia_frame frames[]);
-
-    /** 
-     * Instruct the codec to encode the specified input frame.
+    pj_status_t (*parse)( pjmedia_codec *codec,
+			  void *pkt,
+			  pj_size_t pkt_size,
+			  const pj_timestamp *timestamp,
+			  unsigned *frame_cnt,
+			  pjmedia_frame frames[]);
+
+    /** 
+     * Instruct the codec to encode the specified input frame. The input
+     * PCM samples MUST have ptime that is exactly equal to base frame
+     * ptime (i.e. the value of info.frm_ptime in #pjmedia_codec_param).
      *
      * @param codec	The codec instance.
@@ -218,5 +240,9 @@
 
     /** 
-     * Instruct the codec to decode the specified input frame.
+     * Instruct the codec to decode the specified input frame. The input
+     * frame MUST have ptime that is exactly equal to base frame
+     * ptime (i.e. the value of info.frm_ptime in #pjmedia_codec_param).
+     * Application can achieve this by parsing the packet into base
+     * frames before decoding each frame.
      *
      * @param codec	The codec instance.
@@ -232,4 +258,17 @@
 			  struct pjmedia_frame *output);
 
+    /**
+     * Instruct the codec to recover a missing frame. Not all codec has
+     * this capability, so this function may be NULL.
+     *
+     * @param codec	The codec instance.
+     * @param out_size	The length of buffer in the output frame.
+     * @param output	The output frame.
+     *
+     * @return		PJ_SUCCESS on success;
+     */
+    pj_status_t (*recover)(pjmedia_codec *codec,
+			   unsigned out_size,
+			   struct pjmedia_frame *output);
 };
 
Index: pjproject/trunk/pjmedia/include/pjmedia/config.h
===================================================================
--- pjproject/trunk/pjmedia/include/pjmedia/config.h	(revision 437)
+++ pjproject/trunk/pjmedia/include/pjmedia/config.h	(revision 438)
@@ -78,4 +78,6 @@
 /**
  * Maximum frame duration (in msec) to be supported.
+ * This (among other thing) will affect the size of buffers to be allocated
+ * for outgoing packets.
  */
 #ifndef PJMEDIA_MAX_FRAME_DURATION_MS   
Index: pjproject/trunk/pjmedia/include/pjmedia/errno.h
===================================================================
--- pjproject/trunk/pjmedia/include/pjmedia/errno.h	(revision 437)
+++ pjproject/trunk/pjmedia/include/pjmedia/errno.h	(revision 438)
@@ -276,4 +276,9 @@
  */
 #define PJMEDIA_CODEC_EPCMTOOSHORT  (PJMEDIA_ERRNO_START+83)    /* 220083 */
+/**
+ * @hideinitializer
+ * Invalid codec frame length.
+ */
+#define PJMEDIA_CODEC_EFRMINLEN	    (PJMEDIA_ERRNO_START+84)    /* 220084 */
 
 
Index: pjproject/trunk/pjmedia/include/pjmedia/jbuf.h
===================================================================
--- pjproject/trunk/pjmedia/include/pjmedia/jbuf.h	(revision 437)
+++ pjproject/trunk/pjmedia/include/pjmedia/jbuf.h	(revision 438)
@@ -56,4 +56,10 @@
 
 /**
+ * @see pjmedia_jb_frame_type.
+ */
+typedef enum pjmedia_jb_frame_type pjmedia_jb_frame_type;
+
+
+/**
  * This structure describes jitter buffer current status.
  */
@@ -79,4 +85,9 @@
  */
 #define PJMEDIA_JB_DEFAULT_INIT_DELAY    15
+
+/**
+ * Opaque declaration for jitter buffer.
+ */
+typedef struct pjmedia_jbuf pjmedia_jbuf;
 
 
@@ -182,8 +193,8 @@
  * @return		PJ_SUCCESS on success.
  */
-PJ_DECL(pj_status_t) pjmedia_jbuf_put_frame(pjmedia_jbuf *jb, 
-					    const void *frame, 
-					    pj_size_t size, 
-					    int frame_seq);
+PJ_DECL(void) pjmedia_jbuf_put_frame( pjmedia_jbuf *jb, 
+				      const void *frame, 
+				      pj_size_t size, 
+				      int frame_seq);
 
 /**
@@ -211,10 +222,8 @@
  *			buffer will copy the frame to the buffer, and frame
  *			type will be set to PJMEDIA_JB_NORMAL_FRAME.
- *
- * @return		Always returns PJ_SUCCESS.
- */
-PJ_DECL(pj_status_t) pjmedia_jbuf_get_frame( pjmedia_jbuf *jb, 
-					     void *frame, 
-					     char *p_frm_type);
+ */
+PJ_DECL(void) pjmedia_jbuf_get_frame( pjmedia_jbuf *jb, 
+				      void *frame, 
+				      char *p_frm_type);
 
 
Index: pjproject/trunk/pjmedia/include/pjmedia/session.h
===================================================================
--- pjproject/trunk/pjmedia/include/pjmedia/session.h	(revision 437)
+++ pjproject/trunk/pjmedia/include/pjmedia/session.h	(revision 438)
@@ -67,10 +67,30 @@
 
 
-/**
- * Initialize stream info from SDP media lines.
- *
- * @param si		Stream info structure to be initialized.
- * @param pool		Pool.
+/** 
+ * Opaque declaration of media session. 
+ */
+typedef struct pjmedia_session pjmedia_session;
+
+
+/**
+ * @see pjmedia_session_info.
+ */
+typedef struct pjmedia_session_info pjmedia_session_info;
+
+
+/**
+ * This function will initialize the session info based on information
+ * in both SDP session descriptors. The remaining information will be
+ * taken from default codec parameters. If socket info array is specified,
+ * the socket will be copied to the session info as well.
+ *
+ * @param pool		Pool to allocate memory.
  * @param endpt		Pjmedia endpoint.
+ * @param max_streams	Maximum number of stream infos to be created.
+ * @param si		Session info structure to be initialized.
+ * @param skinfo	Optional array of media socket info to be copied
+ *			to the stream info. If this argument is specified,
+ *			the array must contain sufficient elements for
+ *			each stream to be initialized.
  * @param local		Local SDP session descriptor.
  * @param remote	Remote SDP session descriptor.
@@ -79,12 +99,39 @@
  * @return		PJ_SUCCESS if stream info is successfully initialized.
  */
-PJ_DECL(pj_status_t) pjmedia_stream_info_from_sdp( 
-					   pjmedia_stream_info *si,
-					   pj_pool_t *pool,
-					   pjmedia_endpt *endpt,
-					   const pjmedia_sdp_session *local,
-					   const pjmedia_sdp_session *remote,
-					   unsigned stream_idx);
-
+PJ_DECL(pj_status_t)
+pjmedia_session_info_from_sdp( pj_pool_t *pool,
+			       pjmedia_endpt *endpt,
+			       unsigned max_streams,
+			       pjmedia_session_info *si,
+			       const pjmedia_sock_info skinfo[],
+			       const pjmedia_sdp_session *local,
+			       const pjmedia_sdp_session *remote);
+
+
+/*
+ * This function will initialize the stream info based on information
+ * in both SDP session descriptors for the specified stream index. 
+ * The remaining information will be taken from default codec parameters. 
+ * If socket info array is specified, the socket will be copied to the 
+ * session info as well.
+ *
+ * @param si		Stream info structure to be initialized.
+ * @param pool		Pool to allocate memory.
+ * @param endpt		PJMEDIA endpoint instance.
+ * @param skinfo	Optional socket info to be copied to the stream info.
+ * @param local		Local SDP session descriptor.
+ * @param remote	Remote SDP session descriptor.
+ * @param stream_idx	Media stream index in the session descriptor.
+ *
+ * @return		PJ_SUCCESS if stream info is successfully initialized.
+ */
+PJ_DECL(pj_status_t)
+pjmedia_stream_info_from_sdp( pjmedia_stream_info *si,
+			      pj_pool_t *pool,
+			      pjmedia_endpt *endpt,
+			      const pjmedia_sock_info *skinfo,
+			      const pjmedia_sdp_session *local,
+			      const pjmedia_sdp_session *remote,
+			      unsigned stream_idx);
 
 /**
@@ -102,8 +149,4 @@
  *			also denotes the number of elements in the
  *			socket information.
- * @param skinfo	Array of socket informations. The argument stream_cnt
- *			specifies the number of elements in this array. One
- *			element is needed for each media stream to be
- *			created in the session.
  * @param local_sdp	The SDP describing local capability.
  * @param rem_sdp	The SDP describing remote capability.
@@ -116,8 +159,5 @@
 PJ_DECL(pj_status_t) 
 pjmedia_session_create( pjmedia_endpt *endpt, 
-			unsigned stream_cnt,
-			const pjmedia_sock_info skinfo[],
-			const pjmedia_sdp_session *local_sdp,
-			const pjmedia_sdp_session *rem_sdp,
+			const pjmedia_session_info *si,
 			void *user_data,
 			pjmedia_session **p_session );
Index: pjproject/trunk/pjmedia/include/pjmedia/stream.h
===================================================================
--- pjproject/trunk/pjmedia/include/pjmedia/stream.h	(revision 437)
+++ pjproject/trunk/pjmedia/include/pjmedia/stream.h	(revision 438)
@@ -73,11 +73,29 @@
     pj_sockaddr_in	rem_addr;   /**< Remote RTP address		    */
     pjmedia_codec_info	fmt;	    /**< Incoming codec format info.	    */
+    pjmedia_codec_param *param;	    /**< Optional codec param.		    */
     unsigned		tx_pt;	    /**< Outgoing codec paylaod type.	    */
     int		        tx_event_pt;/**< Outgoing pt for telephone-events.  */
     int			rx_event_pt;/**< Incoming pt for telephone-events.  */
     pj_uint32_t		ssrc;	    /**< RTP SSRC.			    */
-    int			jb_init;    /**< Jitter buffer init delay in msec.  */
+    int			jb_init;    /**< Jitter buffer init delay in msec.  
+					 (-1 for default).		    */
+    int			jb_min_pre; /**< Jitter buffer minimum prefetch
+					 delay in msec (-1 for default).    */
+    int			jb_max_pre; /**< Jitter buffer maximum prefetch
+					 delay in msec (-1 for default).    */
     int			jb_max;	    /**< Jitter buffer max delay in msec.   */
 };
+
+
+/**
+ * @see pjmedia_stream_info.
+ */
+typedef struct pjmedia_stream_info pjmedia_stream_info;
+
+
+/**
+ * Opaque declaration for media stream.
+ */
+typedef struct pjmedia_stream pjmedia_stream;
 
 
Index: pjproject/trunk/pjmedia/include/pjmedia/types.h
===================================================================
--- pjproject/trunk/pjmedia/include/pjmedia/types.h	(revision 437)
+++ pjproject/trunk/pjmedia/include/pjmedia/types.h	(revision 438)
@@ -115,42 +115,18 @@
 
 /**
- * Typedef for media stream information.
+ * This is a general purpose function set PCM samples to zero.
+ * Since this function is needed by many parts of the library, it is important
+ * that the library should select the best performance for this.
+ *
+ * @param samples	The 16bit PCM samples.
+ * @param count		Number of samples.
  */
-typedef struct pjmedia_stream_info pjmedia_stream_info;
+PJ_INLINE(void) pjmedia_zero_samples(pj_int16_t *samples, unsigned count)
+{
+    unsigned i;
+    for (i=0; i<count; ++i)
+	samples[i] = 0;
+}
 
-/**
- * Typedef for media stream statistic.
- */
-typedef struct pjmedia_stream_stat pjmedia_stream_stat;
-
-/**
- * Typedef for media stream.
- */
-typedef struct pjmedia_stream pjmedia_stream;
-
-/**
- * Individual channel statistic.
- */
-typedef struct pjmedia_channel_stat pjmedia_channel_stat;
-
-/** 
- * Opaque declaration of media session. 
- */
-typedef struct pjmedia_session pjmedia_session;
-
-/**
- * Media session info.
- */
-typedef struct pjmedia_session_info pjmedia_session_info;
-
-/**
- * Types of frame returned from jitter buffer (jbuf.h).
- */
-typedef enum pjmedia_jb_frame_type pjmedia_jb_frame_type;
-
-/**
- * Opaque declaration for jitter buffer.
- */
-typedef struct pjmedia_jbuf pjmedia_jbuf;
 
 #endif	/* __PJMEDIA_TYPES_H__ */
Index: pjproject/trunk/pjmedia/src/pjmedia-codec/gsm.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia-codec/gsm.c	(revision 437)
+++ pjproject/trunk/pjmedia/src/pjmedia-codec/gsm.c	(revision 438)
@@ -55,9 +55,10 @@
 				    pjmedia_codec_param *attr );
 static pj_status_t  gsm_codec_close( pjmedia_codec *codec );
-static pj_status_t  gsm_codec_get_frames( pjmedia_codec *codec,
-					  void *pkt,
-					  pj_size_t pkt_size,
-					  unsigned *frame_cnt,
-					  pjmedia_frame frames[]);
+static pj_status_t  gsm_codec_parse( pjmedia_codec *codec,
+				     void *pkt,
+				     pj_size_t pkt_size,
+				     const pj_timestamp *ts,
+				     unsigned *frame_cnt,
+				     pjmedia_frame frames[]);
 static pj_status_t  gsm_codec_encode( pjmedia_codec *codec, 
 				      const struct pjmedia_frame *input,
@@ -75,5 +76,5 @@
     &gsm_codec_open,
     &gsm_codec_close,
-    &gsm_codec_get_frames,
+    &gsm_codec_parse,
     &gsm_codec_encode,
     &gsm_codec_decode
@@ -231,10 +232,12 @@
 
     pj_memset(attr, 0, sizeof(pjmedia_codec_param));
-    attr->clock_rate = 8000;
-    attr->channel_cnt = 1;
-    attr->avg_bps = 13200;
-    attr->pcm_bits_per_sample = 16;
-    attr->ptime = 20;
-    attr->pt = PJMEDIA_RTP_PT_GSM;
+    attr->info.clock_rate = 8000;
+    attr->info.channel_cnt = 1;
+    attr->info.avg_bps = 13200;
+    attr->info.pcm_bits_per_sample = 16;
+    attr->info.frm_ptime = 20;
+    attr->info.pt = PJMEDIA_RTP_PT_GSM;
+
+    attr->setting.frm_per_pkt = 1;
 
     /* Default all flag bits disabled. */
@@ -387,9 +390,10 @@
  * Get frames in the packet.
  */
-static pj_status_t  gsm_codec_get_frames( pjmedia_codec *codec,
-					  void *pkt,
-					  pj_size_t pkt_size,
-					  unsigned *frame_cnt,
-					  pjmedia_frame frames[])
+static pj_status_t  gsm_codec_parse( pjmedia_codec *codec,
+				     void *pkt,
+				     pj_size_t pkt_size,
+				     const pj_timestamp *ts,
+				     unsigned *frame_cnt,
+				     pjmedia_frame frames[])
 {
     unsigned count = 0;
@@ -400,7 +404,8 @@
 
     while (pkt_size >= 33 && count < *frame_cnt) {
-	frames[0].type = PJMEDIA_FRAME_TYPE_AUDIO;
-	frames[0].buf = pkt;
-	frames[0].size = 33;
+	frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
+	frames[count].buf = pkt;
+	frames[count].size = 33;
+	frames[count].timestamp.u64 = ts->u64 + count * 160;
 
 	pkt = ((char*)pkt) + 33;
Index: pjproject/trunk/pjmedia/src/pjmedia-codec/l16.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia-codec/l16.c	(revision 437)
+++ pjproject/trunk/pjmedia/src/pjmedia-codec/l16.c	(revision 438)
@@ -62,9 +62,10 @@
 			       pjmedia_codec_param *attr );
 static pj_status_t  l16_close( pjmedia_codec *codec );
-static pj_status_t  l16_get_frames(pjmedia_codec *codec,
-				    void *pkt,
-				    pj_size_t pkt_size,
-				    unsigned *frame_cnt,
-				    pjmedia_frame frames[]);
+static pj_status_t  l16_parse(pjmedia_codec *codec,
+			      void *pkt,
+			      pj_size_t pkt_size,
+			      const pj_timestamp *ts,
+			      unsigned *frame_cnt,
+			      pjmedia_frame frames[]);
 static pj_status_t  l16_encode( pjmedia_codec *codec, 
 				 const struct pjmedia_frame *input,
@@ -82,5 +83,5 @@
     &l16_open,
     &l16_close,
-    &l16_get_frames,
+    &l16_parse,
     &l16_encode,
     &l16_decode
@@ -235,14 +236,16 @@
 
     pj_memset(attr, 0, sizeof(pjmedia_codec_param));
-    attr->pt = id->pt;
-    attr->clock_rate = id->clock_rate;
-    attr->channel_cnt = id->channel_cnt;
-    attr->avg_bps = id->clock_rate * id->channel_cnt * 16;
-    attr->pcm_bits_per_sample = 16;
+    attr->info.pt = (pj_uint8_t)id->pt;
+    attr->info.clock_rate = id->clock_rate;
+    attr->info.channel_cnt = id->channel_cnt;
+    attr->info.avg_bps = id->clock_rate * id->channel_cnt * 16;
+    attr->info.pcm_bits_per_sample = 16;
 
     /* To keep frame size below 1400 MTU, set ptime to 10ms for
      * sampling rate > 35 KHz
      */
-    attr->ptime = GET_PTIME(id->clock_rate);
+    attr->info.frm_ptime = GET_PTIME(id->clock_rate);
+
+    attr->setting.frm_per_pkt = 1;
 
     /* Default all flag bits disabled. */
@@ -499,9 +502,10 @@
 }
 
-static pj_status_t  l16_get_frames( pjmedia_codec *codec,
-				    void *pkt,
-				    pj_size_t pkt_size,
-				    unsigned *frame_cnt,
-				    pjmedia_frame frames[])
+static pj_status_t  l16_parse( pjmedia_codec *codec,
+			       void *pkt,
+			       pj_size_t pkt_size,
+			       const pj_timestamp *ts,
+			       unsigned *frame_cnt,
+			       pjmedia_frame frames[])
 {
     unsigned count = 0;
@@ -512,7 +516,8 @@
 
     while (pkt_size >= data->frame_size && count < *frame_cnt) {
-	frames[0].type = PJMEDIA_FRAME_TYPE_AUDIO;
-	frames[0].buf = pkt;
-	frames[0].size = data->frame_size;
+	frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
+	frames[count].buf = pkt;
+	frames[count].size = data->frame_size;
+	frames[count].timestamp.u64 = ts->u64 + (count * data->frame_size);
 
 	pkt = ((char*)pkt) + data->frame_size;
Index: pjproject/trunk/pjmedia/src/pjmedia-codec/speex/ltp.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia-codec/speex/ltp.c	(revision 437)
+++ pjproject/trunk/pjmedia/src/pjmedia-codec/speex/ltp.c	(revision 438)
@@ -177,5 +177,5 @@
    VARDECL(spx_word32_t *energy);
    VARDECL(spx_word32_t *score);
-   VARDECL(spx_word16_t *swn2);
+   /*VARDECL(spx_word16_t *swn2);*/
    spx_word16_t *swn;
 
Index: pjproject/trunk/pjmedia/src/pjmedia-codec/speex_codec.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia-codec/speex_codec.c	(revision 437)
+++ pjproject/trunk/pjmedia/src/pjmedia-codec/speex_codec.c	(revision 438)
@@ -62,9 +62,10 @@
 				    pjmedia_codec_param *attr );
 static pj_status_t  spx_codec_close( pjmedia_codec *codec );
-static pj_status_t  spx_codec_get_frames( pjmedia_codec *codec,
-					  void *pkt,
-					  pj_size_t pkt_size,
-					  unsigned *frame_cnt,
-					  pjmedia_frame frames[]);
+static pj_status_t  spx_codec_parse( pjmedia_codec *codec,
+				     void *pkt,
+				     pj_size_t pkt_size,
+				     const pj_timestamp *ts,
+				     unsigned *frame_cnt,
+				     pjmedia_frame frames[]);
 static pj_status_t  spx_codec_encode( pjmedia_codec *codec, 
 				      const struct pjmedia_frame *input,
@@ -75,4 +76,7 @@
 				      unsigned output_buf_len, 
 				      struct pjmedia_frame *output);
+static pj_status_t  spx_codec_recover(pjmedia_codec *codec, 
+				      unsigned output_buf_len, 
+				      struct pjmedia_frame *output);
 
 /* Definition for Speex codec operations. */
@@ -82,7 +86,8 @@
     &spx_codec_open,
     &spx_codec_close,
-    &spx_codec_get_frames,
+    &spx_codec_parse,
     &spx_codec_encode,
-    &spx_codec_decode
+    &spx_codec_decode,
+    &spx_codec_recover
 };
 
@@ -378,34 +383,36 @@
 
     pj_memset(attr, 0, sizeof(pjmedia_codec_param));
-    attr->pt = id->pt;
-    attr->channel_cnt = 1;
+    attr->info.pt = (pj_uint8_t)id->pt;
+    attr->info.channel_cnt = 1;
 
     if (id->clock_rate <= 8000) {
-	attr->clock_rate = spx_factory.speex_param[PARAM_NB].clock_rate;
-	attr->avg_bps = spx_factory.speex_param[PARAM_NB].bitrate;
+	attr->info.clock_rate = spx_factory.speex_param[PARAM_NB].clock_rate;
+	attr->info.avg_bps = spx_factory.speex_param[PARAM_NB].bitrate;
 
     } else if (id->clock_rate <= 16000) {
-	attr->clock_rate = spx_factory.speex_param[PARAM_WB].clock_rate;
-	attr->avg_bps = spx_factory.speex_param[PARAM_WB].bitrate;
+	attr->info.clock_rate = spx_factory.speex_param[PARAM_WB].clock_rate;
+	attr->info.avg_bps = spx_factory.speex_param[PARAM_WB].bitrate;
 
     } else {
 	/* Wow.. somebody is doing ultra-wideband. Cool...! */
-	attr->clock_rate = spx_factory.speex_param[PARAM_UWB].clock_rate;
-	attr->avg_bps = spx_factory.speex_param[PARAM_UWB].bitrate;
-    }
-
-    attr->pcm_bits_per_sample = 16;
-    attr->ptime = 20;
-    attr->pt = id->pt;
+	attr->info.clock_rate = spx_factory.speex_param[PARAM_UWB].clock_rate;
+	attr->info.avg_bps = spx_factory.speex_param[PARAM_UWB].bitrate;
+    }
+
+    attr->info.pcm_bits_per_sample = 16;
+    attr->info.frm_ptime = 20;
+    attr->info.pt = (pj_uint8_t)id->pt;
+
+    attr->setting.frm_per_pkt = 1;
 
     /* Default flags. */
-    attr->cng = 1;
-    attr->concl = 1;
-    attr->hpf = 1;
-    attr->lpf =1 ;
-    attr->penh =1 ;
+    attr->setting.cng = 1;
+    attr->setting.plc = 1;
+    attr->setting.hpf = 1;
+    attr->setting.lpf =1 ;
+    attr->setting.penh =1 ;
 
     /* Default, set VAD off as it caused voice chip off */
-    attr->vad = 0;
+    attr->setting.vad = 0;
 
     return PJ_SUCCESS;
@@ -560,10 +567,10 @@
 
     /* Sampling rate. */
-    tmp = attr->clock_rate;
+    tmp = attr->info.clock_rate;
     speex_encoder_ctl(spx->enc, SPEEX_SET_SAMPLING_RATE, 
 		      &spx_factory.speex_param[id].clock_rate);
 
     /* VAD */
-    tmp = attr->vad;
+    tmp = attr->setting.vad;
     speex_encoder_ctl(spx->enc, SPEEX_SET_VAD, &tmp);
 
@@ -589,5 +596,5 @@
 
     /* PENH */
-    tmp = attr->penh;
+    tmp = attr->setting.penh;
     speex_decoder_ctl(spx->dec, SPEEX_SET_ENH, &tmp);
 
@@ -625,36 +632,41 @@
  * Get frames in the packet.
  */
-static pj_status_t  spx_codec_get_frames( pjmedia_codec *codec,
-					  void *pkt,
-					  pj_size_t pkt_size,
-					  unsigned *frame_cnt,
-					  pjmedia_frame frames[])
+static pj_status_t  spx_codec_parse( pjmedia_codec *codec,
+				     void *pkt,
+				     pj_size_t pkt_size,
+				     const pj_timestamp *ts,
+				     unsigned *frame_cnt,
+				     pjmedia_frame frames[])
 {
     struct spx_private *spx;
-    unsigned speex_frame_size;
+    unsigned frame_size, samples_per_frame;
     unsigned count;
 
     spx = (struct spx_private*) codec->codec_data;
 
-    speex_frame_size = spx_factory.speex_param[spx->param_id].framesize;
+    frame_size = spx_factory.speex_param[spx->param_id].framesize;
+    samples_per_frame = spx_factory.speex_param[spx->param_id].samples_per_frame;
 
     /* Don't really know how to do this... */
     count = 0;
-    while (pkt_size >= speex_frame_size && count < *frame_cnt) {
+    while (pkt_size >= frame_size && count < *frame_cnt) {
 	frames[count].buf = pkt;
-	frames[count].size = speex_frame_size;
+	frames[count].size = frame_size;
 	frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
-	frames[count].timestamp.u64 = 0;
-
-	pkt_size -= speex_frame_size;
+	frames[count].timestamp.u64 = ts->u64 + count * samples_per_frame;
+
+	pkt_size -= frame_size;
 	++count;
-	pkt = ((char*)pkt) + speex_frame_size;
-    }
-
+	pkt = ((char*)pkt) + frame_size;
+    }
+
+    /* Just in case speex has silence frame which size is less than normal
+     * frame size...
+     */
     if (pkt_size && count < *frame_cnt) {
 	frames[count].buf = pkt;
 	frames[count].size = pkt_size;
 	frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
-	frames[count].timestamp.u64 = 0;
+	frames[count].timestamp.u64 = ts->u64 + count * samples_per_frame;
 	++count;
     }
@@ -765,4 +777,34 @@
 }
 
+/* 
+ * Recover lost frame.
+ */
+static pj_status_t  spx_codec_recover(pjmedia_codec *codec, 
+				      unsigned output_buf_len, 
+				      struct pjmedia_frame *output)
+{
+    struct spx_private *spx;
+    float tmp[642]; /* 20ms at 32KHz + 2 */
+    pj_int16_t *dst_buf;
+    unsigned i, count;
+
+    spx = (struct spx_private*) codec->codec_data;
+
+    count = spx_factory.speex_param[spx->param_id].clock_rate * 20 / 1000;
+    pj_assert((count <= output_buf_len/2) && count <= PJ_ARRAY_SIZE(tmp));
+
+    /* Recover packet loss */
+    speex_decode(spx->dec, NULL, tmp);
+
+    /* Copy from float to short samples. */
+    dst_buf = output->buf;
+    for (i=0; i<count; ++i) {
+	dst_buf[i] = (pj_int16_t)tmp[i];
+    }
+    output->size = count * 2;
+
+    return PJ_SUCCESS;
+}
+
 
 #endif	/* PJMEDIA_HAS_SPEEX_CODEC */
Index: pjproject/trunk/pjmedia/src/pjmedia/endpoint.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia/endpoint.c	(revision 437)
+++ pjproject/trunk/pjmedia/src/pjmedia/endpoint.c	(revision 438)
@@ -474,10 +474,10 @@
 		  codec_info[i].clock_rate/1000,
 		  codec_info[i].channel_cnt,
-		  good_number(bps, param.avg_bps), 
-		  param.ptime,
-		  (param.vad ? " vad" : ""),
-		  (param.cng ? " cng" : ""),
-		  (param.concl ? " plc" : ""),
-		  (param.penh ? " penh" : ""),
+		  good_number(bps, param.info.avg_bps), 
+		  param.info.frm_ptime * param.setting.frm_per_pkt,
+		  (param.setting.vad ? " vad" : ""),
+		  (param.setting.cng ? " cng" : ""),
+		  (param.setting.plc ? " plc" : ""),
+		  (param.setting.penh ? " penh" : ""),
 		  (prio[i]==PJMEDIA_CODEC_PRIO_DISABLED?" disabled":"")));
     }
Index: pjproject/trunk/pjmedia/src/pjmedia/errno.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia/errno.c	(revision 437)
+++ pjproject/trunk/pjmedia/src/pjmedia/errno.c	(revision 438)
@@ -88,4 +88,5 @@
     { PJMEDIA_CODEC_EFRMTOOSHORT,   "Codec frame is too short" },
     { PJMEDIA_CODEC_EPCMTOOSHORT,   "PCM frame is too short" },
+    { PJMEDIA_CODEC_EFRMINLEN,	    "Invalid codec frame length" },
 
     /* Media errors. */
Index: pjproject/trunk/pjmedia/src/pjmedia/g711.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia/g711.c	(revision 437)
+++ pjproject/trunk/pjmedia/src/pjmedia/g711.c	(revision 438)
@@ -24,4 +24,5 @@
 #include <pjmedia/errno.h>
 #include <pjmedia/port.h>
+#include <pjmedia/plc.h>
 #include <pj/pool.h>
 #include <pj/string.h>
@@ -31,14 +32,16 @@
 
 
-#define G711_BPS	64000
-#define G711_CODEC_CNT	0	/* number of codec to preallocate in memory */
-#define PTIME		20
-#define FRAME_SIZE	(8000 * PTIME / 1000)
+#define G711_BPS	    64000
+#define G711_CODEC_CNT	    0	/* number of codec to preallocate in memory */
+#define PTIME		    10	/* basic frame size is 10 msec	    */
+#define FRAME_SIZE	    (8000 * PTIME / 1000)   /* 80 bytes	    */
+#define SAMPLES_PER_FRAME   (8000 * PTIME / 1000)   /* 80 samples   */
 
 /* These are the only public functions exported to applications */
-PJ_DECL(pj_status_t) g711_init_factory (pjmedia_codec_factory *factory, pj_pool_t *pool);
+PJ_DECL(pj_status_t) g711_init_factory (pjmedia_codec_factory *factory, 
+					pj_pool_t *pool);
 
 /* Algorithm prototypes. */
-unsigned char linear2alaw(int		pcm_val);   /* 2's complement (16-bit range) */
+unsigned char linear2alaw(int		pcm_val);
 int	      alaw2linear(unsigned char	a_val);
 unsigned char linear2ulaw(int		pcm_val);
@@ -66,9 +69,10 @@
 			       pjmedia_codec_param *attr );
 static pj_status_t  g711_close( pjmedia_codec *codec );
-static pj_status_t  g711_get_frames(pjmedia_codec *codec,
-				    void *pkt,
-				    pj_size_t pkt_size,
-				    unsigned *frame_cnt,
-				    pjmedia_frame frames[]);
+static pj_status_t  g711_parse(pjmedia_codec *codec,
+			       void *pkt,
+			       pj_size_t pkt_size,
+			       const pj_timestamp *timestamp,
+			       unsigned *frame_cnt,
+			       pjmedia_frame frames[]);
 static pj_status_t  g711_encode( pjmedia_codec *codec, 
 				 const struct pjmedia_frame *input,
@@ -79,4 +83,7 @@
 				 unsigned output_buf_len, 
 				 struct pjmedia_frame *output);
+static pj_status_t  g711_recover( pjmedia_codec *codec,
+				  unsigned output_buf_len,
+				  struct pjmedia_frame *output);
 
 /* Definition for G711 codec operations. */
@@ -86,7 +93,8 @@
     &g711_open,
     &g711_close,
-    &g711_get_frames,
+    &g711_parse,
     &g711_encode,
-    &g711_decode
+    &g711_decode,
+    &g711_recover
 };
 
@@ -114,5 +122,7 @@
 struct g711_private
 {
-    unsigned pt;
+    unsigned	    pt;
+    pj_bool_t	    plc_enabled;
+    pjmedia_plc	   *plc;
 };
 
@@ -218,5 +228,5 @@
 
     /* It's sufficient to check payload type only. */
-    return (id->pt==PJMEDIA_RTP_PT_PCMU || id->pt==PJMEDIA_RTP_PT_PCMA) ? 0 : -1;
+    return (id->pt==PJMEDIA_RTP_PT_PCMU || id->pt==PJMEDIA_RTP_PT_PCMA)? 0:-1;
 }
 
@@ -228,10 +238,16 @@
 
     pj_memset(attr, 0, sizeof(pjmedia_codec_param));
-    attr->clock_rate = 8000;
-    attr->channel_cnt = 1;
-    attr->avg_bps = G711_BPS;
-    attr->pcm_bits_per_sample = 16;
-    attr->ptime = PTIME;
-    attr->pt = id->pt;
+    attr->info.clock_rate = 8000;
+    attr->info.channel_cnt = 1;
+    attr->info.avg_bps = G711_BPS;
+    attr->info.pcm_bits_per_sample = 16;
+    attr->info.frm_ptime = PTIME;
+    attr->info.pt = (pj_uint8_t)id->pt;
+
+    /* Set default frames per packet to 2 (or 20ms) */
+    attr->setting.frm_per_pkt = 2;
+
+    /* Enable plc by default. */
+    attr->setting.plc = 1;
 
     /* Default all flag bits disabled. */
@@ -275,4 +291,5 @@
 {
     pjmedia_codec *codec = NULL;
+    pj_status_t status;
 
     PJ_ASSERT_RETURN(factory==&g711_factory.base, PJ_EINVAL);
@@ -293,5 +310,14 @@
 	}
 
+	/* Set the payload type */
 	codec_priv->pt = id->pt;
+
+	/* Create PLC, always with 10ms ptime */
+	status = pjmedia_plc_create(g711_factory.pool, 8000, 80,
+				    0, &codec_priv->plc);
+	if (status != PJ_SUCCESS) {
+	    pj_mutex_unlock(g711_factory.mutex);
+	    return status;
+	}
 
 	codec->factory = factory;
@@ -351,5 +377,6 @@
 {
     struct g711_private *priv = codec->codec_data;
-    priv->pt = attr->pt;
+    priv->pt = attr->info.pt;
+    priv->plc_enabled = (attr->setting.plc != 0);
     return PJ_SUCCESS;
 }
@@ -362,19 +389,22 @@
 }
 
-static pj_status_t  g711_get_frames(pjmedia_codec *codec,
-				    void *pkt,
-				    pj_size_t pkt_size,
-				    unsigned *frame_cnt,
-				    pjmedia_frame frames[])
+static pj_status_t  g711_parse( pjmedia_codec *codec,
+				void *pkt,
+				pj_size_t pkt_size,
+				const pj_timestamp *ts,
+				unsigned *frame_cnt,
+				pjmedia_frame frames[])
 {
     unsigned count = 0;
 
     PJ_UNUSED_ARG(codec);
-    PJ_ASSERT_RETURN(frame_cnt, PJ_EINVAL);
+
+    PJ_ASSERT_RETURN(ts && frame_cnt && frames, PJ_EINVAL);
 
     while (pkt_size >= FRAME_SIZE && count < *frame_cnt) {
-	frames[0].type = PJMEDIA_FRAME_TYPE_AUDIO;
-	frames[0].buf = pkt;
-	frames[0].size = FRAME_SIZE;
+	frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
+	frames[count].buf = pkt;
+	frames[count].size = FRAME_SIZE;
+	frames[count].timestamp.u64 = ts->u64 + SAMPLES_PER_FRAME * count;
 
 	pkt = ((char*)pkt) + FRAME_SIZE;
@@ -434,6 +464,10 @@
 
     /* Check output buffer length */
-    if (output_buf_len < input->size * 2)
-	return PJMEDIA_CODEC_EPCMTOOSHORT;
+    PJ_ASSERT_RETURN(output_buf_len >= input->size * 2,
+		     PJMEDIA_CODEC_EPCMTOOSHORT);
+
+    /* Input buffer MUST have exactly 80 bytes long */
+    PJ_ASSERT_RETURN(input->size == FRAME_SIZE, 
+		     PJMEDIA_CODEC_EFRMINLEN);
 
     /* Decode */
@@ -462,7 +496,27 @@
     output->size = input->size * 2;
 
-    return PJ_SUCCESS;
-}
-
+    if (priv->plc_enabled)
+	pjmedia_plc_save( priv->plc, output->buf);
+
+    return PJ_SUCCESS;
+}
+
+static pj_status_t  g711_recover( pjmedia_codec *codec,
+				  unsigned output_buf_len,
+				  struct pjmedia_frame *output)
+{
+    struct g711_private *priv = codec->codec_data;
+
+    if (!priv->plc_enabled)
+	return PJ_EINVALIDOP;
+
+    PJ_ASSERT_RETURN(output_buf_len >= SAMPLES_PER_FRAME * 2, 
+		     PJMEDIA_CODEC_EPCMTOOSHORT);
+
+    pjmedia_plc_generate(priv->plc, output->buf);
+    output->size = SAMPLES_PER_FRAME * 2;
+
+    return PJ_SUCCESS;
+}
 
 #endif	/* PJMEDIA_HAS_G711_CODEC */
Index: pjproject/trunk/pjmedia/src/pjmedia/jbuf.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia/jbuf.c	(revision 437)
+++ pjproject/trunk/pjmedia/src/pjmedia/jbuf.c	(revision 438)
@@ -433,8 +433,8 @@
 }
 
-PJ_DEF(pj_status_t) pjmedia_jbuf_put_frame(pjmedia_jbuf *jb, 
-					   const void *frame, 
-					   pj_size_t frame_size, 
-					   int frame_seq)
+PJ_DEF(void) pjmedia_jbuf_put_frame( pjmedia_jbuf *jb, 
+				     const void *frame, 
+				     pj_size_t frame_size, 
+				     int frame_seq)
 {
     pj_size_t min_frame_size;
@@ -476,6 +476,4 @@
 	jb_framelist_put_at(&jb->jb_framelist,frame_seq,frame,min_frame_size);
     }
-
-    return PJ_SUCCESS;
 }
 
@@ -483,7 +481,7 @@
  * Get frame from jitter buffer.
  */
-PJ_DEF(pj_status_t) pjmedia_jbuf_get_frame( pjmedia_jbuf *jb, 
-					    void *frame, 
-					    char *p_frame_type)
+PJ_DEF(void) pjmedia_jbuf_get_frame( pjmedia_jbuf *jb, 
+				     void *frame, 
+				     char *p_frame_type)
 {
     pjmedia_jb_frame_type ftype;
@@ -507,5 +505,5 @@
 	    *p_frame_type = PJMEDIA_JB_ZERO_PREFETCH_FRAME;
 
-	return PJ_SUCCESS;
+	return;
     }
 
@@ -516,5 +514,5 @@
 	*p_frame_type = PJMEDIA_JB_ZERO_EMPTY_FRAME;
 
-	return PJ_SUCCESS;
+	return;
     }
 
@@ -526,7 +524,4 @@
     else 
 	*p_frame_type	= PJMEDIA_JB_MISSING_FRAME;
-    
-
-    return PJ_SUCCESS;
 }
 
Index: pjproject/trunk/pjmedia/src/pjmedia/plc_common.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia/plc_common.c	(revision 437)
+++ pjproject/trunk/pjmedia/src/pjmedia/plc_common.c	(revision 438)
@@ -27,8 +27,4 @@
 static void  plc_replay_save(void*, pj_int16_t*);
 static void  plc_replay_generate(void*, pj_int16_t*);
-
-static void* noplc_create(pj_pool_t*, unsigned c, unsigned f);
-static void  noplc_save(void*, pj_int16_t*);
-static void  noplc_generate(void*, pj_int16_t*);
 
 extern void* pjmedia_plc_g711_create(pj_pool_t*, unsigned c, unsigned f);
@@ -63,12 +59,4 @@
     &plc_replay_save,
     &plc_replay_generate
-};
-
-
-static struct plc_alg no_plc =
-{
-    &noplc_create,
-    &noplc_save,
-    &noplc_generate
 };
 
@@ -202,26 +190,2 @@
 
 
-//////////////////////////////////////////////////////////////////////////////
-/*
- * No PLC
- */
-static void* noplc_create(pj_pool_t *pool, unsigned clock_rate, 
-			  unsigned samples_per_sec)
-{
-    PJ_UNUSED_ARG(pool);    
-    PJ_UNUSED_ARG(clock_rate);
-    return (void*) samples_per_sec;
-}
-
-static void noplc_save(void *plc, pj_int16_t *frame)
-{
-    PJ_UNUSED_ARG(plc);
-    PJ_UNUSED_ARG(frame);
-}
-
-static void  noplc_generate(void *plc, pj_int16_t *frame)
-{
-    unsigned samples_per_sec = (unsigned)plc;
-    pj_memset(frame, 0, samples_per_sec);
-}
-
Index: pjproject/trunk/pjmedia/src/pjmedia/session.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia/session.c	(revision 437)
+++ pjproject/trunk/pjmedia/src/pjmedia/session.c	(revision 438)
@@ -65,8 +65,10 @@
 					   pj_pool_t *pool,
 					   pjmedia_endpt *endpt,
+					   const pjmedia_sock_info *skinfo,
 					   const pjmedia_sdp_session *local,
 					   const pjmedia_sdp_session *remote,
 					   unsigned stream_idx)
 {
+    pjmedia_codec_mgr *mgr;
     const pjmedia_sdp_attr *attr;
     const pjmedia_sdp_media *local_m;
@@ -86,4 +88,8 @@
 
 
+    /* Get codec manager. */
+    mgr = pjmedia_endpt_get_codec_mgr(endpt);
+
+    /* Keep SDP shortcuts */
     local_m = local->media[stream_idx];
     rem_m = remote->media[stream_idx];
@@ -216,9 +222,6 @@
 	    }
 
-	} else {
-	    pjmedia_codec_mgr *mgr;
-	    pjmedia_codec_info *p_info;
-
-	    mgr = pjmedia_endpt_get_codec_mgr(endpt);
+	} else {	    
+	    const pjmedia_codec_info *p_info;
 
 	    status = pjmedia_codec_mgr_get_codec_info( mgr, pt, &p_info);
@@ -302,4 +305,9 @@
 
   
+    /* Now that we have codec info, get the codec param. */
+    si->param = pj_pool_alloc(pool, sizeof(*si->param));
+    status = pjmedia_codec_mgr_get_default_param(mgr, &si->fmt, si->param);
+    if (status != PJ_SUCCESS)
+	return status;
 
     /* Get incomming payload type for telephone-events */
@@ -335,10 +343,50 @@
     }
 
+    /* Copy skinfo */
+    if (skinfo)
+	si->sock_info = *skinfo;
 
     /* Leave SSRC to random. */
     si->ssrc = pj_rand();
 
-    /* Leave jitter buffer parameter. */
-    
+    /* Set default jitter buffer parameter. */
+    si->jb_init = si->jb_max = si->jb_min_pre = si->jb_max_pre = -1;
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Initialize session info from SDP session descriptors.
+ */
+PJ_DEF(pj_status_t) 
+pjmedia_session_info_from_sdp( pj_pool_t *pool,
+			       pjmedia_endpt *endpt,
+			       unsigned max_streams,
+			       pjmedia_session_info *si,
+			       const pjmedia_sock_info skinfo[],
+			       const pjmedia_sdp_session *local,
+			       const pjmedia_sdp_session *remote)
+{
+    unsigned i;
+
+    PJ_ASSERT_RETURN(pool && endpt && si && local && remote, PJ_EINVAL);
+
+    si->stream_cnt = max_streams;
+    if (si->stream_cnt > local->media_count)
+	si->stream_cnt = local->media_count;
+
+    for (i=0; i<si->stream_cnt; ++i) {
+	pj_status_t status;
+
+	status = pjmedia_stream_info_from_sdp( &si->stream_info[i], pool,
+					       endpt, 
+					       (skinfo ? &skinfo[i] : NULL),
+					       local, remote, i);
+	if (status != PJ_SUCCESS)
+	    return status;
+
+    }
+
     return PJ_SUCCESS;
 }
@@ -349,8 +397,5 @@
  */
 PJ_DEF(pj_status_t) pjmedia_session_create( pjmedia_endpt *endpt, 
-					    unsigned stream_cnt,
-					    const pjmedia_sock_info skinfo[],
-					    const pjmedia_sdp_session *local_sdp,
-					    const pjmedia_sdp_session *rem_sdp,
+					    const pjmedia_session_info *si,
 					    void *user_data,
 					    pjmedia_session **p_session )
@@ -362,6 +407,5 @@
 
     /* Verify arguments. */
-    PJ_ASSERT_RETURN(endpt && stream_cnt && skinfo &&
-		     local_sdp && rem_sdp && p_session, PJ_EINVAL);
+    PJ_ASSERT_RETURN(endpt && si && p_session, PJ_EINVAL);
 
     /* Create pool for the session. */
@@ -374,33 +418,17 @@
     session->pool = pool;
     session->endpt = endpt;
-    session->stream_cnt = stream_cnt;
+    session->stream_cnt = si->stream_cnt;
     session->user_data = user_data;
-    
-    /* Stream count is the lower number of stream_cnt or SDP m= lines count */
-    if (stream_cnt < local_sdp->media_count)
-	stream_cnt = local_sdp->media_count;
-
-    /* 
-     * Create streams: 
-     */
-    for (i=0; i<(int)stream_cnt; ++i) {
-
-	pjmedia_stream_info *si = &session->stream_info[i];
-
-	/* Build stream info based on media line in local SDP */
-	status = pjmedia_stream_info_from_sdp(si, session->pool, endpt,
-					      local_sdp, rem_sdp, i);
-	if (status != PJ_SUCCESS)
-	    return status;
-
-	/* Assign sockinfo */
-	si->sock_info = skinfo[i];
-    }
+
+    /* Copy stream info (this simple memcpy may break sometime) */
+    pj_memcpy(session->stream_info, si->stream_info,
+	      si->stream_cnt * sizeof(pjmedia_session_info));
 
     /*
      * Now create and start the stream!
      */
-    for (i=0; i<(int)stream_cnt; ++i) {
-
+    for (i=0; i<(int)si->stream_cnt; ++i) {
+
+	/* Create the stream */
 	status = pjmedia_stream_create(endpt, session->pool,
 				       &session->stream_info[i],
Index: pjproject/trunk/pjmedia/src/pjmedia/stream.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia/stream.c	(revision 437)
+++ pjproject/trunk/pjmedia/src/pjmedia/stream.c	(revision 438)
@@ -54,6 +54,4 @@
     unsigned		    out_pkt_size;   /**< Size of output buffer.	    */
     void		   *out_pkt;	    /**< Output buffer.		    */
-    unsigned		    pcm_buf_size;   /**< Size of PCM buffer.	    */
-    void		   *pcm_buf;	    /**< PCM buffer.		    */
     pjmedia_rtp_session	    rtp;	    /**< RTP session.		    */
 };
@@ -86,5 +84,6 @@
 
     pjmedia_codec	    *codec;	    /**< Codec instance being used. */
-    pj_size_t		     frame_size;    /**< Size of encoded frame.	    */
+    pjmedia_codec_param	     codec_param;   /**< Codec param.		    */
+    unsigned		     frame_size;    /**< Size of encoded base frame.*/
     pj_mutex_t		    *jb_mutex;
     pjmedia_jbuf	    *jb;	    /**< Jitter buffer.		    */
@@ -155,7 +154,7 @@
     pjmedia_channel *channel = stream->dec;
     
-    char frame_type;
     pj_status_t status;
-    struct pjmedia_frame frame_in, frame_out;
+    unsigned samples_count, samples_per_frame, samples_required;
+    pj_int16_t *p_out_samp;
 
     /* Return no frame is channel is paused */
@@ -165,45 +164,105 @@
     }
 
-    /* Lock jitter buffer mutex */
+    /* Repeat get frame from the jitter buffer and decode the frame
+     * until we have enough frames according to codec's ptime.
+     */
+
+    /* Lock jitter buffer mutex first */
     pj_mutex_lock( stream->jb_mutex );
 
-    /* Get frame from jitter buffer. */
-    status = pjmedia_jbuf_get_frame(stream->jb, channel->out_pkt,
-				    &frame_type);
+    samples_required = stream->port.info.samples_per_frame;
+    samples_per_frame = stream->codec_param.info.frm_ptime *
+			stream->codec_param.info.clock_rate *
+			stream->codec_param.info.channel_cnt / 
+			1000;
+    p_out_samp = frame->buf;
+
+    for (samples_count=0; samples_count < samples_required; 
+	 samples_count += samples_per_frame) 
+    {
+	 char frame_type;
+
+	/* Get frame from jitter buffer. */
+	pjmedia_jbuf_get_frame(stream->jb, channel->out_pkt, &frame_type);
+	
+	if (frame_type == PJMEDIA_JB_MISSING_FRAME) {
+	    
+	    /* Activate PLC */
+	    if (stream->codec->op->recover && 
+		stream->codec_param.setting.plc) 
+	    {
+		pjmedia_frame frame_out;
+
+		frame_out.buf = p_out_samp + samples_count;
+		frame_out.size = frame->size - samples_count*2;
+		status = (*stream->codec->op->recover)(stream->codec,
+						       frame_out.size,
+						       &frame_out);
+	    } else {
+		status = -1;
+	    }
+
+	    if (status != PJ_SUCCESS) {
+		/* Either PLC failed or PLC not supported/enabled */
+		pjmedia_zero_samples(p_out_samp + samples_count,
+				     samples_required - samples_count);
+	    }
+	    
+	} else if (frame_type == PJMEDIA_JB_ZERO_EMPTY_FRAME) {
+
+	    /* Jitter buffer is empty, zero the remaining samples and break
+	     * the loop.
+	     */
+	    pjmedia_zero_samples(p_out_samp + samples_count,
+				 samples_required - samples_count);
+	    break;
+
+	} else if (frame_type != PJMEDIA_JB_NORMAL_FRAME) {
+
+	    /* It can only be PJMEDIA_JB_ZERO_PREFETCH frame */
+	    pj_assert(frame_type == PJMEDIA_JB_ZERO_PREFETCH_FRAME);
+
+	    /* Zero frame returned. We should zero the PCM buffer then.. */
+	    pjmedia_zero_samples(p_out_samp + samples_count, 
+				 samples_per_frame);
+
+	} else {
+	    /* Got "NORMAL" frame from jitter buffer */
+	    pjmedia_frame frame_in, frame_out;
+
+	    /* Decode */
+	    frame_in.buf = channel->out_pkt;
+	    frame_in.size = stream->frame_size;
+	    frame_in.type = PJMEDIA_FRAME_TYPE_AUDIO;  /* ignored */
+
+	    frame_out.buf = p_out_samp + samples_count;
+	    frame_out.size = frame->size - samples_count*2;
+	    status = stream->codec->op->decode( stream->codec, &frame_in,
+						frame_out.size, &frame_out);
+	    if (status != 0) {
+		LOGERR_((port->info.name.ptr, "codec decode() error", 
+			 status));
+
+		pjmedia_zero_samples(p_out_samp + samples_count, 
+				     samples_per_frame);
+	    }
+	}
+    }
+
 
     /* Unlock jitter buffer mutex. */
     pj_mutex_unlock( stream->jb_mutex );
 
-    if (status != PJ_SUCCESS || frame_type != PJMEDIA_JB_NORMAL_FRAME) {
+    /* Return PJMEDIA_FRAME_TYPE_NONE if we have no frames at all
+     * (it can happen when jitter buffer returns PJMEDIA_JB_ZERO_EMPTY_FRAME).
+     */
+    if (samples_count == 0) {
 	frame->type = PJMEDIA_FRAME_TYPE_NONE;
-	return PJ_SUCCESS;
-    }
-
-    /* Decode */
-    frame_in.buf = channel->out_pkt;
-    frame_in.size = stream->frame_size;
-    frame_in.type = PJMEDIA_FRAME_TYPE_AUDIO;  /* ignored */
-    frame_out.buf = channel->pcm_buf;
-    status = stream->codec->op->decode( stream->codec, &frame_in,
-					channel->pcm_buf_size, &frame_out);
-    if (status != 0) {
-	LOGERR_((port->info.name.ptr, "codec decode() error", status));
-
-	frame->type = PJMEDIA_FRAME_TYPE_NONE;
-	return PJ_SUCCESS;
-    }
-
-    /* Put in sound buffer. */
-    if (frame_out.size > frame->size) {
-	PJ_LOG(4,(port->info.name.ptr, 
-		  "Sound playout buffer truncated %d bytes", 
-		  frame_out.size - frame->size));
-	frame_out.size = frame->size;
-    }
-
-    frame->type = PJMEDIA_FRAME_TYPE_AUDIO;
-    frame->size = frame_out.size;
-    frame->timestamp.u64 = 0;
-    pj_memcpy(frame->buf, frame_out.buf, frame_out.size);
+	frame->size = 0;
+    } else {
+	frame->type = PJMEDIA_FRAME_TYPE_AUDIO;
+	frame->size = samples_count * 2;
+	frame->timestamp.u64 = 0;
+    }
 
     return PJ_SUCCESS;
@@ -319,5 +378,5 @@
     pj_status_t status = 0;
     struct pjmedia_frame frame_out;
-    int ts_len;
+    unsigned ts_len;
     pj_bool_t has_tx;
     void *rtphdr;
@@ -356,15 +415,35 @@
 
     } else if (frame->type != PJMEDIA_FRAME_TYPE_NONE) {
-	unsigned max_size;
+	unsigned ts, samples_per_frame;
 
 	has_tx = PJ_TRUE;
-	max_size = channel->out_pkt_size - sizeof(pjmedia_rtp_hdr);
-	status = stream->codec->op->encode( stream->codec, frame, 
-					    max_size, 
-					    &frame_out);
-	if (status != 0) {
-	    LOGERR_((stream->port.info.name.ptr, 
-		    "Codec encode() error", status));
-	    return status;
+
+	/* Repeatedly call encode if there are multiple frames to be
+	 * sent.
+	 */
+	samples_per_frame = stream->codec_param.info.frm_ptime *
+			    stream->codec_param.info.clock_rate *
+			    stream->codec_param.info.channel_cnt /
+			    1000;
+
+	for (ts=0; ts<ts_len; ts += samples_per_frame) {
+	    pjmedia_frame tmp_frame;
+	    unsigned max_size;
+
+	    tmp_frame.buf = ((char*)frame_out.buf) + frame_out.size;
+
+	    max_size = channel->out_pkt_size - sizeof(pjmedia_rtp_hdr) -
+		       frame_out.size;
+
+	    status = stream->codec->op->encode( stream->codec, frame, 
+						max_size, 
+						&tmp_frame);
+	    if (status != PJ_SUCCESS) {
+		LOGERR_((stream->port.info.name.ptr, 
+			"Codec encode() error", status));
+		return status;
+	    }
+
+	    frame_out.size += tmp_frame.size;
 	}
 
@@ -626,8 +705,41 @@
 
 	} else {
-	    unsigned ext_seq;
-	    ext_seq = channel->rtp.seq_ctrl.cycles | pj_ntohs(hdr->seq);
-	    status = pjmedia_jbuf_put_frame(stream->jb, payload, payloadlen,
-					    ext_seq);
+	    /*
+	     * Packets may contain more than one frames, while the jitter
+	     * buffer can only take one frame per "put" operation. So we need
+	     * to ask the codec to "parse" the payload into multiple frames.
+	     */
+	    enum { MAX = 16 };
+	    pj_timestamp ts;
+	    unsigned i, count;
+	    pjmedia_frame frames[MAX];
+
+	    /* Get the timestamp of the first sample */
+	    ts.u64 = pj_ntohl(hdr->ts);
+
+	    /* Parse the payload. */
+	    status = (*stream->codec->op->parse)(stream->codec,
+						 (void*)payload,
+						 payloadlen,
+						 &ts,
+						 &count,
+						 frames);
+	    if (status != PJ_SUCCESS) {
+		LOGERR_((stream->port.info.name.ptr, 
+			 "Codec parse() error", 
+			 status));
+		count = 0;
+	    }
+
+	    /* Put each frame to jitter buffer. */
+	    for (i=0; i<count; ++i) {
+		unsigned ext_seq;
+
+		ext_seq = (unsigned)(frames[i].timestamp.u64 /
+				     stream->port.info.samples_per_frame);
+		pjmedia_jbuf_put_frame(stream->jb, frames[i].buf, 
+				       frames[i].size, ext_seq);
+
+	    }
 	}
 	pj_mutex_unlock( stream->jb_mutex );
@@ -728,5 +840,4 @@
 				   unsigned pt,
 				   const pjmedia_stream_info *param,
-				   const pjmedia_codec_param *codec_param,
 				   pjmedia_channel **p_channel)
 {
@@ -756,5 +867,5 @@
 
     channel->out_pkt_size = sizeof(pjmedia_rtp_hdr) + 
-			    codec_param->avg_bps/8 * 
+			    stream->codec_param.info.avg_bps/8 * 
 			    PJMEDIA_MAX_FRAME_DURATION_MS / 
 			    1000;
@@ -766,13 +877,4 @@
     PJ_ASSERT_RETURN(channel->out_pkt != NULL, PJ_ENOMEM);
 
-
-    /* Allocate buffer for decoding to PCM: */
-
-    channel->pcm_buf_size = codec_param->clock_rate * 
-			    codec_param->channel_cnt *
-			    codec_param->pcm_bits_per_sample / 8 *
-			    PJMEDIA_MAX_FRAME_DURATION_MS / 1000;
-    channel->pcm_buf = pj_pool_alloc (pool, channel->pcm_buf_size);
-    PJ_ASSERT_RETURN(channel->pcm_buf != NULL, PJ_ENOMEM);
 
 
@@ -800,8 +902,7 @@
 {
     pjmedia_stream *stream;
-    pjmedia_codec_param codec_param;
     pj_ioqueue_callback ioqueue_cb;
     pj_uint16_t rtcp_port;
-    unsigned jbuf_init, jbuf_max;
+    unsigned jb_init, jb_max, jb_min_pre, jb_max_pre;
     pj_status_t status;
 
@@ -867,29 +968,42 @@
 
 
-    /* Get default codec param: */
-
-    //status = stream->codec->op->default_attr(stream->codec, &codec_param);
-    status = pjmedia_codec_mgr_get_default_param( stream->codec_mgr, 
-						  &info->fmt, &codec_param);
+    /* Get codec param: */
+    if (info->param)
+	stream->codec_param = *info->param;
+    else {
+	status = pjmedia_codec_mgr_get_default_param(stream->codec_mgr, 
+						     &info->fmt, 
+						     &stream->codec_param);
+	if (status != PJ_SUCCESS)
+	    goto err_cleanup;
+    }
+
+    /* Check for invalid frame per packet. */
+    if (stream->codec_param.setting.frm_per_pkt < 1)
+	stream->codec_param.setting.frm_per_pkt = 1;
+
+    /* Set additional info. */
+    stream->port.info.bits_per_sample = 16;
+    stream->port.info.samples_per_frame = info->fmt.clock_rate * 
+					  stream->codec_param.info.frm_ptime *
+					  stream->codec_param.setting.frm_per_pkt /
+					  1000;
+    stream->port.info.bytes_per_frame = stream->codec_param.info.avg_bps/8 * 
+					stream->codec_param.info.frm_ptime *
+					stream->codec_param.setting.frm_per_pkt /
+					1000;
+
+
+    /* Open the codec: */
+
+    status = stream->codec->op->open(stream->codec, &stream->codec_param);
     if (status != PJ_SUCCESS)
 	goto err_cleanup;
 
-    /* Set additional info. */
-    stream->port.info.bits_per_sample = 16;
-    stream->port.info.samples_per_frame = info->fmt.clock_rate*codec_param.ptime/1000;
-    stream->port.info.bytes_per_frame = codec_param.avg_bps/8 * codec_param.ptime/1000;
-
-
-    /* Open the codec: */
-
-    status = stream->codec->op->open(stream->codec, &codec_param);
-    if (status != PJ_SUCCESS)
-	goto err_cleanup;
-
 
     /* Get the frame size: */
 
-    stream->frame_size = (codec_param.avg_bps / 8) * codec_param.ptime / 1000;
-
+    stream->frame_size = (stream->codec_param.info.avg_bps / 8) * 
+			  stream->codec_param.info.frm_ptime / 1000;
 
     /* Init RTCP session: */
@@ -901,29 +1015,42 @@
 
 
-    /* Create jitter buffer: */
-    if (info->jb_init)
-	jbuf_init = info->jb_init;
+    /* Init jitter buffer parameters: */
+    if (info->jb_max > 0)
+	jb_max = info->jb_max;
     else
-	jbuf_init = 60 / (stream->port.info.samples_per_frame * 1000 / 
-			  info->fmt.clock_rate);
-
-    if (info->jb_max)
-	jbuf_max = info->jb_max;
+	jb_max = 240 / (stream->port.info.samples_per_frame * 1000 / 
+			   info->fmt.clock_rate);
+
+    if (info->jb_min_pre >= 0)
+	jb_min_pre = info->jb_min_pre;
     else
-	jbuf_max = 240 / (stream->port.info.samples_per_frame * 1000 / 
-			   info->fmt.clock_rate);
+	jb_min_pre = 0;
+
+    if (info->jb_max_pre > 0)
+	jb_max_pre = info->jb_max_pre;
+    else
+	jb_max_pre = jb_max * 4 / 5;
+
+    if (info->jb_init >= 0)
+	jb_init = info->jb_init;
+    else
+	jb_init = jb_min_pre;
+
+
+    /* Create jitter buffer */
     status = pjmedia_jbuf_create(pool, &stream->port.info.name,
 				 stream->frame_size, 
-				 jbuf_max, &stream->jb);
+				 jb_max, &stream->jb);
     if (status != PJ_SUCCESS)
 	goto err_cleanup;
 
-    /* Set jitter buffer to adaptive */
-    pjmedia_jbuf_set_adaptive( stream->jb, jbuf_init, 1, jbuf_max * 4 / 5);
+
+    /* Set up jitter buffer */
+    pjmedia_jbuf_set_adaptive( stream->jb, jb_init, jb_min_pre, jb_max_pre);
 
     /* Create decoder channel: */
 
     status = create_channel( pool, stream, PJMEDIA_DIR_DECODING, 
-			     info->fmt.pt, info, &codec_param, &stream->dec);
+			     info->fmt.pt, info, &stream->dec);
     if (status != PJ_SUCCESS)
 	goto err_cleanup;
@@ -933,5 +1060,5 @@
 
     status = create_channel( pool, stream, PJMEDIA_DIR_ENCODING, 
-			     info->tx_pt, info, &codec_param, &stream->enc);
+			     info->tx_pt, info, &stream->enc);
     if (status != PJ_SUCCESS)
 	goto err_cleanup;
Index: pjproject/trunk/pjsip-apps/build/Samples.mak
===================================================================
--- pjproject/trunk/pjsip-apps/build/Samples.mak	(revision 437)
+++ pjproject/trunk/pjsip-apps/build/Samples.mak	(revision 438)
@@ -2,12 +2,12 @@
 include ../../build/common.mak
 
-PJLIB_LIB:=../../pjlib/lib/libpj-$(MACHINE_NAME)-$(OS_NAME)-$(CC_NAME)$(LIBEXT)
-PJLIB_UTIL_LIB:=../../pjlib-util/lib/libpjlib-util-$(MACHINE_NAME)-$(OS_NAME)-$(CC_NAME)$(LIBEXT)
-PJMEDIA_LIB:=../../pjmedia/lib/libpjmedia-$(MACHINE_NAME)-$(OS_NAME)-$(CC_NAME)$(LIBEXT)
-PJMEDIA_CODEC_LIB:=../../pjmedia/lib/libpjmedia-codec-$(MACHINE_NAME)-$(OS_NAME)-$(CC_NAME)$(LIBEXT)
-PJSIP_LIB:=../../pjsip/lib/libpjsip-$(MACHINE_NAME)-$(OS_NAME)-$(CC_NAME)$(LIBEXT)
-PJSIP_UA_LIB:=../../pjsip/lib/libpjsip-ua-$(MACHINE_NAME)-$(OS_NAME)-$(CC_NAME)$(LIBEXT)
-PJSIP_SIMPLE_LIB:=../../pjsip/lib/libpjsip-simple-$(MACHINE_NAME)-$(OS_NAME)-$(CC_NAME)$(LIBEXT)
-PJSUA_LIB_LIB=../../pjsip/lib/libpjsua-$(MACHINE_NAME)-$(OS_NAME)-$(CC_NAME)$(LIBEXT)
+PJLIB_LIB:=../../pjlib/lib/libpj-$(TARGET)$(LIBEXT)
+PJLIB_UTIL_LIB:=../../pjlib-util/lib/libpjlib-util-$(TARGET)$(LIBEXT)
+PJMEDIA_LIB:=../../pjmedia/lib/libpjmedia-$(TARGET)$(LIBEXT)
+PJMEDIA_CODEC_LIB:=../../pjmedia/lib/libpjmedia-codec-$(TARGET)$(LIBEXT)
+PJSIP_LIB:=../../pjsip/lib/libpjsip-$(TARGET)$(LIBEXT)
+PJSIP_UA_LIB:=../../pjsip/lib/libpjsip-ua-$(TARGET)$(LIBEXT)
+PJSIP_SIMPLE_LIB:=../../pjsip/lib/libpjsip-simple-$(TARGET)$(LIBEXT)
+PJSUA_LIB_LIB=../../pjsip/lib/libpjsua-$(TARGET)$(LIBEXT)
 
 
@@ -36,5 +36,5 @@
 
 SRCDIR := ../src/samples
-OBJDIR := ./output/samples-$(MACHINE_NAME)-$(OS_NAME)-$(CC_NAME)
+OBJDIR := ./output/samples-$(TARGET)
 BINDIR := ../bin/samples
 
@@ -42,9 +42,9 @@
 	   siprtp streamutil
 
-EXES := $(foreach file, $(SAMPLES), $(BINDIR)/$(file)-$(MACHINE_NAME)-$(OS_NAME)-$(CC_NAME)$(HOST_EXE))
+EXES := $(foreach file, $(SAMPLES), $(BINDIR)/$(file)-$(TARGET)$(HOST_EXE))
 
 all: $(OBJDIR) $(EXES)
 
-$(BINDIR)/%-$(MACHINE_NAME)-$(OS_NAME)-$(CC_NAME)$(HOST_EXE): $(OBJDIR)/%$(OBJEXT) $(LIBS)
+$(BINDIR)/%-$(TARGET)$(HOST_EXE): $(OBJDIR)/%$(OBJEXT) $(LIBS)
 	$(LD) $(LDOUT)$(subst /,$(HOST_PSEP),$@) \
 	    $(subst /,$(HOST_PSEP),$<) \
Index: pjproject/trunk/pjsip-apps/src/samples/debug.c
===================================================================
--- pjproject/trunk/pjsip-apps/src/samples/debug.c	(revision 437)
+++ pjproject/trunk/pjsip-apps/src/samples/debug.c	(revision 438)
@@ -28,4 +28,4 @@
  *  #include "playfile.c"
  */
-#include "streamutil.c"
+#include "sndinfo.c"
 
Index: pjproject/trunk/pjsip-apps/src/samples/playfile.c
===================================================================
--- pjproject/trunk/pjsip-apps/src/samples/playfile.c	(revision 437)
+++ pjproject/trunk/pjsip-apps/src/samples/playfile.c	(revision 438)
@@ -77,5 +77,9 @@
 
 
-    PJ_UNUSED_ARG(argc);
+    if (argc != 2) {
+    	puts("Error: filename required");
+	puts(desc);
+	return 1;
+    }
 
 
Index: pjproject/trunk/pjsip-apps/src/samples/simpleua.c
===================================================================
--- pjproject/trunk/pjsip-apps/src/samples/simpleua.c	(revision 437)
+++ pjproject/trunk/pjsip-apps/src/samples/simpleua.c	(revision 438)
@@ -586,4 +586,5 @@
 				  pj_status_t status)
 {
+    pjmedia_session_info sess_info;
     const pjmedia_sdp_session *local_sdp;
     const pjmedia_sdp_session *remote_sdp;
@@ -608,11 +609,25 @@
 
 
+    /* Create session info based on the two SDPs. 
+     * We only support one stream per session for now.
+     */
+    status = pjmedia_session_info_from_sdp(inv->dlg->pool, g_med_endpt, 1,
+					   &sess_info, &g_med_skinfo,
+					   local_sdp, remote_sdp);
+    if (status != PJ_SUCCESS) {
+	app_perror( THIS_FILE, "Unable to create media session", status);
+	return;
+    }
+
+    /* If required, we can also change some settings in the session info,
+     * (such as jitter buffer settings, codec settings, etc) before we
+     * create the session.
+     */
+
     /* Create new media session, passing the two SDPs, and also the
      * media socket that we created earlier.
      * The media session is active immediately.
      */
-    status = pjmedia_session_create( g_med_endpt, 1, 
-				     &g_med_skinfo,
-				     local_sdp, remote_sdp, 
+    status = pjmedia_session_create( g_med_endpt, &sess_info,
 				     NULL, &g_med_session );
     if (status != PJ_SUCCESS) {
Index: pjproject/trunk/pjsip-apps/src/samples/siprtp.c
===================================================================
--- pjproject/trunk/pjsip-apps/src/samples/siprtp.c	(revision 437)
+++ pjproject/trunk/pjsip-apps/src/samples/siprtp.c	(revision 438)
@@ -1169,5 +1169,5 @@
 					     strm->bytes_per_frame, 
 					     strm->samples_per_frame,
-					     &hdr, &hdrlen);
+					     (const void**)&hdr, &hdrlen);
 	    if (status == PJ_SUCCESS) {
 
@@ -1267,5 +1267,5 @@
 
     status = pjmedia_stream_info_from_sdp(&audio->si, inv->pool, app.med_endpt,
-					  local_sdp, remote_sdp, 0);
+					  NULL, local_sdp, remote_sdp, 0);
     if (status != PJ_SUCCESS) {
 	app_perror(THIS_FILE, "Error creating stream info from SDP", status);
Index: pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h
===================================================================
--- pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h	(revision 437)
+++ pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h	(revision 438)
@@ -196,4 +196,5 @@
     int		     complexity;    /**< Codec complexity.		*/
     int		     quality;	    /**< Codec quality.			*/
+    int		     ptime;	    /**< Codec ptime in msec.		*/
 
 
Index: pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c	(revision 437)
+++ pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c	(revision 438)
@@ -27,5 +27,5 @@
  */
 
-#define THIS_FILE   "pjsua_inv.c"
+#define THIS_FILE   "pjsua_call.c"
 
 
@@ -154,8 +154,8 @@
 	call->session = NULL;
 
-    }
-
-    PJ_LOG(3,(THIS_FILE, "Media session for call %d is destroyed", 
-			 call_index));
+	PJ_LOG(3,(THIS_FILE, "Media session for call %d is destroyed", 
+			     call_index));
+
+    }
 
     return PJ_SUCCESS;
@@ -524,4 +524,9 @@
 	    pj_gettimeofday(&call->dis_time);
 	    break;
+	default:
+	    /* Nothing to do. Just to keep gcc from complaining about
+	     * unused enums.
+	     */ 
+	    break;
     }
 
@@ -557,4 +562,10 @@
 	    st_code = e->body.tsx_state.tsx->status_code;
 	    ev_state = PJSIP_EVSUB_STATE_TERMINATED;
+	    break;
+
+	default:
+	    /* Nothing to do. Just to keep gcc from complaining about
+	     * unused enums.
+	     */
 	    break;
 	}
@@ -916,4 +927,5 @@
 }
 
+#if 0
 /* Disconnect call */
 static void call_disconnect(pjsip_inv_session *inv,
@@ -931,4 +943,5 @@
     }
 }
+#endif
 
 /*
@@ -941,4 +954,5 @@
 {
     pjsua_call *call;
+    pjmedia_session_info sess_info;
     const pjmedia_sdp_session *local_sdp;
     const pjmedia_sdp_session *remote_sdp;
@@ -991,15 +1005,36 @@
     }
 
-    /* Create new media session. 
-     * The media session is active immediately.
-     */
     if (pjsua.null_audio)
 	return;
-    
-    status = pjmedia_session_create( pjsua.med_endpt, 1, 
-				     &call->skinfo,
-				     local_sdp, remote_sdp, 
-				     call,
-				     &call->session );
+
+    /* Create media session info based on SDP parameters. 
+     * We only support one stream per session at the moment
+     */    
+    status = pjmedia_session_info_from_sdp( call->inv->dlg->pool, 
+					    pjsua.med_endpt, 1,
+					    &sess_info, &call->skinfo,
+					    local_sdp, remote_sdp);
+    if (status != PJ_SUCCESS) {
+	pjsua_perror(THIS_FILE, "Unable to create media session", 
+		     status);
+	//call_disconnect(inv, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE);
+	return;
+    }
+
+    /* Override ptime, if this option is specified. */
+    if (pjsua.ptime) {
+	sess_info.stream_info[0].param->setting.frm_per_pkt = (pj_uint8_t)
+	    (pjsua.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;
+    }
+
+    /* Optionally, application may modify other stream settings here
+     * (such as jitter buffer parameters, codec ptime, etc.)
+     */
+
+    /* Create session based on session info. */
+    status = pjmedia_session_create( pjsua.med_endpt, &sess_info,
+				     call, &call->session );
     if (status != PJ_SUCCESS) {
 	pjsua_perror(THIS_FILE, "Unable to create media session", 
Index: pjproject/trunk/pjsip/src/pjsua-lib/pjsua_settings.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsua-lib/pjsua_settings.c	(revision 437)
+++ pjproject/trunk/pjsip/src/pjsua-lib/pjsua_settings.c	(revision 438)
@@ -95,4 +95,5 @@
     puts  ("  --complexity=N      Specify encoding complexity (0-10, default=none(-1))");
     puts  ("  --quality=N         Specify encoding quality (0-10, default=4)");
+    puts  ("  --ptime=MSEC        Override codec ptime to MSEC (default=specific)");
     puts  ("");
     puts  ("Buddy List (can be more than one):");
@@ -228,5 +229,5 @@
 	   OPT_AUTO_CONF, OPT_CLOCK_RATE,
 	   OPT_PLAY_FILE, OPT_RTP_PORT, OPT_ADD_CODEC,
-	   OPT_COMPLEXITY, OPT_QUALITY,
+	   OPT_COMPLEXITY, OPT_QUALITY, OPT_PTIME,
 	   OPT_NEXT_ACCOUNT, OPT_NEXT_CRED, OPT_MAX_CALLS, OPT_UAS_REFRESH,
 	   OPT_UAS_DURATION,
@@ -267,4 +268,5 @@
 	{ "complexity",	1, 0, OPT_COMPLEXITY},
 	{ "quality",	1, 0, OPT_QUALITY},
+	{ "ptime",      1, 0, OPT_PTIME},
 	{ "next-account",0,0, OPT_NEXT_ACCOUNT},
 	{ "next-cred",	0, 0, OPT_NEXT_CRED},
@@ -556,4 +558,13 @@
 		PJ_LOG(1,(THIS_FILE,
 			  "Error: invalid --quality (expecting 0-10"));
+		return -1;
+	    }
+	    break;
+
+	case OPT_PTIME:
+	    pjsua.ptime = my_atoi(pj_optarg);
+	    if (pjsua.ptime < 10 || pjsua.ptime > 1000) {
+		PJ_LOG(1,(THIS_FILE,
+			  "Error: invalid --ptime option"));
 		return -1;
 	    }
@@ -772,5 +783,5 @@
 
 	PJ_LOG(3,(THIS_FILE,
-	       "                  TX pt=%d, stat last update: %s\n"
+	       "                  TX pt=%d, ptime=%dms, stat last update: %s\n"
 	       "                     total %spkt %sB (%sB +IP hdr)%s\n"
 	       "                     pkt loss=%d (%3.1f%%), dup=%d (%3.1f%%), reorder=%d (%3.1f%%)%s\n"
@@ -779,4 +790,6 @@
 	       "                     jitter     : %7.3f %7.3f %7.3f %7.3f%s",
 	       info.stream_info[i].tx_pt,
+	       info.stream_info[i].param->info.frm_ptime *
+		info.stream_info[i].param->setting.frm_per_pkt,
 	       last_update,
 	       good_number(packets, stat.tx.pkt),
@@ -970,4 +983,6 @@
     char line[128];
 
+    PJ_UNUSED_ARG(max);
+
     cfg.ptr = buf;
     cfg.slen = 0;
@@ -1097,4 +1112,11 @@
     pj_strcat2(&cfg, line);
 
+    /* ptime */
+    if (pjsua.ptime) {
+	pj_ansi_sprintf(line, "--ptime %d\n",
+			pjsua.ptime);
+	pj_strcat2(&cfg, line);
+    }
+
     /* Start RTP port. */
     pj_ansi_sprintf(line, "--rtp-port %d\n",
