summaryrefslogtreecommitdiff
path: root/pjmedia/src
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 /pjmedia/src
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
Diffstat (limited to 'pjmedia/src')
-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
3 files changed, 696 insertions, 400 deletions
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;
}