Index: pjproject/trunk/pjmedia/include/pjmedia/jbuf.h
===================================================================
--- pjproject/trunk/pjmedia/include/pjmedia/jbuf.h	(revision 434)
+++ pjproject/trunk/pjmedia/include/pjmedia/jbuf.h	(revision 435)
@@ -46,8 +46,30 @@
 enum pjmedia_jb_frame_type 
 {
-    PJMEDIA_JB_MISSING_FRAME   = 0, /**< No frame because it's missing.	    */
-    PJMEDIA_JB_NORMAL_FRAME    = 1, /**< Normal frame is being returned.    */
-    PJMEDIA_JB_ZERO_FRAME      = 2, /**< Zero frame is being returned.	    */
+    PJMEDIA_JB_MISSING_FRAME	   = 0, /**< No frame because it's missing  */
+    PJMEDIA_JB_NORMAL_FRAME	   = 1, /**< Normal frame is being returned */
+    PJMEDIA_JB_ZERO_PREFETCH_FRAME = 2, /**< Zero frame is being returned  
+					     because JB is bufferring.	    */
+    PJMEDIA_JB_ZERO_EMPTY_FRAME	   = 3	/**< Zero frame is being returned
+					     because JB is empty.	    */
 };
+
+
+/**
+ * This structure describes jitter buffer current status.
+ */
+struct pjmedia_jb_state
+{
+    unsigned	frame_size;	    /**< Individual frame size, in bytes.   */
+    unsigned	prefetch;	    /**< Current prefetch value, in frames  */
+    unsigned	min_prefetch;	    /**< Minimum allowed prefetch, in frms. */
+    unsigned	max_prefetch;	    /**< Maximum allowed prefetch, in frms. */
+    unsigned	size;		    /**< Current buffer size, in frames.    */
+};
+
+
+/**
+ * @see pjmedia_jb_state
+ */
+typedef struct pjmedia_jb_state pjmedia_jb_state;
 
 
@@ -60,6 +82,10 @@
 
 /**
- * Create the jitter buffer. This function may allocate large chunk of
- * memory to keep the frames in the buffer.
+ * Create an adaptive jitter buffer according to the specification. If
+ * application wants to have a fixed jitter buffer, it may call
+ * #pjmedia_jbuf_set_fixed() after the jitter buffer is created.
+ *
+ * This function may allocate large chunk of memory to keep the frames in 
+ * the buffer.
  *
  * @param pool		The pool to allocate memory.
@@ -67,9 +93,12 @@
  *			purpose.
  * @param frame_size	The size of each frame that will be kept in the
- *			jitter buffer. The value here normaly corresponds
- *			to the RTP payload size according to the codec
- *			being used.
- * @param init_delay	Initial jitter buffer delay, in number of frames.
- * @param max_count	Maximum jitter buffer delay, in number of frames.
+ *			jitter buffer, in bytes. This should correspond
+ *			to the minimum frame size supported by the codec.
+ *			For example, a 10ms frame (80 bytes) would be 
+ *			recommended for G.711 codec.
+ * @param max_count	Maximum number of frames that can be kept in the
+ *			jitter buffer. This effectively means the maximum
+ *			delay that may be introduced by this jitter 
+ *			buffer.
  * @param p_jb		Pointer to receive jitter buffer instance.
  *
@@ -78,8 +107,41 @@
 PJ_DECL(pj_status_t) pjmedia_jbuf_create(pj_pool_t *pool,
 					 const pj_str_t *name,
-					 int frame_size, 
-					 int init_delay, 
-					 int max_count,
+					 unsigned frame_size,
+					 unsigned max_count,
 					 pjmedia_jbuf **p_jb);
+
+/**
+ * Set the jitter buffer to fixed delay mode. The default behavior
+ * is to adapt the delay with actual packet delay.
+ *
+ * @param jb		The jitter buffer
+ * @param prefetch	The fixed delay value, in number of frames.
+ *
+ * @return		PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_jbuf_set_fixed( pjmedia_jbuf *jb,
+					     unsigned prefetch);
+
+
+/**
+ * Set the jitter buffer to adaptive mode.
+ *
+ * @param jb		The jitter buffer.
+ * @param prefetch	The prefetch value to be applied to the jitter
+ *			buffer.
+ * @param min_prefetch	The minimum delay that must be applied to each
+ *			incoming packets, in number of frames. The
+ *			default value is zero.
+ * @param max_prefetch	The maximum allowable value for prefetch delay,
+ *			in number of frames. The default value is equal
+ *			to the size of the jitter buffer.
+ *
+ * @return		PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_jbuf_set_adaptive( pjmedia_jbuf *jb,
+					        unsigned prefetch,
+					        unsigned min_prefetch,
+						unsigned max_prefetch);
+
 
 /**
@@ -156,26 +218,15 @@
 					     char *p_frm_type);
 
-/**
- * Retrieve the current value of jitter buffer minimum delay, in number
- * of frames.
- *
- * @param jb		The jitter buffer.
- *
- * @return		Number of frames, indicating the minimum delay that 
- *			will be applied by the jitter buffer between frame
- *			arrival and frame retrieval.
- */
-PJ_DECL(unsigned)    pjmedia_jbuf_get_min_delay_size(pjmedia_jbuf *jb);
-
-
-/**
- * Retrieve the current delay value, in number of frames.
- *
- * @param jb		The jitter buffer.
- *
- * @return		Number of frames, indicating the delay between frame
- *			arrival and frame retrieval.
- */
-PJ_DECL(unsigned)    pjmedia_jbuf_get_delay(pjmedia_jbuf *jb);
+
+/**
+ * Get jitter buffer state.
+ *
+ * @param jb		The jitter buffer.
+ * @param state		Buffer to receive jitter buffer state.
+ *
+ * @return		PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_jbuf_get_state( pjmedia_jbuf *jb,
+					     pjmedia_jb_state *state );
 
 
Index: pjproject/trunk/pjmedia/src/pjmedia/jbuf.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia/jbuf.c	(revision 434)
+++ pjproject/trunk/pjmedia/src/pjmedia/jbuf.c	(revision 435)
@@ -65,4 +65,6 @@
 					  // (at the beginning of the framelist->flist_buffer operation)
     int		    jb_prefetch_cnt;	  // prefetch counter
+    int		    jb_min_prefetch;	  // Minimum allowable prefetch
+    int		    jb_max_prefetch;	  // Maximum allowable prefetch
     int		    jb_status;		  // status is 'init' until the	first 'put' operation
 
@@ -138,5 +140,6 @@
 		    framelist->flist_head * framelist->flist_frame_size,
 		  0, framelist->flist_frame_size);
-	framelist->flist_frame_type[framelist->flist_head] = 0;
+	framelist->flist_frame_type[framelist->flist_head] = 
+	    PJMEDIA_JB_MISSING_FRAME;
 
 	framelist->flist_origin++;
@@ -182,5 +185,5 @@
 	          step1*framelist->flist_frame_size);
 	pj_memset(framelist->flist_frame_type+framelist->flist_head,
-		  0,
+		  PJMEDIA_JB_MISSING_FRAME,
 		  step1*sizeof(framelist->flist_frame_type[0]));
 
@@ -190,5 +193,5 @@
 		      step2*framelist->flist_frame_size);
 	    pj_memset(framelist->flist_frame_type,
-		      0,
+		      PJMEDIA_JB_MISSING_FRAME,
 		      step2*sizeof(framelist->flist_frame_type[0]));
 	}
@@ -264,7 +267,6 @@
 PJ_DEF(pj_status_t) pjmedia_jbuf_create(pj_pool_t *pool, 
 					const pj_str_t *name,
-					int frame_size, 
-					int initial_prefetch, 
-					int max_count,
+					unsigned frame_size, 
+					unsigned max_count,
 					pjmedia_jbuf **p_jb)
 {
@@ -285,6 +287,8 @@
     jb->jb_last_jitter	 = 0;
     jb->jb_last_op	 = JB_OP_INIT;
-    jb->jb_prefetch	 = PJ_MIN(initial_prefetch, max_count*4/5);
+    jb->jb_prefetch	 = PJ_MIN(PJMEDIA_JB_DEFAULT_INIT_DELAY,max_count*4/5);
     jb->jb_prefetch_cnt	 = 0;
+    jb->jb_min_prefetch  = 0;
+    jb->jb_max_prefetch  = max_count*4/5;
     jb->jb_stable_hist	 = 0;
     jb->jb_status	 = JB_STATUS_INITIALIZING;
@@ -293,4 +297,45 @@
 
     *p_jb = jb;
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Set the jitter buffer to fixed delay mode. The default behavior
+ * is to adapt the delay with actual packet delay.
+ *
+ */
+PJ_DEF(pj_status_t) pjmedia_jbuf_set_fixed( pjmedia_jbuf *jb,
+					    unsigned prefetch)
+{
+    PJ_ASSERT_RETURN(jb, PJ_EINVAL);
+    PJ_ASSERT_RETURN(prefetch <= jb->jb_max_count, PJ_EINVAL);
+
+    jb->jb_min_prefetch = jb->jb_max_prefetch = 
+	jb->jb_prefetch = prefetch;
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Set the jitter buffer to adaptive mode.
+ */
+PJ_DEF(pj_status_t) pjmedia_jbuf_set_adaptive( pjmedia_jbuf *jb,
+					       unsigned prefetch,
+					       unsigned min_prefetch,
+					       unsigned max_prefetch)
+{
+    PJ_ASSERT_RETURN(jb, PJ_EINVAL);
+    PJ_ASSERT_RETURN(min_prefetch < max_prefetch &&
+		     prefetch >= min_prefetch &&
+		     prefetch <= max_prefetch &&
+		     max_prefetch <= jb->jb_max_count,
+		     PJ_EINVAL);
+
+    jb->jb_prefetch = prefetch;
+    jb->jb_min_prefetch = min_prefetch;
+    jb->jb_max_prefetch = max_prefetch;
+
     return PJ_SUCCESS;
 }
@@ -337,5 +382,6 @@
 
 	    jb->jb_prefetch -= seq_diff;
-	    if (jb->jb_prefetch < 1) jb->jb_prefetch = 1;
+	    if (jb->jb_prefetch < jb->jb_min_prefetch) 
+		jb->jb_prefetch = jb->jb_min_prefetch;
 
 	    jb->jb_stable_hist = 0;
@@ -358,4 +404,6 @@
 	jb->jb_prefetch = PJ_MIN(jb->jb_last_jitter,
 				 (int)(jb->jb_max_count*4/5));
+	if (jb->jb_prefetch > jb->jb_max_prefetch)
+	    jb->jb_prefetch = jb->jb_max_prefetch;
 	jb->jb_stable_hist = 0;
 	jb->jb_max_hist_jitter = 0;
@@ -432,4 +480,7 @@
 }
 
+/*
+ * Get frame from jitter buffer.
+ */
 PJ_DEF(pj_status_t) pjmedia_jbuf_get_frame( pjmedia_jbuf *jb, 
 					    void *frame, 
@@ -446,12 +497,29 @@
     }
 
-    if ((jb->jb_prefetch_cnt < jb->jb_prefetch) || 
-	jb_framelist_get(&jb->jb_framelist,frame,&ftype) == PJ_FALSE) 
-    {
+    if ((jb->jb_prefetch_cnt < jb->jb_prefetch)) {
+	/* Can't return frame because jitter buffer is filling up
+	 * minimum prefetch.
+	 */
 	pj_memset(frame, 0, jb->jb_frame_size);
-	*p_frame_type = PJMEDIA_JB_ZERO_FRAME;
+	if (jb_framelist_size(&jb->jb_framelist) == 0)
+	    *p_frame_type = PJMEDIA_JB_ZERO_EMPTY_FRAME;
+	else
+	    *p_frame_type = PJMEDIA_JB_ZERO_PREFETCH_FRAME;
+
 	return PJ_SUCCESS;
     }
 
+    /* Retrieve a frame from frame list */
+    if (jb_framelist_get(&jb->jb_framelist,frame,&ftype) == PJ_FALSE) {
+	/* Can't return frame because jitter buffer is empty! */
+	pj_memset(frame, 0, jb->jb_frame_size);
+	*p_frame_type = PJMEDIA_JB_ZERO_EMPTY_FRAME;
+
+	return PJ_SUCCESS;
+    }
+
+    /* We've successfully retrieved a frame from the frame list, but
+     * the frame could be a blank frame!
+     */
     if (ftype == PJMEDIA_JB_NORMAL_FRAME) {
 	*p_frame_type	= PJMEDIA_JB_NORMAL_FRAME;
@@ -463,13 +531,19 @@
 }
 
-PJ_DEF(unsigned) pjmedia_jbuf_get_min_delay_size(pjmedia_jbuf *jb)
-{
-    return jb->jb_prefetch;
-}
-
-PJ_DEF(unsigned) pjmedia_jbuf_get_delay(pjmedia_jbuf *jb)
-{
-    return jb_framelist_size(&jb->jb_framelist);
-}
-
-
+/*
+ * Get jitter buffer state.
+ */
+PJ_DEF(pj_status_t) pjmedia_jbuf_get_state( pjmedia_jbuf *jb,
+					    pjmedia_jb_state *state )
+{
+    PJ_ASSERT_RETURN(jb && state, PJ_EINVAL);
+
+    state->frame_size = jb->jb_frame_size;
+    state->prefetch = jb->jb_prefetch;
+    state->min_prefetch = jb->jb_min_prefetch;
+    state->max_prefetch = jb->jb_max_prefetch;
+    state->size = jb_framelist_size(&jb->jb_framelist);
+
+    return PJ_SUCCESS;
+}
+
Index: pjproject/trunk/pjmedia/src/pjmedia/session.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia/session.c	(revision 434)
+++ pjproject/trunk/pjmedia/src/pjmedia/session.c	(revision 435)
@@ -303,6 +303,6 @@
   
 
-    /* Get local DTMF payload type */
-    si->tx_event_pt = -1;
+    /* Get incomming payload type for telephone-events */
+    si->rx_event_pt = -1;
     for (i=0; i<local_m->attr_count; ++i) {
 	pjmedia_sdp_rtpmap r;
@@ -314,11 +314,11 @@
 	    continue;
 	if (pj_strcmp(&r.enc_name, &ID_TELEPHONE_EVENT) == 0) {
-	    si->tx_event_pt = pj_strtoul(&r.pt);
+	    si->rx_event_pt = pj_strtoul(&r.pt);
 	    break;
 	}
     }
 
-    /* Get remote DTMF payload type */
-    si->rx_event_pt = -1;
+    /* Get outgoing payload type for telephone-events */
+    si->tx_event_pt = -1;
     for (i=0; i<rem_m->attr_count; ++i) {
 	pjmedia_sdp_rtpmap r;
@@ -330,5 +330,5 @@
 	    continue;
 	if (pj_strcmp(&r.enc_name, &ID_TELEPHONE_EVENT) == 0) {
-	    si->rx_event_pt = pj_strtoul(&r.pt);
+	    si->tx_event_pt = pj_strtoul(&r.pt);
 	    break;
 	}
Index: pjproject/trunk/pjmedia/src/pjmedia/stream.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia/stream.c	(revision 434)
+++ pjproject/trunk/pjmedia/src/pjmedia/stream.c	(revision 435)
@@ -175,7 +175,5 @@
     pj_mutex_unlock( stream->jb_mutex );
 
-    if (status != PJ_SUCCESS || frame_type == PJMEDIA_JB_ZERO_FRAME ||
-	frame_type == PJMEDIA_JB_MISSING_FRAME) 
-    {
+    if (status != PJ_SUCCESS || frame_type != PJMEDIA_JB_NORMAL_FRAME) {
 	frame->type = PJMEDIA_FRAME_TYPE_NONE;
 	return PJ_SUCCESS;
@@ -628,6 +626,8 @@
 
 	} else {
+	    unsigned ext_seq;
+	    ext_seq = channel->rtp.seq_ctrl.cycles | pj_ntohs(hdr->seq);
 	    status = pjmedia_jbuf_put_frame(stream->jb, payload, payloadlen,
-					    pj_ntohs(hdr->seq));
+					    ext_seq);
 	}
 	pj_mutex_unlock( stream->jb_mutex );
@@ -915,9 +915,10 @@
     status = pjmedia_jbuf_create(pool, &stream->port.info.name,
 				 stream->frame_size, 
-				 jbuf_init, jbuf_max,
-				 &stream->jb);
+				 jbuf_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);
 
     /* Create decoder channel: */
