📄 jbuf.c
字号:
if (status != PJ_SUCCESS)
return status;
pj_strdup_with_null(pool, &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_level = 0;
jb->jb_last_jitter = 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_jitter = 0;
jb->jb_max_count = max_count;
*p_jb = jb;
return PJ_SUCCESS;
}
/*
* Set the jitter buffer to fixed delay mode. The default behavior
* is to adapt the delay with actual packet delay.
*
*/
PJ_DEF(pj_status_t) pjmedia_jbuf_set_fixed( pjmedia_jbuf *jb,
unsigned prefetch)
{
PJ_ASSERT_RETURN(jb, PJ_EINVAL);
PJ_ASSERT_RETURN(prefetch <= jb->jb_max_count, PJ_EINVAL);
jb->jb_min_prefetch = jb->jb_max_prefetch =
jb->jb_prefetch = prefetch;
return PJ_SUCCESS;
}
/*
* Set the jitter buffer to adaptive mode.
*/
PJ_DEF(pj_status_t) pjmedia_jbuf_set_adaptive( pjmedia_jbuf *jb,
unsigned prefetch,
unsigned min_prefetch,
unsigned max_prefetch)
{
PJ_ASSERT_RETURN(jb, PJ_EINVAL);
PJ_ASSERT_RETURN(min_prefetch < max_prefetch &&
prefetch >= min_prefetch &&
prefetch <= max_prefetch &&
max_prefetch <= jb->jb_max_count,
PJ_EINVAL);
jb->jb_prefetch = prefetch;
jb->jb_min_prefetch = min_prefetch;
jb->jb_max_prefetch = max_prefetch;
return PJ_SUCCESS;
}
PJ_DEF(pj_status_t) pjmedia_jbuf_reset(pjmedia_jbuf *jb)
{
jb->jb_last_seq_no = -1;
jb->jb_level = 0;
jb->jb_last_level = 0;
jb->jb_last_jitter = 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_jitter = 0;
jb_framelist_remove_head(&jb->jb_framelist,
jb_framelist_size(&jb->jb_framelist));
return PJ_SUCCESS;
}
PJ_DEF(pj_status_t) pjmedia_jbuf_destroy(pjmedia_jbuf *jb)
{
return jb_framelist_destroy(&jb->jb_framelist);
}
static void jbuf_calculate_jitter(pjmedia_jbuf *jb)
{
unsigned stable_history_limit;
stable_history_limit = 1000 / jb->jb_frame_ptime;
jb->jb_last_jitter = PJ_ABS(jb->jb_level-jb->jb_last_level);
jb->jb_last_level = jb->jb_level;
jb->jb_max_hist_jitter = PJ_MAX(jb->jb_max_hist_jitter,jb->jb_last_jitter);
jb->jb_op_count++;
if (jb->jb_last_jitter < jb->jb_prefetch) {
jb->jb_stable_hist += jb->jb_last_jitter;
if (jb->jb_stable_hist > (int)stable_history_limit) {
int seq_diff = (jb->jb_prefetch - jb->jb_max_hist_jitter)/3;
if (seq_diff<1) seq_diff = 1;
jb->jb_prefetch -= seq_diff;
if (jb->jb_prefetch < jb->jb_min_prefetch)
jb->jb_prefetch = jb->jb_min_prefetch;
jb->jb_stable_hist = 0;
jb->jb_max_hist_jitter = 0;
TRACE__((THIS_FILE,"jb updated(1), prefetch=%d, size=%d",
jb->jb_prefetch, jb_framelist_size(&jb->jb_framelist)));
/* These code is used to shorten the delay in the jitter buffer.
if (jb->jb_op_count >= stable_history_limit*2 &&
(int)jb_framelist_size(&jb->jb_framelist) > jb->jb_prefetch+2)
{
jb_framelist_remove_head(&jb->jb_framelist,1);
PJ_LOG(5,(jb->name.ptr,
"jbuf optimizing, prefetch: %d, size=%d",
jb->jb_prefetch,
jb_framelist_size(&jb->jb_framelist)));
jb->jb_op_count = 0;
}
*/
}
} else {
jb->jb_prefetch = PJ_MIN(jb->jb_last_jitter,
(int)(jb->jb_max_count*4/5));
if (jb->jb_prefetch > jb->jb_max_prefetch)
jb->jb_prefetch = jb->jb_max_prefetch;
jb->jb_stable_hist = 0;
jb->jb_max_hist_jitter = 0;
TRACE__((THIS_FILE,"jb updated(2), prefetch=%d, size=%d",
jb->jb_prefetch, jb_framelist_size(&jb->jb_framelist)));
/* These code is used to shorten the delay in the jitter buffer
when the current size is larger than the prefetch. But it does
not really work when the stream supports multiple frames, since
the size may grow only temporarily.
if (jb->jb_op_count >= stable_history_limit * 2) {
if ((int)jb_framelist_size(&jb->jb_framelist) > jb->jb_prefetch+2)
{
jb_framelist_remove_head(&jb->jb_framelist,1);
PJ_LOG(5,(jb->name.ptr,
"jbuf optimizing prefetch: %d, size=%d",
jb->jb_prefetch,
jb_framelist_size(&jb->jb_framelist)));
}
jb->jb_op_count = 0;
}
*/
}
}
static void jbuf_update(pjmedia_jbuf *jb, int oper)
{
if(jb->jb_last_op != oper) {
jbuf_calculate_jitter(jb);
jb->jb_last_op = oper;
}
}
PJ_DEF(void) pjmedia_jbuf_put_frame( pjmedia_jbuf *jb,
const void *frame,
pj_size_t frame_size,
int frame_seq)
{
pj_size_t min_frame_size;
int seq_diff;
if (jb->jb_last_seq_no == -1) {
jb->jb_last_seq_no = frame_seq - 1;
}
seq_diff = frame_seq - jb->jb_last_seq_no;
jb->jb_last_seq_no = PJ_MAX(jb->jb_last_seq_no, frame_seq);
if (seq_diff > 0) jb->jb_level += seq_diff;
if(jb->jb_status == JB_STATUS_INITIALIZING) {
jb->jb_status = JB_STATUS_PROCESSING;
jb->jb_level = 0;
jb->jb_last_level = 0;
jb->jb_last_jitter = 0;
} else {
jbuf_update(jb, JB_OP_PUT);
}
min_frame_size = PJ_MIN(frame_size, jb->jb_frame_size);
if (seq_diff > 0) {
while (jb_framelist_put_at(&jb->jb_framelist,
frame_seq,frame,min_frame_size) ==PJ_FALSE)
{
jb_framelist_remove_head(&jb->jb_framelist,
PJ_MAX(jb->jb_max_count/4,1) );
}
if (jb->jb_prefetch_cnt < jb->jb_prefetch)
jb->jb_prefetch_cnt += seq_diff;
}
else
{
jb_framelist_put_at(&jb->jb_framelist,frame_seq,frame,min_frame_size);
}
}
/*
* Get frame from jitter buffer.
*/
PJ_DEF(void) pjmedia_jbuf_get_frame( pjmedia_jbuf *jb,
void *frame,
char *p_frame_type)
{
pjmedia_jb_frame_type ftype;
jb->jb_level--;
jbuf_update(jb, JB_OP_GET);
if (jb_framelist_size(&jb->jb_framelist) == 0) {
jb->jb_prefetch_cnt = 0;
}
if ((jb->jb_prefetch_cnt < jb->jb_prefetch)) {
/* 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;
return;
}
/* Retrieve a frame from frame list */
if (jb_framelist_get(&jb->jb_framelist,frame,&ftype) == PJ_FALSE) {
/* Can't return frame because jitter buffer is empty! */
pj_bzero(frame, jb->jb_frame_size);
*p_frame_type = PJMEDIA_JB_ZERO_EMPTY_FRAME;
return;
}
/* We've successfully retrieved a frame from the frame list, but
* the frame could be a blank frame!
*/
if (ftype == PJMEDIA_JB_NORMAL_FRAME)
*p_frame_type = PJMEDIA_JB_NORMAL_FRAME;
else
*p_frame_type = PJMEDIA_JB_MISSING_FRAME;
}
/*
* Get jitter buffer state.
*/
PJ_DEF(pj_status_t) pjmedia_jbuf_get_state( pjmedia_jbuf *jb,
pjmedia_jb_state *state )
{
PJ_ASSERT_RETURN(jb && state, PJ_EINVAL);
state->frame_size = jb->jb_frame_size;
state->prefetch = jb->jb_prefetch;
state->min_prefetch = jb->jb_min_prefetch;
state->max_prefetch = jb->jb_max_prefetch;
state->size = jb_framelist_size(&jb->jb_framelist);
return PJ_SUCCESS;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -