📄 jbuf.c
字号:
/* $Id: jbuf.c 1266 2007-05-11 15:14:34Z bennylp $ */
/*
* Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Based on implementation kindly contributed by Switchlab, Ltd.
*/
#include <pjmedia/jbuf.h>
#include <pjmedia/errno.h>
#include <pj/pool.h>
#include <pj/assert.h>
#include <pj/log.h>
#include <pj/string.h>
#define THIS_FILE "jbuf.c"
typedef struct jb_framelist_t
{
char *flist_buffer;
int *flist_frame_type;
unsigned flist_frame_size;
unsigned flist_max_count;
unsigned flist_empty;
unsigned flist_head;
unsigned flist_tail;
unsigned flist_origin;
} 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_last_level; // last delay
int jb_last_jitter; // last jitter calculated
int jb_max_hist_jitter; // max jitter during the last jitter calculations
int jb_stable_hist; // num of times the delay has been lower then the prefetch num
unsigned jb_op_count; // of of operations.
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_min_prefetch; // Minimum allowable prefetch
int jb_max_prefetch; // Maximum allowable prefetch
int jb_status; // status is 'init' until the first 'put' operation
};
#define JB_STATUS_INITIALIZING 0
#define JB_STATUS_PROCESSING 1
#define PJ_ABS(x) ((x > 0) ? (x) : -(x))
#define PJ_MAX(x, y) ((x > y) ? (x) : (y))
#define PJ_MIN(x, y) ((x < y) ? (x) : (y))
/* Enabling this would log the jitter buffer state about once per
* second.
*/
#if 0
# define TRACE__(args) PJ_LOG(4,args)
#else
# define TRACE__(args)
#endif
static pj_status_t jb_framelist_init( pj_pool_t *pool,
jb_framelist_t *framelist,
unsigned frame_size,
unsigned max_count)
{
PJ_ASSERT_RETURN(pool && framelist, PJ_EINVAL);
pj_bzero(framelist, sizeof(jb_framelist_t));
framelist->flist_frame_size = frame_size;
framelist->flist_max_count = max_count;
framelist->flist_buffer = (char*)
pj_pool_zalloc(pool,
framelist->flist_frame_size *
framelist->flist_max_count);
framelist->flist_frame_type = (int*)
pj_pool_zalloc(pool, sizeof(framelist->flist_frame_type[0]) *
framelist->flist_max_count);
framelist->flist_empty = 1;
return PJ_SUCCESS;
}
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;
}
}
static pj_bool_t jb_framelist_get(jb_framelist_t *framelist,
void *frame,
pjmedia_jb_frame_type *p_type)
{
if (!framelist->flist_empty) {
pj_memcpy(frame,
framelist->flist_buffer +
framelist->flist_head * framelist->flist_frame_size,
framelist->flist_frame_size);
*p_type = (pjmedia_jb_frame_type)
framelist->flist_frame_type[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_origin++;
framelist->flist_head = (framelist->flist_head + 1 ) %
framelist->flist_max_count;
if (framelist->flist_head == framelist->flist_tail)
framelist->flist_empty = PJ_TRUE;
return PJ_TRUE;
} else {
pj_bzero(frame, framelist->flist_frame_size);
return PJ_FALSE;
}
}
static void jb_framelist_remove_head( jb_framelist_t *framelist,
unsigned count)
{
unsigned cur_size;
cur_size = jb_framelist_size(framelist);
if (count > cur_size)
count = cur_size;
if (count) {
// may be done in two steps if overlapping
unsigned step1,step2;
unsigned tmp = framelist->flist_head+count;
if (tmp > framelist->flist_max_count) {
step1 = framelist->flist_max_count - framelist->flist_head;
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,
PJMEDIA_JB_MISSING_FRAME,
step1*sizeof(framelist->flist_frame_type[0]));
if (step2) {
pj_bzero( framelist->flist_buffer,
step2*framelist->flist_frame_size);
pj_memset(framelist->flist_frame_type,
PJMEDIA_JB_MISSING_FRAME,
step2*sizeof(framelist->flist_frame_type[0]));
}
// update pointers
framelist->flist_origin += count;
framelist->flist_head = (framelist->flist_head + count) %
framelist->flist_max_count;
if (framelist->flist_head == framelist->flist_tail)
framelist->flist_empty = PJ_TRUE;
}
}
static pj_bool_t jb_framelist_put_at(jb_framelist_t *framelist,
unsigned index,
const void *frame,
unsigned frame_size)
{
unsigned where;
assert(frame_size <= framelist->flist_frame_size);
if (!framelist->flist_empty) {
unsigned max_index;
unsigned cur_size;
// too late
if (index < framelist->flist_origin)
return PJ_FALSE;
// too soon
max_index = framelist->flist_origin + framelist->flist_max_count - 1;
if (index > max_index)
return PJ_FALSE;
where = (index - framelist->flist_origin + framelist->flist_head) %
framelist->flist_max_count;
// update framelist->flist_tail pointer
cur_size = jb_framelist_size(framelist);
if (index >= framelist->flist_origin + cur_size) {
unsigned diff = (index - (framelist->flist_origin + cur_size));
framelist->flist_tail = (framelist->flist_tail + diff + 1) %
framelist->flist_max_count;
}
} else {
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);
framelist->flist_frame_type[where] = PJMEDIA_JB_NORMAL_FRAME;
return PJ_TRUE;
}
enum pjmedia_jb_op
{
JB_OP_INIT = -1,
JB_OP_PUT = 1,
JB_OP_GET = 2
};
PJ_DEF(pj_status_t) pjmedia_jbuf_create(pj_pool_t *pool,
const pj_str_t *name,
unsigned frame_size,
unsigned ptime,
unsigned max_count,
pjmedia_jbuf **p_jb)
{
pjmedia_jbuf *jb;
pj_status_t status;
jb = PJ_POOL_ZALLOC_T(pool, pjmedia_jbuf);
status = jb_framelist_init(pool, &jb->jb_framelist, frame_size, max_count);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -