Index: pjproject/branches/1.0/pjmedia/build/Jbtest.dat
===================================================================
--- pjproject/branches/1.0/pjmedia/build/Jbtest.dat	(revision 2553)
+++ pjproject/branches/1.0/pjmedia/build/Jbtest.dat	(revision 2788)
@@ -1,62 +1,324 @@
-#
-###############################################################################
-# This test demonstrates situation where there is no jitter. 
-# Jitter should go the minimum configured value.
-###############################################################################
-#
-#PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG
-
-#
-###############################################################################
-# This test demonstrates situation where there is no jitter, but with
-# addition of silence compression. The jitter value should also go
-# to the minimum.
-###############################################################################
-#
-#PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG /* Start silence */ GGGGGGGGGGGGGGGGGGGGG /* End silence */ PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG
-
-#
-###############################################################################
-# This test demonstrates situation where there's about one-three packets jitter
-# in the network, without packet lost.
-###############################################################################
-#
-#PGPGPPGGPPGGPPGGGGPG PGPGPPGGPPPGGPPGGGPG PGPGPPGGPPPGGPPGGGPG PGPGPPGGPPGGPPPGGGPG PGPGPPGGPPGGPPPGGGPG
-
-#
-###############################################################################
-# Two gets two puts, no jitter
-###############################################################################
-#
-#PPGGPPGGPPGGPPGGPPGG PPGGPPGGPPGGPPGGPPGG PPGGPPGGPPGGPPGGPPGG PPGGPPGGPPGGPPGGPPGG PPGGPPGGPPGGPPGGPPGG
-
-#
-###############################################################################
-# Three gets three puts, no packet lost
-###############################################################################
-#
-#PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG
-
-
-#
-###############################################################################
-# Three gets three puts, with packet lost
-###############################################################################
-#
-#PPPGGGPPPGGGPPPGGGPGPG /* Lost */ GGGGGGGGGG PPPGGGPPPGGGPPPGGGPGPG /* Lost */ GGGGGGGGGG PPPGGGPPPGGGPPPGGGPGPG /* Lost */ GGGGGGGGGG PPPGGGPPPGGGPPPGGGPGPG /* Lost */ GGGGGGGGGG PPPGGGPPPGGGPPPGGGPGPG /* Lost */ GGGGGGGGGG PPPGGGPPPGGGPPPGGGPGPG /* Lost */ GGGGGGGGGG PPPGGGPPPGGGPPPGGGPGPG /* Lost */ GGGGGGGGGG PPPGGGPPPGGGPPPGGGPGPG /* Lost */ GGGGGGGGGG PPPGGGPPPGGGPPPGGGPGPG /* Lost */ GGGGGGGGGG PPPGGGPPPGGGPPPGGGPGPG /* Lost */ GGGGGGGGGG PPPGGGPPPGGGPPPGGGPGPG
-
-
-#
-###############################################################################
-# Three gets three puts, then stable
-###############################################################################
-#
-PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PPPGGGPPPGGGPPPGGGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG 
-
-#
-###############################################################################
-# Some jitter
-###############################################################################
-#
-#PGPGPGPGPG /*Some frames missing here*/ GG /*Some frames arrive*/ PPPG /*Normal*/ PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG
-
+= Ideal condition
+%adaptive 0 0 10
+!burst	    1
+!discard    0
+!lost	    0
+!empty	    0
+!delay	    1
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG 
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG 
+.
+
+= DTX
+%adaptive 0 0 10
+!burst	    1
+!discard    0
+!lost	    0
+!empty	    20
+!delay	    1
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG
+# Start silence
+GGGGGGGGGGGGGGGGGGGG
+# End silence
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG
+.
+
+= Regular burst (three gets three puts)
+%adaptive 0 0 10
+!burst	    3
+!discard    0
+!lost	    0
+!empty	    0
+!delay	    3
+PPPGGGPPPGGGPPPGGG PPPGGGPPPGGGPPPGGG PPPGGGPPPGGGPPPGGG PPPGGGPPPGGGPPPGGG
+PPPGGGPPPGGGPPPGGG PPPGGGPPPGGGPPPGGG PPPGGGPPPGGGPPPGGG PPPGGGPPPGGGPPPGGG
+.
+
+= Random burst (no drift)
+%adaptive 0 0 10
+!burst	    4
+!discard    1 <- there may be delay adaptation caused by multiple empty GETs followed by multiple PUTs, later when burst level reaches 'stable' condition, JB may shrink some excess frames
+!lost	    0
+!empty	    4
+!delay	    4
+PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPPPGGPGGGPG 
+PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG PGGGGPPPGPPGPPPGGPGG 
+PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPPPGGPGGGPG 
+PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG PGGGGPPPGPPGPPPGGPGG 
+PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPPPGGPGGGPG 
+PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG PGGGGPPPGPPGPPPGGPGG 
+PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPPPGGPGGGPG 
+PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG PGGGGPPPGPPGPPPGGPGG 
+PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPPPGGPGGGPG 
+PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG PGGGGPPPGPPGPPPGGPGG 
+PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPPPGGPGGGPG 
+PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG PGGGGPPPGPPGPPPGGPGG 
+PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPPPGGPGGGPG 
+PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG PGGGGPPPGPPGPPPGGPGG 
+PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPPPGGPGGGPG 
+PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG PGGGGPPPGPPGPPPGGPGG 
+PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPPPGGPGGGPG 
+PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG PGGGGPPPGPPGPPPGGPGG 
+PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPPPGGPGGGPG 
+PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG PGGGGPPPGPPGPPPGGPGG 
+PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPPPGGPGGGPG 
+PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG PGGGGPPPGPPGPPPGGPGG 
+PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPPPGGPGGGPG 
+PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG PGGGGPPPGPPGPPPGGPGG 
+PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPPPGGPGGGPG 
+PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG PGGGGPPPGPPGPPPGGPGG 
+PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPPPGGPGGGPG 
+PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG PGGGGPPPGPPGPPPGGPGG 
+PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPPPGGPGGGPG 
+PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG PGGGGPPPGPPGPPPGGPGG 
+PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPPPGGPGGGPG 
+PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG PGGGGPPPGPPGPPPGGPGG 
+PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPPPGGPGGGPG 
+PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG PGGGGPPPGPPGPPPGGPGG 
+PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPPPGGPGGGPG 
+PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG PGGGGPPPGPPGPPPGGPGG 
+PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPPPGGPGGGPG 
+PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG PGGGGPPPGPPGPPPGGPGG 
+PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPPPGGPGGGPG 
+PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG PGGGGPPPGPPGPPPGGPGG 
+PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPPPGGPGGGPG 
+PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG PGGGGPPPGPPGPPPGGPGG 
+PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPPPGGPGGGPG 
+PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG PGGGGPPPGPPGPPPGGPGG 
+PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPPPGGPGGGPG 
+PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG PGGGGPPPGPPGPPPGGPGG 
+PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPPPGGPGGGPG 
+PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG PGGGGPPPGPPGPPPGGPGG 
+PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPPPGGPGGGPG 
+PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG PGGGGPPPGPPGPPPGGPGG 
+PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPPPGGPGGGPG 
+PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG PGGGGPPPGPPGPPPGGPGG 
+.
+
+= Random burst (with drift, PUT > GET)
+%adaptive 0 0 10
+!burst	    4
+!discard    68 <- number of PUT - GET, JB does shrinking by discarding frames
+!lost	    0
+!empty	    4
+!delay	    8  <- should be less than or equal to twice of burst
+P PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG P PGPGPPGGPPPPGGPGGGPG 
+P PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG P PGGGGPPPGPPGPPPGGPGG 
+P PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG P PGPGPPGGPPPPGGPGGGPG 
+P PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG P PGGGGPPPGPPGPPPGGPGG 
+P PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG P PGPGPPGGPPPPGGPGGGPG 
+P PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG P PGGGGPPPGPPGPPPGGPGG 
+P PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG P PGPGPPGGPPPPGGPGGGPG 
+P PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG P PGGGGPPPGPPGPPPGGPGG 
+P PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG P PGPGPPGGPPPPGGPGGGPG 
+P PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG P PGGGGPPPGPPGPPPGGPGG 
+P PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG P PGPGPPGGPPPPGGPGGGPG 
+P PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG P PGGGGPPPGPPGPPPGGPGG 
+P PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG P PGPGPPGGPPPPGGPGGGPG 
+P PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG P PGGGGPPPGPPGPPPGGPGG 
+P PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG P PGPGPPGGPPPPGGPGGGPG 
+P PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG P PGGGGPPPGPPGPPPGGPGG 
+P PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG P PGPGPPGGPPPPGGPGGGPG 
+P PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG P PGGGGPPPGPPGPPPGGPGG 
+P PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG P PGPGPPGGPPPPGGPGGGPG 
+P PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG P PGGGGPPPGPPGPPPGGPGG 
+P PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG P PGPGPPGGPPPPGGPGGGPG 
+P PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG P PGGGGPPPGPPGPPPGGPGG 
+P PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG P PGPGPPGGPPPPGGPGGGPG 
+P PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG P PGGGGPPPGPPGPPPGGPGG 
+P PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG P PGPGPPGGPPPPGGPGGGPG 
+P PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG P PGGGGPPPGPPGPPPGGPGG 
+P PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG P PGPGPPGGPPPPGGPGGGPG 
+P PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG P PGGGGPPPGPPGPPPGGPGG 
+P PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG P PGPGPPGGPPPPGGPGGGPG 
+P PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG P PGGGGPPPGPPGPPPGGPGG 
+P PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG P PGPGPPGGPPPPGGPGGGPG 
+P PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG P PGGGGPPPGPPGPPPGGPGG 
+P PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG P PGPGPPGGPPPPGGPGGGPG 
+P PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG P PGGGGPPPGPPGPPPGGPGG 
+.
+
+= Random burst (with drift, PUT < GET)
+%adaptive 0 0 10
+!burst	    4
+!discard    0
+!lost	    0
+!empty	    70 <- GET - PUT = 66, added 4 for tolerating empty caused by burst
+!delay	    4  <- should be less than or equal to burst
+G PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG G PGPGPPGGPPPPGGPGGGPG 
+G PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG G PGGGGPPPGPPGPPPGGPGG 
+G PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG G PGPGPPGGPPPPGGPGGGPG 
+G PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG G PGGGGPPPGPPGPPPGGPGG 
+G PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG G PGPGPPGGPPPPGGPGGGPG 
+G PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG G PGGGGPPPGPPGPPPGGPGG 
+G PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG G PGPGPPGGPPPPGGPGGGPG 
+G PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG G PGGGGPPPGPPGPPPGGPGG 
+G PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG G PGPGPPGGPPPPGGPGGGPG 
+G PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG G PGGGGPPPGPPGPPPGGPGG 
+G PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG G PGPGPPGGPPPPGGPGGGPG 
+G PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG G PGGGGPPPGPPGPPPGGPGG 
+G PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG G PGPGPPGGPPPPGGPGGGPG 
+G PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG G PGGGGPPPGPPGPPPGGPGG 
+G PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG G PGPGPPGGPPPPGGPGGGPG 
+G PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG G PGGGGPPPGPPGPPPGGPGG 
+G PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG G PGPGPPGGPPPPGGPGGGPG 
+G PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG G PGGGGPPPGPPGPPPGGPGG 
+G PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG G PGPGPPGGPPPPGGPGGGPG 
+G PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG G PGGGGPPPGPPGPPPGGPGG 
+G PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG G PGPGPPGGPPPPGGPGGGPG 
+G PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG G PGGGGPPPGPPGPPPGGPGG 
+G PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG G PGPGPPGGPPPPGGPGGGPG 
+G PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG G PGGGGPPPGPPGPPPGGPGG 
+G PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG G PGPGPPGGPPPPGGPGGGPG 
+G PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG G PGGGGPPPGPPGPPPGGPGG 
+G PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG G PGPGPPGGPPPPGGPGGGPG 
+G PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG G PGGGGPPPGPPGPPPGGPGG 
+G PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG G PGPGPPGGPPPPGGPGGGPG 
+G PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG G PGGGGPPPGPPGPPPGGPGG 
+G PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG G PGPGPPGGPPPPGGPGGGPG 
+G PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG G PGGGGPPPGPPGPPPGGPGG 
+G PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG G PGPGPPGGPPPPGGPGGGPG 
+.
+
+= Packet lost
+%adaptive 0 0 10
+!burst	    1
+!discard    0
+!lost	    7
+!empty	    3
+!delay	    3
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG
+# Some losts
+LGPGPGLGPGPGPGLGPGPG
+# Normal
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG
+# More losts
+PLPGGGPPPGGGPLPGGGPG PLPGGGPPPGGGPLPGGGPG
+# Normal
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG
+.
+
+= Sequence restart
+%adaptive 0 0 10
+!burst	    1
+!discard    0
+!lost	    0
+!empty	    0
+!delay	    1
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG 
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG 
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG 
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG 
+# seq restarted after 120 PUTs (default MAX_MISORDER == 100)
+R
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG 
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG 
+.
+
+= Duplicated frames
+= e.g.: some Forward Error Correction (FEC) methods.
+%adaptive 0 0 10
+!burst	    1
+!discard    40
+!lost	    0
+!empty	    0
+!delay	    1
+PDGPDGPDGPDGPDG PDGPDGPDGPDGPDG PDGPDGPDGPDGPDG PDGPDGPDGPDGPDG
+PDGPDGPDGPDGPDG PDGPDGPDGPDGPDG PDGPDGPDGPDGPDG PDGPDGPDGPDGPDG
+.
+
+= Late frames
+%adaptive 0 0 10
+!burst	    1
+!discard    8  <- late frames are discarded + delay adaptation
+!lost	    4
+!empty	    4
+!delay	    4
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG 
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG 
+# Suddenly there are some lost frames
+LGLGPGLGLGPG
+# Those lost frames are actually late (+misordered), here they come
+OOOO
+# Then back to normal
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG 
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG 
+.
+
+= PUT burst at the beginning
+%adaptive 0 0 10
+!burst	    1
+!discard    50 <- frames discarded for delay adaptation
+!lost	    0
+!empty	    0
+!delay	    25 <- average delay, JB is able to adapt the delay
+PPPPPPPPPPPPPPPPPPPP PPPPPPPPPPPPPPPPPPPP PPPPPPPPPP
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
+.
+
+= Fixed mode prefetch 5, with two empty events
+%fixed 5
+!burst	    1
+!discard    0
+!lost	    0
+!empty	    10
+!delay	    5
+G
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
+GGGGG
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
+.
+
+= Fixed mode prefetch 5, with random burst
+%fixed 5
+!burst	    3
+!discard    0
+!lost	    0
+!empty	    5
+!delay	    5
+PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPPPGGPGGGPG 
+PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG PGGGGPPPGPPGPPPGGPGG 
+PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPPPGGPGGGPG 
+PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG PGGGGPPPGPPGPPPGGPGG 
+PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPPPGGPGGGPG 
+PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG PGGGGPPPGPPGPPPGGPGG 
+PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPPPGGPGGGPG 
+PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG PGGGGPPPGPPGPPPGGPGG 
+.
+
+= Fixed mode prefetch 10, PUT burst at the beginning
+%fixed 10
+!burst	    1
+!discard    35 <- frames discarded for delay adaptation
+!lost	    0
+!empty	    0
+!delay	    30 <- average delay
+PPPPPPPPPPPPPPPPPPPP PPPPPPPPPPPPPPPPPPPP PPPPPPPPPP
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
+PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
+.
Index: pjproject/branches/1.0/pjmedia/include/pjmedia/jbuf.h
===================================================================
--- pjproject/branches/1.0/pjmedia/include/pjmedia/jbuf.h	(revision 2553)
+++ pjproject/branches/1.0/pjmedia/include/pjmedia/jbuf.h	(revision 2788)
@@ -67,17 +67,26 @@
 
 /**
- * This structure describes jitter buffer current status.
+ * This structure describes jitter buffer state.
  */
 struct pjmedia_jb_state
 {
+    /* Setting */
     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. */
+
+    /* Status */
+    unsigned	prefetch;	    /**< Current prefetch value, in frames  */
     unsigned	size;		    /**< Current buffer size, in frames.    */
+
+    /* Statistic */
     unsigned	avg_delay;	    /**< Average delay, in ms.		    */
     unsigned	min_delay;	    /**< Minimum delay, in ms.		    */
     unsigned	max_delay;	    /**< Maximum delay, in ms.		    */
-    unsigned	dev_delay;	    /**< Standard deviation of delay, in ms. */
+    unsigned	dev_delay;	    /**< Standard deviation of delay, in ms.*/
+    unsigned	avg_burst;	    /**< Average burst, in frames.	    */
+    unsigned	lost;		    /**< Number of lost frames.		    */
+    unsigned	discard;	    /**< Number of discarded frames.	    */
+    unsigned	empty;		    /**< Number of empty on GET events.	    */
 };
 
Index: pjproject/branches/1.0/pjmedia/src/pjmedia/jbuf.c
===================================================================
--- pjproject/branches/1.0/pjmedia/src/pjmedia/jbuf.c	(revision 2553)
+++ pjproject/branches/1.0/pjmedia/src/pjmedia/jbuf.c	(revision 2788)
@@ -32,19 +32,47 @@
 #define THIS_FILE   "jbuf.c"
 
+
+/* Minimal difference between JB size and 2*burst-level to perform 
+ * JB shrinking. 
+ */
 #define SAFE_SHRINKING_DIFF	1
+
+/* Minimal gap (in ms) between JB shrinking */
 #define MIN_SHRINK_GAP_MSEC	200
 
+/* Invalid sequence number, used as the initial value. */
+#define INVALID_OFFSET		-9999
+
+/* Maximum burst length, whenever an operation is bursting longer than 
+ * this value, JB will assume that the opposite operation was idle.
+ */
+#define MAX_BURST_MSEC		1000
+
+/* Number of OP switches to be performed in JB_STATUS_INITIALIZING, before
+ * JB can switch its states to JB_STATUS_PROCESSING.
+ */
+#define INIT_CYCLE		10
+
+
+/* Struct of JB internal buffer, represented in a circular buffer containing
+ * frame content, frame type, frame length, and frame bit info.
+ */
 typedef struct jb_framelist_t
 {
-    char	*flist_buffer;
-    int		*flist_frame_type;
-    pj_size_t	*flist_content_len;
-    pj_uint32_t	*flist_bit_info;
-    unsigned	 flist_frame_size;
-    unsigned	 flist_max_count;
-    unsigned	 flist_empty;
-    unsigned	 flist_head;
-    unsigned	 flist_tail;
-    unsigned	 flist_origin;
+    /* Settings */
+    unsigned	     frame_size;	/**< maximum size of frame	    */
+    unsigned	     max_count;		/**< maximum number of frames	    */
+
+    /* Buffers */
+    char	    *content;		/**< frame content array	    */
+    int		    *frame_type;	/**< frame type array		    */
+    pj_size_t	    *content_len;	/**< frame length array		    */
+    pj_uint32_t	    *bit_info;		/**< frame bit info array	    */
+    
+    /* States */
+    unsigned	     head;		/**< index of head, pointed frame
+					     will be returned by next GET   */
+    unsigned	     size;		/**< current size of framelist.	    */
+    int		     origin;		/**< original index of flist_head   */
 } jb_framelist_t;
 
@@ -52,27 +80,53 @@
 struct pjmedia_jbuf
 {
-    pj_str_t	    name;		  // jitter buffer name
-    jb_framelist_t  jb_framelist;
-    pj_size_t	    jb_frame_size;	  // frame size	
-    unsigned	    jb_frame_ptime;	  // frame duration.
-    pj_size_t	    jb_max_count;	  // max frames in the jitter framelist->flist_buffer
-
-    int		    jb_level;		  // delay between source & destination
-					  // (calculated according of the number of get/put operations)
-    int		    jb_max_hist_level;    // max level during the last level calculations
-    int		    jb_stable_hist;	  // num of times the delay has	been lower then	the prefetch num
-    int		    jb_last_op;		  // last operation executed on	the framelist->flist_buffer (put/get)
-    int		    jb_last_seq_no;	  // seq no. of	the last frame inserted	to the framelist->flist_buffer
-    int		    jb_prefetch;	  // no. of frame to insert before removing some
-					  // (at the beginning of the framelist->flist_buffer operation)
-    int		    jb_prefetch_cnt;	  // prefetch counter
-    int		    jb_def_prefetch;	  // Default prefetch
-    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
-    pj_math_stat    jb_delay;		  // Delay statistics of jitter buffer (in frame unit)
-
-    unsigned	    jb_last_del_seq;	  // Seq # of last frame deleted
-    unsigned	    jb_min_shrink_gap;	  // How often can we shrink
+    /* Settings (consts) */
+    pj_str_t	    jb_name;		/**< jitter buffer name		    */
+    pj_size_t	    jb_frame_size;	/**< frame size			    */
+    unsigned	    jb_frame_ptime;	/**< frame duration.		    */
+    pj_size_t	    jb_max_count;	/**< capacity of jitter buffer, 
+					     in frames			    */
+    int		    jb_def_prefetch;	/**< Default prefetch		    */
+    int		    jb_min_prefetch;	/**< Minimum allowable prefetch	    */
+    int		    jb_max_prefetch;	/**< Maximum allowable prefetch	    */
+    int		    jb_max_burst;	/**< maximum possible burst, whenever
+					     burst exceeds this value, it 
+					     won't be included in level 
+					     calculation		    */
+    int		    jb_min_shrink_gap;	/**< How often can we shrink	    */
+
+    /* Buffer */
+    jb_framelist_t  jb_framelist;	/**< the buffer			    */
+
+    /* States */
+    int		    jb_level;		/**< delay between source & 
+					     destination (calculated according 
+					     of the number of burst get/put 
+					     operations)		    */
+    int		    jb_max_hist_level;  /**< max level during the last level 
+					     calculations		    */
+    int		    jb_stable_hist;	/**< num of times the delay has	been 
+					     lower then the prefetch num    */
+    int		    jb_last_op;		/**< last operation executed 
+					     (put/get)			    */
+    int		    jb_prefetch;	/**< no. of frame to insert before 
+					     removing some (at the beginning 
+					     of the framelist->content 
+					     operation), the value may be
+					     continuously updated based on
+					     current frame burst level.	    */
+    int		    jb_status;		/**< status is 'init' until the	first 
+					     'put' operation		    */
+    int		    jb_init_cycle_cnt;	/**< status is 'init' until the	first 
+					     'put' operation		    */
+    int		    jb_last_del_seq;	/**< Seq # of last frame deleted    */
+
+    /* Statistics */
+    pj_math_stat    jb_delay;		/**< Delay statistics of jitter buffer 
+					     (in ms)			    */
+    pj_math_stat    jb_burst;		/**< Burst statistics (in frames)   */
+    unsigned	    jb_lost;		/**< Number of lost frames.	    */
+    unsigned	    jb_discard;		/**< Number of discarded frames.    */
+    unsigned	    jb_empty;		/**< Number of empty/prefetching frame
+					     returned by GET. */
 };
 
@@ -91,4 +145,5 @@
 #endif
 
+static pj_status_t jb_framelist_reset(jb_framelist_t *framelist);
 
 static pj_status_t jb_framelist_init( pj_pool_t *pool,
@@ -101,26 +156,24 @@
     pj_bzero(framelist, sizeof(jb_framelist_t));
 
-    framelist->flist_frame_size = frame_size;
-    framelist->flist_max_count = max_count;
-    framelist->flist_buffer = (char*) 
-			      pj_pool_zalloc(pool,
-					     framelist->flist_frame_size * 
-					     framelist->flist_max_count);
-
-    framelist->flist_frame_type = (int*)
-	pj_pool_zalloc(pool, sizeof(framelist->flist_frame_type[0]) * 
-				framelist->flist_max_count);
-
-    framelist->flist_content_len = (pj_size_t*)
-	pj_pool_zalloc(pool, sizeof(framelist->flist_content_len[0]) * 
-				framelist->flist_max_count);
-
-    framelist->flist_bit_info = (pj_uint32_t*)
-	pj_pool_zalloc(pool, sizeof(framelist->flist_bit_info[0]) * 
-				framelist->flist_max_count);
-
-    framelist->flist_empty = 1;
-
-    return PJ_SUCCESS;
+    framelist->frame_size   = frame_size;
+    framelist->max_count    = max_count;
+    framelist->content	    = (char*) 
+			      pj_pool_alloc(pool,
+					    framelist->frame_size* 
+					    framelist->max_count);
+    framelist->frame_type   = (int*)
+			      pj_pool_alloc(pool, 
+					    sizeof(framelist->frame_type[0])*
+					    framelist->max_count);
+    framelist->content_len  = (pj_size_t*)
+			      pj_pool_alloc(pool, 
+					    sizeof(framelist->content_len[0])*
+					    framelist->max_count);
+    framelist->bit_info	    = (pj_uint32_t*)
+			      pj_pool_alloc(pool, 
+					    sizeof(framelist->bit_info[0])*
+					    framelist->max_count);
+
+    return jb_framelist_reset(framelist);
 
 }
@@ -132,13 +185,34 @@
 }
 
+static pj_status_t jb_framelist_reset(jb_framelist_t *framelist) 
+{
+    framelist->head = 0;
+    framelist->origin = INVALID_OFFSET;
+    framelist->size = 0;
+
+    //pj_bzero(framelist->content, 
+    //	     framelist->frame_size * 
+    //	     framelist->max_count);
+
+    pj_memset(framelist->frame_type,
+	      PJMEDIA_JB_MISSING_FRAME,
+	      sizeof(framelist->frame_type[0]) * 
+	      framelist->max_count);
+
+    pj_bzero(framelist->content_len, 
+	     sizeof(framelist->content_len[0]) * 
+	     framelist->max_count);
+
+    //pj_bzero(framelist->bit_info,
+    //	     sizeof(framelist->bit_info[0]) * 
+    //	     framelist->max_count);
+
+    return PJ_SUCCESS;
+}
+
 
 static unsigned jb_framelist_size(jb_framelist_t *framelist) 
 {
-    if (framelist->flist_tail == framelist->flist_head) {
-	return framelist->flist_empty ? 0 : framelist->flist_max_count;
-    } else {
-	return (framelist->flist_tail - framelist->flist_head + 
-		framelist->flist_max_count) % framelist->flist_max_count;
-    }
+    return framelist->size;
 }
 
@@ -149,33 +223,31 @@
 				  pj_uint32_t *bit_info) 
 {
-    if (!framelist->flist_empty) {
+    if (framelist->size) {
 	pj_memcpy(frame, 
-		  framelist->flist_buffer + 
-		    framelist->flist_head * framelist->flist_frame_size,
-		  framelist->flist_frame_size);
+		  framelist->content + 
+		  framelist->head * framelist->frame_size,
+		  framelist->frame_size);
 	*p_type = (pjmedia_jb_frame_type) 
-		  framelist->flist_frame_type[framelist->flist_head];
+		  framelist->frame_type[framelist->head];
 	if (size)
-	    *size   = framelist->flist_content_len[framelist->flist_head];
+	    *size   = framelist->content_len[framelist->head];
 	if (bit_info)
-	    *bit_info = framelist->flist_bit_info[framelist->flist_head];
-
-	pj_bzero(framelist->flist_buffer + 
-		    framelist->flist_head * framelist->flist_frame_size,
-		  framelist->flist_frame_size);
-	framelist->flist_frame_type[framelist->flist_head] = 
-	    PJMEDIA_JB_MISSING_FRAME;
-	framelist->flist_content_len[framelist->flist_head] = 0;
-
-	framelist->flist_origin++;
-	framelist->flist_head = (framelist->flist_head + 1 ) % 
-				framelist->flist_max_count;
-	if (framelist->flist_head == framelist->flist_tail) 
-	    framelist->flist_empty = PJ_TRUE;
+	    *bit_info = framelist->bit_info[framelist->head];
+
+	//pj_bzero(framelist->content + 
+	//	 framelist->head * framelist->frame_size,
+	//	 framelist->frame_size);
+	framelist->frame_type[framelist->head] = PJMEDIA_JB_MISSING_FRAME;
+	framelist->content_len[framelist->head] = 0;
+	framelist->bit_info[framelist->head] = 0;
+
+	framelist->origin++;
+	framelist->head = (framelist->head + 1) % framelist->max_count;
+	framelist->size--;
 	
 	return PJ_TRUE;
-
     } else {
-	pj_bzero(frame, framelist->flist_frame_size);
+	pj_bzero(frame, framelist->frame_size);
+
 	return PJ_FALSE;
     }
@@ -183,20 +255,17 @@
 
 
-static void jb_framelist_remove_head( jb_framelist_t *framelist,
-				      unsigned count) 
-{
-    unsigned cur_size;
-
-    cur_size = jb_framelist_size(framelist);
-    if (count > cur_size) 
-	count = cur_size;
+static unsigned jb_framelist_remove_head(jb_framelist_t *framelist,
+					 unsigned count) 
+{
+    if (count > framelist->size) 
+	count = framelist->size;
 
     if (count) {
-	// may be done in two steps if overlapping
+	/* may be done in two steps if overlapping */
 	unsigned step1,step2;
-	unsigned tmp = framelist->flist_head+count;
-
-	if (tmp > framelist->flist_max_count) {
-	    step1 = framelist->flist_max_count - framelist->flist_head;
+	unsigned tmp = framelist->head+count;
+
+	if (tmp > framelist->max_count) {
+	    step1 = framelist->max_count - framelist->head;
 	    step2 = count-step1;
 	} else {
@@ -205,89 +274,95 @@
 	}
 
-	pj_bzero(framelist->flist_buffer + 
-		    framelist->flist_head * framelist->flist_frame_size,
-	          step1*framelist->flist_frame_size);
-	pj_memset(framelist->flist_frame_type+framelist->flist_head,
+	//pj_bzero(framelist->content + 
+	//	    framelist->head * framelist->frame_size,
+	//          step1*framelist->frame_size);
+	pj_memset(framelist->frame_type+framelist->head,
 		  PJMEDIA_JB_MISSING_FRAME,
-		  step1*sizeof(framelist->flist_frame_type[0]));
-	pj_bzero(framelist->flist_content_len+framelist->flist_head,
-		  step1*sizeof(framelist->flist_content_len[0]));
+		  step1*sizeof(framelist->frame_type[0]));
+	pj_bzero(framelist->content_len+framelist->head,
+		  step1*sizeof(framelist->content_len[0]));
 
 	if (step2) {
-	    pj_bzero( framelist->flist_buffer,
-		      step2*framelist->flist_frame_size);
-	    pj_memset(framelist->flist_frame_type,
+	    //pj_bzero( framelist->content,
+	    //	      step2*framelist->frame_size);
+	    pj_memset(framelist->frame_type,
 		      PJMEDIA_JB_MISSING_FRAME,
-		      step2*sizeof(framelist->flist_frame_type[0]));
-	    pj_bzero (framelist->flist_content_len,
-		      step2*sizeof(framelist->flist_content_len[0]));
-	}
-
-	// update pointers
-	framelist->flist_origin += count;
-	framelist->flist_head = (framelist->flist_head + count) % 
-			        framelist->flist_max_count;
-	if (framelist->flist_head == framelist->flist_tail) 
-	    framelist->flist_empty = PJ_TRUE;
-    }
-}
-
-
-static pj_bool_t jb_framelist_put_at(jb_framelist_t *framelist,
-				     unsigned index,
-				     const void *frame,
-				     unsigned frame_size,
-				     pj_uint32_t bit_info)
-{
+		      step2*sizeof(framelist->frame_type[0]));
+	    pj_bzero (framelist->content_len,
+		      step2*sizeof(framelist->content_len[0]));
+	}
+
+	/* update states */
+	framelist->origin += count;
+	framelist->head = (framelist->head + count) % framelist->max_count;
+	framelist->size -= count;
+    }
+    
+    return count;
+}
+
+
+static pj_status_t jb_framelist_put_at(jb_framelist_t *framelist,
+				       int index,
+				       const void *frame,
+				       unsigned frame_size,
+				       pj_uint32_t bit_info)
+{
+    int distance;
     unsigned where;
-
-    assert(frame_size <= framelist->flist_frame_size);
-
-    if (!framelist->flist_empty) {
-	unsigned max_index;
-	unsigned cur_size;
-
-	// too late
-	if (index < framelist->flist_origin) 
-	    return PJ_FALSE;
-
-	// too soon
-	max_index = framelist->flist_origin + framelist->flist_max_count - 1;
-	if (index > max_index)
-	    return PJ_FALSE;
-
-	where = (index - framelist->flist_origin + framelist->flist_head) % 
-	        framelist->flist_max_count;
-
-	// update framelist->flist_tail pointer
-	cur_size = jb_framelist_size(framelist);
-	if (index >= framelist->flist_origin + cur_size) {
-	    unsigned diff = (index - (framelist->flist_origin + cur_size));
-	    framelist->flist_tail = (framelist->flist_tail + diff + 1) % 
-				    framelist->flist_max_count;
-	}
-    } else {
-	// check if frame is not too late, but watch out for sequence restart.
-	if (index < framelist->flist_origin && 
-	    framelist->flist_origin - index < 0x7FFF) 
-	{
-	    return PJ_FALSE;
-	}
-
-	where = framelist->flist_tail;
-	framelist->flist_origin = index;
-	framelist->flist_tail = (framelist->flist_tail + 1) % 
-				framelist->flist_max_count;
-	framelist->flist_empty = PJ_FALSE;
-    }
-
-    pj_memcpy(framelist->flist_buffer + where * framelist->flist_frame_size, 
+    enum { MAX_MISORDER = 100 };
+    enum { MAX_DROPOUT = 3000 };
+
+    assert(frame_size <= framelist->frame_size);
+
+    /* too late or duplicated or sequence restart */
+    if (index < framelist->origin) {
+	if (framelist->origin - index < MAX_MISORDER) {
+	    /* too late or duplicated */
+	    return PJ_ETOOSMALL;
+	} else {
+	    /* sequence restart */
+	    framelist->origin = index - framelist->size;
+	}
+    }
+
+    /* if jbuf is empty, just reset the origin */
+    if (framelist->size == 0) {
+	framelist->origin = index;
+    }
+
+    /* get distance of this frame to the first frame in the buffer */
+    distance = index - framelist->origin;
+
+    /* far jump, the distance is greater than buffer capacity */
+    if (distance >= (int)framelist->max_count) {
+	if (distance > MAX_DROPOUT) {
+	    /* jump too far, reset the buffer */
+	    jb_framelist_reset(framelist);
+	    framelist->origin = index;
+	    distance = 0;
+	} else {
+	    /* otherwise, reject the frame */
+	    return PJ_ETOOMANY;
+	}
+    }
+
+    /* get the slot position */
+    where = (framelist->head + distance) % framelist->max_count;
+
+    /* if the slot is occupied, it must be duplicated frame, ignore it. */
+    if (framelist->frame_type[where] != PJMEDIA_JB_MISSING_FRAME)
+	return PJ_EEXISTS;
+
+    /* put the frame into the slot */
+    pj_memcpy(framelist->content + where * framelist->frame_size,
 	      frame, frame_size);
-
-    framelist->flist_frame_type[where] = PJMEDIA_JB_NORMAL_FRAME;
-    framelist->flist_content_len[where] = frame_size;
-    framelist->flist_bit_info[where] = bit_info;
-
-    return PJ_TRUE;
+    framelist->frame_type[where] = PJMEDIA_JB_NORMAL_FRAME;
+    framelist->content_len[where] = frame_size;
+    framelist->bit_info[where] = bit_info;
+    if (framelist->origin + (int)framelist->size <= index)
+	framelist->size = distance + 1;
+
+    return PJ_SUCCESS;
 }
 
@@ -318,21 +393,17 @@
 	return status;
 
-    pj_strdup_with_null(pool, &jb->name, name);
+    pj_strdup_with_null(pool, &jb->jb_name, name);
     jb->jb_frame_size	 = frame_size;
     jb->jb_frame_ptime   = ptime;
-    jb->jb_last_seq_no	 = -1;
-    jb->jb_level	 = 0;
-    jb->jb_last_op	 = JB_OP_INIT;
     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;
-    jb->jb_max_hist_level = 0;
     jb->jb_max_count	 = max_count;
     jb->jb_min_shrink_gap= MIN_SHRINK_GAP_MSEC / ptime;
-
+    jb->jb_max_burst	 = MAX_BURST_MSEC / ptime;
     pj_math_stat_init(&jb->jb_delay);
+    pj_math_stat_init(&jb->jb_burst);
+
+    pjmedia_jbuf_reset(jb);
 
     *p_jb = jb;
@@ -383,17 +454,13 @@
 PJ_DEF(pj_status_t) pjmedia_jbuf_reset(pjmedia_jbuf *jb)
 {
-    jb->jb_last_seq_no	 = -1;
     jb->jb_level	 = 0;
     jb->jb_last_op	 = JB_OP_INIT;
-    jb->jb_prefetch_cnt	 = 0;
     jb->jb_stable_hist	 = 0;
     jb->jb_status	 = JB_STATUS_INITIALIZING;
-    jb->jb_max_hist_level = 0;
-
-    jb_framelist_remove_head(&jb->jb_framelist, 
-			     jb_framelist_size(&jb->jb_framelist));
-
-    pj_math_stat_init(&jb->jb_delay);
-    
+    jb->jb_init_cycle_cnt= 0;
+    jb->jb_max_hist_level= 0;
+
+    jb_framelist_reset(&jb->jb_framelist);
+
     return PJ_SUCCESS;
 }
@@ -402,4 +469,17 @@
 PJ_DEF(pj_status_t) pjmedia_jbuf_destroy(pjmedia_jbuf *jb)
 {
+    TRACE__((jb->jb_name.ptr, "\n"
+	    "  JB summary:\n"
+	    "    size=%d prefetch=%d\n"
+	    "    delay (min/max/avg/dev)=%d/%d/%d/%d ms\n"
+	    "    burst (min/max/avg/dev)=%d/%d/%d/%d frames\n"
+	    "    lost=%d discard=%d empty=%d\n",
+	    jb->jb_framelist.size, jb->jb_prefetch,
+	    jb->jb_delay.min, jb->jb_delay.max, jb->jb_delay.mean, 
+	    pj_math_stat_get_stddev(&jb->jb_delay),
+	    jb->jb_burst.min, jb->jb_burst.max, jb->jb_burst.mean, 
+	    pj_math_stat_get_stddev(&jb->jb_burst),
+	    jb->jb_lost, jb->jb_discard, jb->jb_empty));
+
     return jb_framelist_destroy(&jb->jb_framelist);
 }
@@ -411,97 +491,133 @@
 
     cur_size = jb_framelist_size(&jb->jb_framelist);
-
-    /* Only apply burst-level calculation on PUT operation since if VAD is 
-     * active the burst-level may not be accurate.
+    pj_math_stat_update(&jb->jb_burst, jb->jb_level);
+    jb->jb_max_hist_level = PJ_MAX(jb->jb_max_hist_level, jb->jb_level);
+
+    /* Burst level is decreasing */
+    if (jb->jb_level < jb->jb_prefetch) {
+
+	enum { STABLE_HISTORY_LIMIT = 100 };
+        
+	jb->jb_stable_hist++;
+        
+	/* Only update the prefetch if 'stable' condition is reached 
+	 * (not just short time impulse)
+	 */
+	if (jb->jb_stable_hist > STABLE_HISTORY_LIMIT) {
+    	
+	    diff = (jb->jb_prefetch - jb->jb_max_hist_level) / 3;
+
+	    if (diff < 1)
+		diff = 1;
+
+	    jb->jb_prefetch -= diff;
+	    if (jb->jb_prefetch < jb->jb_min_prefetch) 
+		jb->jb_prefetch = jb->jb_min_prefetch;
+
+	    /* Reset history */
+	    jb->jb_max_hist_level = 0;
+	    jb->jb_stable_hist = 0;
+
+	    TRACE__((jb->jb_name.ptr,"jb updated(1), prefetch=%d, size=%d",
+		     jb->jb_prefetch, cur_size));
+	}
+    }
+
+    /* Burst level is increasing */
+    else if (jb->jb_level > jb->jb_prefetch) {
+
+	/* Instaneous set prefetch to recent maximum level (max_hist_level) */
+	jb->jb_prefetch = PJ_MIN(jb->jb_max_hist_level,
+				 (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;
+	/* Do not reset max_hist_level. */
+	//jb->jb_max_hist_level = 0;
+
+	TRACE__((jb->jb_name.ptr,"jb updated(2), prefetch=%d, size=%d", 
+		 jb->jb_prefetch, cur_size));
+    }
+
+    /* Level is unchanged */
+    else {
+	jb->jb_stable_hist = 0;
+    }
+}
+
+PJ_INLINE(void) jbuf_update(pjmedia_jbuf *jb, int oper)
+{
+    int diff, burst_level;
+
+    if(jb->jb_last_op != oper) {
+	jb->jb_last_op = oper;
+
+	if (jb->jb_status == JB_STATUS_INITIALIZING) {
+	    /* Switch status 'initializing' -> 'processing' after some OP 
+	     * switch cycles and current OP is GET (burst level is calculated 
+	     * based on PUT burst), so burst calculation is guaranted to be
+	     * performed right after the status switching.
+	     */
+	    if (++jb->jb_init_cycle_cnt >= INIT_CYCLE && oper == JB_OP_GET) {
+		jb->jb_status = JB_STATUS_PROCESSING;
+	    } else {
+		jb->jb_level = 0;
+		return;
+	    }
+	}
+
+	/* Perform jitter calculation based on PUT burst-level only, since 
+	 * GET burst-level may not be accurate, e.g: when VAD is active.
+	 * Note that when burst-level is too big, i.e: exceeds jb_max_burst,
+	 * the GET op may be idle, in this case, we better skip the jitter 
+	 * calculation.
+	 */
+	if (oper == JB_OP_GET && jb->jb_level < jb->jb_max_burst)
+	    jbuf_calculate_jitter(jb);
+
+	jb->jb_level = 0;
+    }
+
+    /* These code is used for shortening the delay in the jitter buffer.
+     * It needs shrink only when there is possibility of drift. Drift
+     * detection is performed by inspecting the jitter buffer size, if
+     * its size is twice of current burst level, there can be drift.
+     *
+     * Moreover, normally drift level is quite low, so JB shouldn't need
+     * to shrink aggresively, it will shrink maximum one frame per 
+     * MIN_SHRINK_GAP_MSEC ms. Theoritically, JB may handle drift level 
+     * as much as = FRAME_PTIME/MIN_SHRINK_GAP_MSEC * 100%
+     *
+     * Whenever there is drift, where PUT > GET, this method will keep 
+     * the latency (JB size) as much as twice of burst level.
      */
-    if (jb->jb_last_op == JB_OP_PUT) {
-
-	jb->jb_max_hist_level = PJ_MAX(jb->jb_max_hist_level,jb->jb_level);
-
-	/* Level is decreasing */
-	if (jb->jb_level < jb->jb_prefetch) {
-
-	    enum { STABLE_HISTORY_LIMIT = 100 };
-	    
-	    jb->jb_stable_hist++;
-	    
-	    /* Only update the prefetch if 'stable' condition is reached 
-	     * (not just short time impulse)
-	     */
-	    if (jb->jb_stable_hist > STABLE_HISTORY_LIMIT) {
-		
-		diff = (jb->jb_prefetch - jb->jb_max_hist_level) / 3;
-
-		if (diff < 1)
-		    diff = 1;
-
-		/* Update max_hist_level. */
-		jb->jb_max_hist_level = jb->jb_prefetch;
-
-		jb->jb_prefetch -= diff;
-		if (jb->jb_prefetch < jb->jb_min_prefetch) 
-		    jb->jb_prefetch = jb->jb_min_prefetch;
-
-		jb->jb_stable_hist = 0;
-
-		TRACE__((jb->name.ptr,"jb updated(1), prefetch=%d, size=%d", 
-			 jb->jb_prefetch, cur_size));
-	    }
-	}
-
-	/* Level is increasing */
-	else if (jb->jb_level > jb->jb_prefetch) {
-
-	    /* Instaneous set prefetch */
-	    jb->jb_prefetch = PJ_MIN(jb->jb_max_hist_level,
-				     (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;
-	    // Keep max_hist_level.
-	    //jb->jb_max_hist_level = 0;
-
-	    TRACE__((jb->name.ptr,"jb updated(2), prefetch=%d, size=%d", 
-		     jb->jb_prefetch, cur_size));
-	}
-
-	/* Level is unchanged */
-	else {
-	    jb->jb_stable_hist = 0;
-	}
-    }
-
-    /* These code is used for shortening the delay in the jitter buffer. */
-    // Shrinking based on max_hist_level (recent max level).
-    //diff = cur_size - jb->jb_prefetch;
-    diff = cur_size - jb->jb_max_hist_level;
-    if (diff > SAFE_SHRINKING_DIFF && 
-	jb->jb_framelist.flist_origin-jb->jb_last_del_seq > jb->jb_min_shrink_gap)
-    {
-	/* Shrink slowly */
-	diff = 1;
-
-	/* Drop frame(s)! */
-	jb_framelist_remove_head(&jb->jb_framelist, diff);
-	jb->jb_last_del_seq = jb->jb_framelist.flist_origin;
-
-	pj_math_stat_update(&jb->jb_delay, cur_size - diff);
-
-	TRACE__((jb->name.ptr, 
-		 "JB shrinking %d frame(s), size=%d", diff,
-		 jb_framelist_size(&jb->jb_framelist)));
-    } else {
-	pj_math_stat_update(&jb->jb_delay, cur_size);
-    }
-
-    jb->jb_level = 0;
-}
-
-PJ_INLINE(void) jbuf_update(pjmedia_jbuf *jb, int oper)
-{
-    if(jb->jb_last_op != oper) {
-	jbuf_calculate_jitter(jb);
-	jb->jb_last_op = oper;
+
+    if (jb->jb_status != JB_STATUS_PROCESSING)
+	return;
+
+    burst_level = PJ_MAX(jb->jb_prefetch, jb->jb_level);
+    diff = jb_framelist_size(&jb->jb_framelist) - burst_level*2;
+
+    if (diff >= SAFE_SHRINKING_DIFF) {
+	/* Check and adjust jb_last_del_seq, in case there was seq restart */
+	if (jb->jb_framelist.origin < jb->jb_last_del_seq)
+	    jb->jb_last_del_seq = jb->jb_framelist.origin;
+
+	if (jb->jb_framelist.origin - jb->jb_last_del_seq >=
+	    jb->jb_min_shrink_gap)
+	{
+	    /* Shrink slowly, one frame per cycle */
+	    diff = 1;
+
+	    /* Drop frame(s)! */
+	    diff = jb_framelist_remove_head(&jb->jb_framelist, diff);
+	    jb->jb_last_del_seq = jb->jb_framelist.origin;
+	    jb->jb_discard += diff;
+
+	    TRACE__((jb->jb_name.ptr, 
+		     "JB shrinking %d frame(s), cur size=%d", diff,
+		     jb_framelist_size(&jb->jb_framelist)));
+	}
     }
 }
@@ -523,57 +639,45 @@
 {
     pj_size_t min_frame_size;
-    int seq_diff;
-
-    if (jb->jb_last_seq_no == -1)	{
-	jb->jb_last_seq_no = frame_seq - 1;
-    }
-
-    seq_diff = frame_seq - jb->jb_last_seq_no;
-    jb->jb_last_seq_no = PJ_MAX(jb->jb_last_seq_no, frame_seq);
-    if (seq_diff > 0) jb->jb_level += seq_diff;
-
-    if(jb->jb_status ==	JB_STATUS_INITIALIZING) {
-	jb->jb_status = JB_STATUS_PROCESSING;
-	jb->jb_level = 0;
-    } else {
+    int prev_size, cur_size;
+    pj_status_t status;
+
+    /* Get JB size before PUT */
+    prev_size = jb_framelist_size(&jb->jb_framelist);
+    
+    /* Attempt to store the frame */
+    min_frame_size = PJ_MIN(frame_size, jb->jb_frame_size);
+    status = jb_framelist_put_at(&jb->jb_framelist, frame_seq, frame,
+				 min_frame_size, bit_info);
+    
+    /* Jitter buffer is full, cannot store the frame */
+    while (status == PJ_ETOOMANY) {
+	unsigned removed;
+
+	removed = jb_framelist_remove_head(&jb->jb_framelist,
+					   PJ_MAX(jb->jb_max_count/4, 1));
+	status = jb_framelist_put_at(&jb->jb_framelist, frame_seq, frame,
+				     min_frame_size, bit_info);
+
+	jb->jb_discard += removed;
+    }
+
+    /* Get JB size after PUT */
+    cur_size = jb_framelist_size(&jb->jb_framelist);
+
+    /* Return the flag if this frame is discarded */
+    if (discarded)
+	*discarded = (status != PJ_SUCCESS);
+
+    if (status == PJ_SUCCESS) {
+	if (jb->jb_status == JB_STATUS_PREFETCHING) {
+	    TRACE__((jb->jb_name.ptr, "PUT prefetch_cnt=%d/%d", 
+		     cur_size, jb->jb_prefetch));
+	    if (cur_size >= jb->jb_prefetch)
+		jb->jb_status = JB_STATUS_PROCESSING;
+	}
+	jb->jb_level += (cur_size > prev_size ? cur_size-prev_size : 1);
 	jbuf_update(jb, JB_OP_PUT);
-    }
-
-    min_frame_size = PJ_MIN(frame_size, jb->jb_frame_size);
-    if (seq_diff > 0) {
-
-	while (jb_framelist_put_at(&jb->jb_framelist, frame_seq, frame,
-				   min_frame_size, bit_info) == PJ_FALSE)
-	{
-	    jb_framelist_remove_head(&jb->jb_framelist,
-				     PJ_MAX(jb->jb_max_count/4,1) );
-	}
-
-	if (jb->jb_prefetch_cnt < jb->jb_prefetch) {
-	    jb->jb_prefetch_cnt += seq_diff;
-	    
-	    TRACE__((jb->name.ptr, "PUT prefetch_cnt=%d/%d", 
-		     jb->jb_prefetch_cnt, jb->jb_prefetch));
-
-	    if (jb->jb_status == JB_STATUS_PREFETCHING && 
-		jb->jb_prefetch_cnt >= jb->jb_prefetch)
-	    {
-		jb->jb_status = JB_STATUS_PROCESSING;
-	    }
-	}
-
-
-
-	if (discarded)
-	    *discarded = PJ_FALSE;
-    }
-    else
-    {
-	pj_bool_t res;
-	res = jb_framelist_put_at(&jb->jb_framelist,frame_seq,frame,
-				  min_frame_size, bit_info);
-	if (discarded)
-	    *discarded = !res;
-    }
+    } else
+	jb->jb_discard++;
 }
 
@@ -597,56 +701,64 @@
 				     pj_uint32_t *bit_info)
 {
-    pjmedia_jb_frame_type ftype;
-
-    jb->jb_level++;
-
-    jbuf_update(jb, JB_OP_GET);
-
-    if (jb_framelist_size(&jb->jb_framelist) == 0) {
-	jb->jb_prefetch_cnt = 0;
+    int cur_size;
+
+    cur_size = jb_framelist_size(&jb->jb_framelist);
+
+    if (cur_size == 0) {
+	/* jitter buffer empty */
+
 	if (jb->jb_def_prefetch)
 	    jb->jb_status = JB_STATUS_PREFETCHING;
-    }
-
-    if (jb->jb_status == JB_STATUS_PREFETCHING && 
-	jb->jb_prefetch_cnt < jb->jb_prefetch)
-    {
+
+	//pj_bzero(frame, jb->jb_frame_size);
+	*p_frame_type = PJMEDIA_JB_ZERO_EMPTY_FRAME;
+	if (size)
+	    *size = 0;
+
+	jb->jb_empty++;
+
+    } else if (jb->jb_status == JB_STATUS_PREFETCHING) {
+
 	/* Can't return frame because jitter buffer is filling up
 	 * minimum prefetch.
 	 */
-	pj_bzero(frame, jb->jb_frame_size);
-	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;
-
+
+	//pj_bzero(frame, jb->jb_frame_size);
+	*p_frame_type = PJMEDIA_JB_ZERO_PREFETCH_FRAME;
 	if (size)
 	    *size = 0;
 
-	TRACE__((jb->name.ptr, "GET prefetch_cnt=%d/%d",
-		 jb->jb_prefetch_cnt, jb->jb_prefetch));
-	return;
-    }
-
-    /* Retrieve a frame from frame list */
-    if (jb_framelist_get(&jb->jb_framelist,frame,size,&ftype,bit_info) ==
-	PJ_FALSE) 
-    {
-	/* Can't return frame because jitter buffer is empty! */
-	pj_bzero(frame, jb->jb_frame_size);
-	*p_frame_type = PJMEDIA_JB_ZERO_EMPTY_FRAME;
-	if (size)
-	    *size = 0;
-
-	return;
-    }
-
-    /* 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;
-    else 
-	*p_frame_type	= PJMEDIA_JB_MISSING_FRAME;
+	TRACE__((jb->jb_name.ptr, "GET prefetch_cnt=%d/%d",
+		 cur_size, jb->jb_prefetch));
+
+	jb->jb_empty++;
+
+    } else {
+
+	pjmedia_jb_frame_type ftype;
+	pj_bool_t res;
+
+	/* Retrieve a frame from frame list */
+	res = jb_framelist_get(&jb->jb_framelist, frame, size, &ftype, 
+			       bit_info);
+	pj_assert(res);
+
+	/* 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;
+	} else {
+	    *p_frame_type = PJMEDIA_JB_MISSING_FRAME;
+	    jb->jb_lost++;
+	}
+
+	/* Calculate delay on the first GET */
+	if (jb->jb_last_op == JB_OP_PUT)
+	    pj_math_stat_update(&jb->jb_delay, cur_size * jb->jb_frame_ptime);
+    }
+
+    jb->jb_level++;
+    jbuf_update(jb, JB_OP_GET);
 }
 
@@ -660,13 +772,19 @@
 
     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->prefetch = jb->jb_prefetch;
     state->size = jb_framelist_size(&jb->jb_framelist);
-    state->avg_delay = jb->jb_delay.mean * jb->jb_frame_ptime;
-    state->min_delay = jb->jb_delay.min * jb->jb_frame_ptime;
-    state->max_delay = jb->jb_delay.max * jb->jb_frame_ptime;
-    state->dev_delay = pj_math_stat_get_stddev(&jb->jb_delay) * 
-		       jb->jb_frame_ptime;
+    
+    state->avg_delay = jb->jb_delay.mean;
+    state->min_delay = jb->jb_delay.min;
+    state->max_delay = jb->jb_delay.max;
+    state->dev_delay = pj_math_stat_get_stddev(&jb->jb_delay);
+    
+    state->avg_burst = jb->jb_burst.mean;
+    state->empty = jb->jb_empty;
+    state->discard = jb->jb_discard;
+    state->lost = jb->jb_lost;
 
     return PJ_SUCCESS;
Index: pjproject/branches/1.0/pjmedia/src/test/jbuf_test.c
===================================================================
--- pjproject/branches/1.0/pjmedia/src/test/jbuf_test.c	(revision 2553)
+++ pjproject/branches/1.0/pjmedia/src/test/jbuf_test.c	(revision 2788)
@@ -27,106 +27,282 @@
 #define JB_MAX_PREFETCH	    10
 #define JB_PTIME	    20
-#define JB_BUF_SIZE	    20
+#define JB_BUF_SIZE	    50
 
 #define REPORT
 //#define PRINT_COMMENT
 
+typedef struct test_param_t {
+    pj_bool_t adaptive;
+    unsigned init_prefetch;
+    unsigned min_prefetch;
+    unsigned max_prefetch;
+} test_param_t;
+
+typedef struct test_cond_t {
+    int burst;
+    int discard;
+    int lost;
+    int empty;
+    int delay;	    /**< Maximum delay, in frames.	    */
+} test_cond_t;
+
+static pj_bool_t parse_test_headers(char *line, test_param_t *param, 
+			       test_cond_t *cond)
+{
+    char *p = line;
+
+    if (*p == '%') {
+	/* Test params. */
+	char mode_st[16];
+
+	sscanf(p+1, "%s %u %u %u", mode_st, &param->init_prefetch, 
+	       &param->min_prefetch, &param->max_prefetch);
+	param->adaptive = (pj_ansi_stricmp(mode_st, "adaptive") == 0);
+
+    } else if (*p == '!') {
+	/* Success condition. */
+	char cond_st[16];
+	unsigned cond_val;
+
+	sscanf(p+1, "%s %u", cond_st, &cond_val);
+	if (pj_ansi_stricmp(cond_st, "burst") == 0)
+	    cond->burst = cond_val;
+	else if (pj_ansi_stricmp(cond_st, "delay") == 0)
+	    cond->delay = cond_val;
+	else if (pj_ansi_stricmp(cond_st, "discard") == 0)
+	    cond->discard = cond_val;
+	else if (pj_ansi_stricmp(cond_st, "empty") == 0)
+	    cond->empty = cond_val;
+	else if (pj_ansi_stricmp(cond_st, "lost") == 0)
+	    cond->lost = cond_val;
+
+    } else if (*p == '=') {
+	/* Test title. */
+	++p;
+	while (*p && isspace(*p)) ++p;
+	printf("%s", p);
+    } else {
+	/* Unknown header, perhaps this is the test data */
+
+	/* Skip spaces */
+	while (*p && isspace(*p)) ++p;
+
+	/* Test data started.*/
+	if (*p != 0)
+	    return PJ_FALSE;
+    }
+
+    return PJ_TRUE;
+}
+
+static pj_bool_t process_test_data(char data, pjmedia_jbuf *jb, 
+				   pj_uint16_t *seq, pj_uint16_t *last_seq)
+{
+    char frame[1];
+    char f_type;
+    pj_bool_t print_state = PJ_TRUE;
+    pj_bool_t data_eos = PJ_FALSE;
+
+    switch (toupper(data)) {
+    case 'G': /* Get */
+	pjmedia_jbuf_get_frame(jb, frame, &f_type);
+	break;
+    case 'P': /* Put */
+	pjmedia_jbuf_put_frame(jb, (void*)frame, 1, *seq);
+	*last_seq = *seq;
+	++*seq;
+	break;
+    case 'L': /* Lost */
+	*last_seq = *seq;
+	++*seq;
+	printf("Lost\n");
+	break;
+    case 'R': /* Sequence restarts */
+	*seq = 1;
+	printf("Sequence restarting, from %u to %u\n", *last_seq, *seq);
+	break;
+    case 'J': /* Sequence jumps */
+	(*seq) += 5000;
+	printf("Sequence jumping, from %u to %u\n", *last_seq, *seq);
+	break;
+    case 'D': /* Frame duplicated */
+	pjmedia_jbuf_put_frame(jb, (void*)frame, 1, *seq - 1);
+	break;
+    case 'O': /* Old/late frame */
+	pjmedia_jbuf_put_frame(jb, (void*)frame, 1, *seq - 10 - pj_rand()%40);
+	break;
+    case '.': /* End of test session. */
+	data_eos = PJ_TRUE;
+	break;
+    default:
+	print_state = PJ_FALSE;
+	printf("Unknown test data '%c'\n", data);
+	break;
+    }
+
+    if (data_eos)
+	return PJ_FALSE;
+
+#ifdef REPORT
+    if (print_state) {
+	pjmedia_jb_state state;
+
+	pjmedia_jbuf_get_state(jb, &state);
+	printf("seq=%d\t%c\tsize=%d\tprefetch=%d\n", 
+	       *last_seq, toupper(data), state.size, state.prefetch);
+    }
+#endif
+
+    return PJ_TRUE;
+}
+
 int jbuf_main(void)
 {
-    pjmedia_jbuf *jb;
     FILE *input = fopen("JBTEST.DAT", "rt");
-    unsigned seq;
-    char line[1024 * 10], *p;
-    pj_pool_t *pool;
-    pjmedia_jb_state state;
-    pj_str_t jb_name = {"JBTEST", 6};
-
-    pj_init();
-    pool = pj_pool_create(mem, "JBPOOL", 256*16, 256*16, NULL);
-
-    pjmedia_jbuf_create(pool, &jb_name, 1, JB_PTIME, JB_BUF_SIZE, &jb);
-    pjmedia_jbuf_set_adaptive(jb, JB_INIT_PREFETCH, JB_MIN_PREFETCH, 
-			      JB_MAX_PREFETCH);
-
-    while ((p=fgets(line, sizeof(line), input)) != NULL) {
-
-	while (*p && isspace(*p))
-	    ++p;
-
-	if (!*p)
-	    continue;
-
-	if (*p == '#') {
-#ifdef PRINT_COMMENT
-	    printf("%s", p);
-#endif
-	    continue;
-	}
-
+    pj_bool_t data_eof = PJ_FALSE;
+    int old_log_level;
+    int rc = 0;
+
+    old_log_level = pj_log_get_level();
+    pj_log_set_level(5);
+
+    while (rc == 0 && !data_eof) {
+	pj_str_t jb_name = {"JBTEST", 6};
+	pjmedia_jbuf *jb;
+	pj_pool_t *pool;
+	pjmedia_jb_state state;
+	pj_uint16_t last_seq = 0;
+	pj_uint16_t seq = 1;
+	char line[1024], *p = NULL;
+
+	test_param_t param;
+	test_cond_t cond;
+
+	param.adaptive = PJ_TRUE;
+	param.init_prefetch = JB_INIT_PREFETCH;
+	param.min_prefetch = JB_MIN_PREFETCH;
+	param.max_prefetch = JB_MAX_PREFETCH;
+
+	cond.burst = -1;
+	cond.delay = -1;
+	cond.discard = -1;
+	cond.empty = -1;
+	cond.lost = -1;
+
+	printf("\n\n");
+
+	/* Parse test session title, param, and conditions */
+	do {
+	    p = fgets(line, sizeof(line), input);
+	} while (p && parse_test_headers(line, &param, &cond));
+
+	/* EOF test data */
+	if (p == NULL)
+	    break;
+
+	//printf("======================================================\n");
+
+	/* Initialize test session */
+	pool = pj_pool_create(mem, "JBPOOL", 256*16, 256*16, NULL);
+	pjmedia_jbuf_create(pool, &jb_name, 1, JB_PTIME, JB_BUF_SIZE, &jb);
 	pjmedia_jbuf_reset(jb);
-	seq = 1;
+
+	if (param.adaptive) {
+	    pjmedia_jbuf_set_adaptive(jb, 
+				      param.init_prefetch, 
+				      param.min_prefetch,
+				      param.max_prefetch);
+	} else {
+	    pjmedia_jbuf_set_fixed(jb, param.init_prefetch);
+	}
 
 #ifdef REPORT
 	pjmedia_jbuf_get_state(jb, &state);
 	printf("Initial\tsize=%d\tprefetch=%d\tmin.pftch=%d\tmax.pftch=%d\n", 
-	    state.size, state.prefetch, state.min_prefetch, state.max_prefetch);
+	       state.size, state.prefetch, state.min_prefetch, 
+	       state.max_prefetch);
 #endif
 
-	while (*p) {
+
+	/* Test session start */
+	while (1) {
 	    int c;
-	    char frame[1];
-	    char f_type;
 	    
+	    /* Get next line of test data */
+	    if (!p || *p == 0) {
+		p = fgets(line, sizeof(line), input);
+		if (p == NULL) {
+		    data_eof = PJ_TRUE;
+		    break;
+		}
+	    }
+
+	    /* Get next char of test data */
 	    c = *p++;
+
+	    /* Skip spaces */
 	    if (isspace(c))
 		continue;
-	    
-	    if (c == '/') {
-		putchar('\n');
-
-		while (*++p && *p != '/')
-		    putchar(*p);
-
-		putchar('\n');
-
-		if (*++p == 0)
-		    break;
-
+
+	    /* Print comment line */
+	    if (c == '#') {
+#ifdef PRINT_COMMENT
+		while (*p && isspace(*p)) ++p;
+		if (*p) printf("..%s", p);
+#endif
+		*p = 0;
 		continue;
 	    }
 
-	    switch (toupper(c)) {
-	    case 'G':
-		pjmedia_jbuf_get_frame(jb, frame, &f_type);
+	    /* Process test data */
+	    if (!process_test_data(c, jb, &seq, &last_seq))
 		break;
-	    case 'P':
-		pjmedia_jbuf_put_frame(jb, (void*)frame, 1, seq);
-		seq++;
-		break;
-	    case 'L':
-		seq++;
-		printf("Lost\n");
-		break;
-	    default:
-		printf("Unknown character '%c'\n", c);
-		break;
-	    }
-
-#ifdef REPORT
-	    if (toupper(c) != 'L') {
-		pjmedia_jbuf_get_state(jb, &state);
-		printf("seq=%d\t%c\tsize=%d\tprefetch=%d\n", 
-		       seq, toupper(c), state.size, state.prefetch);
-	    }
-#endif
-	}
+	}
+
+	/* Print JB states */
+	pjmedia_jbuf_get_state(jb, &state);
+	printf("------------------------------------------------------\n");
+	printf("Summary:\n");
+	printf("  size=%d prefetch=%d\n", state.size, state.prefetch);
+	printf("  delay (min/max/avg/dev)=%d/%d/%d/%d ms\n",
+	       state.min_delay, state.max_delay, state.avg_delay, 
+	       state.dev_delay);
+	printf("  lost=%d discard=%d empty=%d burst(avg)=%d\n", 
+	       state.lost, state.discard, state.empty, state.avg_burst);
+
+	/* Evaluate test session */
+	if (cond.burst >= 0 && (int)state.avg_burst > cond.burst) {
+	    printf("! 'Burst' should be %d, it is %d\n", 
+		   cond.burst, state.avg_burst);
+	    rc |= 1;
+	}
+	if (cond.delay >= 0 && (int)state.avg_delay/JB_PTIME > cond.delay) {
+	    printf("! 'Delay' should be %d, it is %d\n", 
+		   cond.delay, state.avg_delay/JB_PTIME);
+	    rc |= 2;
+	}
+	if (cond.discard >= 0 && (int)state.discard > cond.discard) {
+	    printf("! 'Discard' should be %d, it is %d\n",
+		   cond.discard, state.discard);
+	    rc |= 4;
+	}
+	if (cond.empty >= 0 && (int)state.empty > cond.empty) {
+	    printf("! 'Empty' should be %d, it is %d\n", 
+		   cond.empty, state.empty);
+	    rc |= 8;
+	}
+	if (cond.lost >= 0 && (int)state.lost > cond.lost) {
+	    printf("! 'Lost' should be %d, it is %d\n", 
+		   cond.lost, state.lost);
+	    rc |= 16;
+	}
+
+	pjmedia_jbuf_destroy(jb);
+	pj_pool_release(pool);
     }
 
-    pjmedia_jbuf_destroy(jb);
-
-    if (input != stdin)
-	fclose(input);
-
-    pj_pool_release(pool);
-    return 0;
+    fclose(input);
+    pj_log_set_level(old_log_level);
+
+    return rc;
 }
Index: pjproject/branches/1.0/pjmedia/src/test/test.c
===================================================================
--- pjproject/branches/1.0/pjmedia/src/test/test.c	(revision 2553)
+++ pjproject/branches/1.0/pjmedia/src/test/test.c	(revision 2788)
@@ -61,9 +61,10 @@
     //rtp_test(&caching_pool.factory);
     //session_test (&caching_pool.factory);
-    //jbuf_main();
-    mips_test();
+    DO_TEST(jbuf_main());
+    //DO_TEST(mips_test());
 
     PJ_LOG(3,(THIS_FILE," "));
 
+on_return:
     if (rc != 0) {
 	PJ_LOG(3,(THIS_FILE,"Test completed with error(s)!"));
@@ -73,4 +74,5 @@
 
     pj_caching_pool_destroy(&caching_pool);
+
     return rc;
 }
