summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNanang Izzuddin <nanang@teluu.com>2009-06-24 14:46:36 +0000
committerNanang Izzuddin <nanang@teluu.com>2009-06-24 14:46:36 +0000
commit790fe4aff28bf82dc3bc754a35cc51dce15eae46 (patch)
tree3dd04be62e771c3f7ee557678299533f6e8b5779
parent9006038744d3b688623f8023627d2d1d70519fbb (diff)
Ticket #763: backported changes from ticket #762
git-svn-id: http://svn.pjsip.org/repos/pjproject/branches/1.0@2788 74dad513-b988-da41-8d7b-12977e46ad98
-rw-r--r--pjmedia/build/Jbtest.dat384
-rw-r--r--pjmedia/include/pjmedia/jbuf.h15
-rw-r--r--pjmedia/src/pjmedia/jbuf.c780
-rw-r--r--pjmedia/src/test/jbuf_test.c310
-rw-r--r--pjmedia/src/test/test.c6
5 files changed, 1031 insertions, 464 deletions
diff --git a/pjmedia/build/Jbtest.dat b/pjmedia/build/Jbtest.dat
index 7646b6f5..3e2169c4 100644
--- a/pjmedia/build/Jbtest.dat
+++ b/pjmedia/build/Jbtest.dat
@@ -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
+.
diff --git a/pjmedia/include/pjmedia/jbuf.h b/pjmedia/include/pjmedia/jbuf.h
index 0c9299cc..4088e359 100644
--- a/pjmedia/include/pjmedia/jbuf.h
+++ b/pjmedia/include/pjmedia/jbuf.h
@@ -66,19 +66,28 @@ typedef enum pjmedia_jb_frame_type pjmedia_jb_frame_type;
/**
- * 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. */
};
diff --git a/pjmedia/src/pjmedia/jbuf.c b/pjmedia/src/pjmedia/jbuf.c
index 2cbb1643..1df68a57 100644
--- a/pjmedia/src/pjmedia/jbuf.c
+++ b/pjmedia/src/pjmedia/jbuf.c
@@ -31,49 +31,103 @@
#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;
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. */
};
@@ -90,6 +144,7 @@ struct pjmedia_jbuf
# define TRACE__(args)
#endif
+static pj_status_t jb_framelist_reset(jb_framelist_t *framelist);
static pj_status_t jb_framelist_init( pj_pool_t *pool,
jb_framelist_t *framelist,
@@ -100,46 +155,65 @@ static pj_status_t jb_framelist_init( pj_pool_t *pool,
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->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);
- 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);
+static pj_status_t jb_framelist_destroy(jb_framelist_t *framelist)
+{
+ PJ_UNUSED_ARG(framelist);
+ return PJ_SUCCESS;
+}
- framelist->flist_bit_info = (pj_uint32_t*)
- pj_pool_zalloc(pool, sizeof(framelist->flist_bit_info[0]) *
- framelist->flist_max_count);
+static pj_status_t jb_framelist_reset(jb_framelist_t *framelist)
+{
+ framelist->head = 0;
+ framelist->origin = INVALID_OFFSET;
+ framelist->size = 0;
- framelist->flist_empty = 1;
+ //pj_bzero(framelist->content,
+ // framelist->frame_size *
+ // framelist->max_count);
- return PJ_SUCCESS;
+ 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);
-static pj_status_t jb_framelist_destroy(jb_framelist_t *framelist)
-{
- PJ_UNUSED_ARG(framelist);
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;
}
@@ -148,147 +222,148 @@ static pj_bool_t jb_framelist_get(jb_framelist_t *framelist,
pjmedia_jb_frame_type *p_type,
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;
}
}
-static void jb_framelist_remove_head( jb_framelist_t *framelist,
- unsigned count)
+static unsigned 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;
+ 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;
+ unsigned tmp = framelist->head+count;
- if (tmp > framelist->flist_max_count) {
- step1 = framelist->flist_max_count - framelist->flist_head;
+ if (tmp > framelist->max_count) {
+ step1 = framelist->max_count - framelist->head;
step2 = count-step1;
} else {
step1 = count;
step2 = 0;
}
- 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]));
+ step2*sizeof(framelist->frame_type[0]));
+ pj_bzero (framelist->content_len,
+ step2*sizeof(framelist->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;
+ /* update states */
+ framelist->origin += count;
+ framelist->head = (framelist->head + count) % framelist->max_count;
+ framelist->size -= count;
}
+
+ return count;
}
-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)
+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;
+ enum { MAX_MISORDER = 100 };
+ enum { MAX_DROPOUT = 3000 };
- assert(frame_size <= framelist->flist_frame_size);
-
- if (!framelist->flist_empty) {
- unsigned max_index;
- unsigned cur_size;
+ assert(frame_size <= framelist->frame_size);
- // too late
- if (index < framelist->flist_origin)
- return PJ_FALSE;
+ /* 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;
+ }
+ }
- // too soon
- max_index = framelist->flist_origin + framelist->flist_max_count - 1;
- if (index > max_index)
- return PJ_FALSE;
+ /* if jbuf is empty, just reset the origin */
+ if (framelist->size == 0) {
+ framelist->origin = index;
+ }
- where = (index - framelist->flist_origin + framelist->flist_head) %
- framelist->flist_max_count;
+ /* get distance of this frame to the first frame in the buffer */
+ distance = index - framelist->origin;
- // 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;
+ /* 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;
}
-
- 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,
- frame, frame_size);
+ /* 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;
- framelist->flist_frame_type[where] = PJMEDIA_JB_NORMAL_FRAME;
- framelist->flist_content_len[where] = frame_size;
- framelist->flist_bit_info[where] = bit_info;
+ /* put the frame into the slot */
+ pj_memcpy(framelist->content + where * framelist->frame_size,
+ frame, frame_size);
+ 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_TRUE;
+ return PJ_SUCCESS;
}
@@ -317,23 +392,19 @@ PJ_DEF(pj_status_t) pjmedia_jbuf_create(pj_pool_t *pool,
if (status != PJ_SUCCESS)
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;
return PJ_SUCCESS;
@@ -382,25 +453,34 @@ PJ_DEF(pj_status_t) pjmedia_jbuf_set_adaptive( pjmedia_jbuf *jb,
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->jb_init_cycle_cnt= 0;
+ jb->jb_max_hist_level= 0;
- jb_framelist_remove_head(&jb->jb_framelist,
- jb_framelist_size(&jb->jb_framelist));
+ jb_framelist_reset(&jb->jb_framelist);
- pj_math_stat_init(&jb->jb_delay);
-
return PJ_SUCCESS;
}
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);
}
@@ -410,99 +490,135 @@ static void jbuf_calculate_jitter(pjmedia_jbuf *jb)
int diff, cur_size;
cur_size = jb_framelist_size(&jb->jb_framelist);
+ 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;
- /* Only apply burst-level calculation on PUT operation since if VAD is
- * active the burst-level may not be accurate.
- */
- if (jb->jb_last_op == JB_OP_PUT) {
+ if (diff < 1)
+ diff = 1;
- jb->jb_max_hist_level = PJ_MAX(jb->jb_max_hist_level,jb->jb_level);
+ jb->jb_prefetch -= diff;
+ if (jb->jb_prefetch < jb->jb_min_prefetch)
+ jb->jb_prefetch = jb->jb_min_prefetch;
- /* Level is decreasing */
- if (jb->jb_level < jb->jb_prefetch) {
+ /* Reset history */
+ jb->jb_max_hist_level = 0;
+ jb->jb_stable_hist = 0;
- 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;
+ 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) {
- if (diff < 1)
- diff = 1;
+ /* 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;
- /* Update max_hist_level. */
- jb->jb_max_hist_level = jb->jb_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;
+ }
+}
- jb->jb_prefetch -= diff;
- if (jb->jb_prefetch < jb->jb_min_prefetch)
- jb->jb_prefetch = jb->jb_min_prefetch;
+PJ_INLINE(void) jbuf_update(pjmedia_jbuf *jb, int oper)
+{
+ int diff, burst_level;
- jb->jb_stable_hist = 0;
+ if(jb->jb_last_op != oper) {
+ jb->jb_last_op = oper;
- TRACE__((jb->name.ptr,"jb updated(1), prefetch=%d, size=%d",
- jb->jb_prefetch, cur_size));
+ 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;
}
}
- /* Level is increasing */
- else if (jb->jb_level > jb->jb_prefetch) {
+ /* 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);
- /* 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_level = 0;
+ }
- jb->jb_stable_hist = 0;
- // Keep max_hist_level.
- //jb->jb_max_hist_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.
+ */
- TRACE__((jb->name.ptr,"jb updated(2), prefetch=%d, size=%d",
- jb->jb_prefetch, cur_size));
- }
+ if (jb->jb_status != JB_STATUS_PROCESSING)
+ return;
- /* Level is unchanged */
- else {
- jb->jb_stable_hist = 0;
- }
- }
+ burst_level = PJ_MAX(jb->jb_prefetch, jb->jb_level);
+ diff = jb_framelist_size(&jb->jb_framelist) - burst_level*2;
- /* 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);
- }
+ 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;
- jb->jb_level = 0;
-}
+ if (jb->jb_framelist.origin - jb->jb_last_del_seq >=
+ jb->jb_min_shrink_gap)
+ {
+ /* Shrink slowly, one frame per cycle */
+ diff = 1;
-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;
+ /* 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)));
+ }
}
}
@@ -522,59 +638,47 @@ PJ_DEF(void) pjmedia_jbuf_put_frame2(pjmedia_jbuf *jb,
pj_bool_t *discarded)
{
pj_size_t min_frame_size;
- int seq_diff;
+ int prev_size, cur_size;
+ pj_status_t status;
- if (jb->jb_last_seq_no == -1) {
- jb->jb_last_seq_no = frame_seq - 1;
- }
+ /* 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;
- 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;
+ 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);
- if(jb->jb_status == JB_STATUS_INITIALIZING) {
- jb->jb_status = JB_STATUS_PROCESSING;
- jb->jb_level = 0;
- } else {
- jbuf_update(jb, JB_OP_PUT);
+ jb->jb_discard += removed;
}
- 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) );
- }
+ /* Get JB size after PUT */
+ cur_size = jb_framelist_size(&jb->jb_framelist);
- 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));
+ /* Return the flag if this frame is discarded */
+ if (discarded)
+ *discarded = (status != PJ_SUCCESS);
- if (jb->jb_status == JB_STATUS_PREFETCHING &&
- jb->jb_prefetch_cnt >= jb->jb_prefetch)
- {
+ 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;
- }
}
-
-
-
- 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;
- }
+ jb->jb_level += (cur_size > prev_size ? cur_size-prev_size : 1);
+ jbuf_update(jb, JB_OP_PUT);
+ } else
+ jb->jb_discard++;
}
/*
@@ -596,58 +700,66 @@ PJ_DEF(void) pjmedia_jbuf_get_frame2(pjmedia_jbuf *jb,
char *p_frame_type,
pj_uint32_t *bit_info)
{
- pjmedia_jb_frame_type ftype;
+ int cur_size;
- jb->jb_level++;
+ cur_size = jb_framelist_size(&jb->jb_framelist);
- jbuf_update(jb, JB_OP_GET);
+ if (cur_size == 0) {
+ /* jitter buffer empty */
- if (jb_framelist_size(&jb->jb_framelist) == 0) {
- jb->jb_prefetch_cnt = 0;
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;
- }
+ TRACE__((jb->jb_name.ptr, "GET prefetch_cnt=%d/%d",
+ cur_size, jb->jb_prefetch));
- /* 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;
+ jb->jb_empty++;
- return;
+ } 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);
}
- /* 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_level++;
+ jbuf_update(jb, JB_OP_GET);
}
/*
@@ -659,15 +771,21 @@ PJ_DEF(pj_status_t) pjmedia_jbuf_get_state( pjmedia_jbuf *jb,
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->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;
}
diff --git a/pjmedia/src/test/jbuf_test.c b/pjmedia/src/test/jbuf_test.c
index c8a5681f..3e896483 100644
--- a/pjmedia/src/test/jbuf_test.c
+++ b/pjmedia/src/test/jbuf_test.c
@@ -26,107 +26,283 @@
#define JB_MIN_PREFETCH 0
#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_bool_t data_eof = PJ_FALSE;
+ int old_log_level;
+ int rc = 0;
- pj_init();
- pool = pj_pool_create(mem, "JBPOOL", 256*16, 256*16, NULL);
+ old_log_level = pj_log_get_level();
+ pj_log_set_level(5);
- 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 (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;
- while ((p=fgets(line, sizeof(line), input)) != NULL) {
+ test_param_t param;
+ test_cond_t cond;
- while (*p && isspace(*p))
- ++p;
+ param.adaptive = PJ_TRUE;
+ param.init_prefetch = JB_INIT_PREFETCH;
+ param.min_prefetch = JB_MIN_PREFETCH;
+ param.max_prefetch = JB_MAX_PREFETCH;
- if (!*p)
- continue;
+ cond.burst = -1;
+ cond.delay = -1;
+ cond.discard = -1;
+ cond.empty = -1;
+ cond.lost = -1;
- if (*p == '#') {
-#ifdef PRINT_COMMENT
- printf("%s", p);
-#endif
- continue;
- }
+ 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);
- break;
- case 'P':
- pjmedia_jbuf_put_frame(jb, (void*)frame, 1, seq);
- seq++;
+ /* Process test data */
+ if (!process_test_data(c, jb, &seq, &last_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);
+ pjmedia_jbuf_destroy(jb);
+ pj_pool_release(pool);
+ }
- if (input != stdin)
- fclose(input);
+ fclose(input);
+ pj_log_set_level(old_log_level);
- pj_pool_release(pool);
- return 0;
+ return rc;
}
diff --git a/pjmedia/src/test/test.c b/pjmedia/src/test/test.c
index 2bae030b..0c39963e 100644
--- a/pjmedia/src/test/test.c
+++ b/pjmedia/src/test/test.c
@@ -60,11 +60,12 @@ int test_main(void)
//sdp_test (&caching_pool.factory);
//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)!"));
} else {
@@ -72,5 +73,6 @@ int test_main(void)
}
pj_caching_pool_destroy(&caching_pool);
+
return rc;
}