mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-04-14 16:15:04 +00:00
backport change from the iaxclient sf repository rev 648, 649, 650, 656.
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@5158 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
parent
343d77a408
commit
9c475bb692
@ -226,6 +226,10 @@ extern unsigned int iax_session_get_capability(struct iax_session *s);
|
||||
extern char iax_pref_codec_add(struct iax_session *session, unsigned int format);
|
||||
extern void iax_pref_codec_del(struct iax_session *session, unsigned int format);
|
||||
extern int iax_pref_codec_get(struct iax_session *session, unsigned int *array, int len);
|
||||
|
||||
/* Fine tune jitterbuffer */
|
||||
extern void iax_set_jb_target_extra( long value );
|
||||
|
||||
extern char *iax_get_peer_ip(struct iax_session *session);
|
||||
extern char *iax_event_get_apparent_ip(struct iax_event *event);
|
||||
extern void iax_set_samplerate(struct iax_session *session, unsigned short samplemask);
|
||||
|
@ -140,6 +140,9 @@ static int netfd = -1;
|
||||
/* Max timeouts */
|
||||
static int maxretries = 10;
|
||||
|
||||
/* configurable jitterbuffer options */
|
||||
static long jb_target_extra = -1;
|
||||
|
||||
static int do_shutdown = 0;
|
||||
|
||||
/* external global networking replacements */
|
||||
@ -521,6 +524,7 @@ struct iax_session *iax_session_new(void)
|
||||
jbconf.max_jitterbuf = 0;
|
||||
jbconf.resync_threshold = 1000;
|
||||
jbconf.max_contig_interp = 0;
|
||||
jbconf.target_extra = jb_target_extra;
|
||||
jb_setconf(s->jb, &jbconf);
|
||||
}
|
||||
#endif
|
||||
@ -944,6 +948,12 @@ int iax_shutdown(void)
|
||||
return do_shutdown++;
|
||||
}
|
||||
|
||||
void iax_set_jb_target_extra( long value )
|
||||
{
|
||||
/* store in jb_target_extra, a static global */
|
||||
jb_target_extra = value ;
|
||||
}
|
||||
|
||||
int iax_init(char *ip, int preferredportno)
|
||||
{
|
||||
int portno = preferredportno;
|
||||
|
@ -14,17 +14,19 @@
|
||||
*/
|
||||
|
||||
#include "iax2.h"
|
||||
#include "jitterbuf.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "jitterbuf.h"
|
||||
|
||||
/* define these here, just for ancient compiler systems */
|
||||
#define JB_LONGMAX 2147483647L
|
||||
#define JB_LONGMIN (-JB_LONGMAX - 1L)
|
||||
|
||||
/* MS VC can't do __VA_ARGS__ */
|
||||
#if defined(WIN32) && defined(_MSC_VER)
|
||||
#if (defined(WIN32) || defined(_WIN32_WCE)) && defined(_MSC_VER)
|
||||
#define jb_warn if (warnf) warnf
|
||||
#define jb_err if (errf) errf
|
||||
#define jb_dbg if (dbgf) dbgf
|
||||
@ -72,11 +74,11 @@ void jb_reset(jitterbuf *jb)
|
||||
{
|
||||
/* only save settings */
|
||||
jb_conf s = jb->info.conf;
|
||||
memset(jb,0,sizeof(jitterbuf));
|
||||
memset(jb, 0, sizeof(*jb));
|
||||
jb->info.conf = s;
|
||||
|
||||
/* initialize length */
|
||||
jb->info.current = jb->info.target = JB_TARGET_EXTRA;
|
||||
/* initialize length, using the configured value */
|
||||
jb->info.current = jb->info.target = jb->info.conf.target_extra;
|
||||
jb->info.silence_begin_ts = -1;
|
||||
}
|
||||
|
||||
@ -84,9 +86,10 @@ jitterbuf * jb_new()
|
||||
{
|
||||
jitterbuf *jb;
|
||||
|
||||
if (!(jb = (jitterbuf *)malloc(sizeof(*jb))))
|
||||
return NULL;
|
||||
|
||||
jb = malloc(sizeof(jitterbuf));
|
||||
if(!jb) return NULL;
|
||||
jb->info.conf.target_extra = JB_TARGET_EXTRA;
|
||||
|
||||
jb_reset(jb);
|
||||
|
||||
@ -113,10 +116,6 @@ void jb_destroy(jitterbuf *jb)
|
||||
|
||||
|
||||
|
||||
/* simple history manipulation */
|
||||
/* maybe later we can make the history buckets variable size, or something? */
|
||||
/* drop parameter determines whether we will drop outliers to minimize
|
||||
* delay */
|
||||
#if 0
|
||||
static int longcmp(const void *a, const void *b)
|
||||
{
|
||||
@ -124,6 +123,10 @@ static int longcmp(const void *a, const void *b)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* simple history manipulation */
|
||||
/* maybe later we can make the history buckets variable size, or something? */
|
||||
/* drop parameter determines whether we will drop outliers to minimize
|
||||
* delay */
|
||||
static int history_put(jitterbuf *jb, time_in_ms_t ts, time_in_ms_t now, long ms)
|
||||
{
|
||||
time_in_ms_t delay = now - (ts - jb->info.resync_offset);
|
||||
@ -156,15 +159,17 @@ static int history_put(jitterbuf *jb, time_in_ms_t ts, time_in_ms_t now, long ms
|
||||
}
|
||||
}
|
||||
|
||||
kicked = jb->history[jb->hist_ptr & JB_HISTORY_SZ];
|
||||
kicked = jb->history[jb->hist_ptr % JB_HISTORY_SZ];
|
||||
|
||||
jb->history[(jb->hist_ptr++) % JB_HISTORY_SZ] = delay;
|
||||
|
||||
/* optimization; the max/min buffers don't need to be recalculated, if this packet's
|
||||
* entry doesn't change them. This happens if this packet is not involved, _and_ any packet
|
||||
* that got kicked out of the history is also not involved
|
||||
* We do a number of comparisons, but it's probably still worthwhile, because it will usually
|
||||
* succeed, and should be a lot faster than going through all 500 packets in history */
|
||||
/* optimization; the max/min buffers don't need to be recalculated,
|
||||
* if this packet's entry doesn't change them. This happens if this
|
||||
* packet is not involved, _and_ any packet that got kicked out of
|
||||
* the history is also not involved. We do a number of comparisons,
|
||||
* but it's probably still worthwhile, because it will usually
|
||||
* succeed, and should be a lot faster than going through all 500
|
||||
* packets in history */
|
||||
if (!jb->hist_maxbuf_valid)
|
||||
return 0;
|
||||
|
||||
@ -203,7 +208,8 @@ static void history_calc_maxbuf(jitterbuf *jb)
|
||||
{
|
||||
int i,j;
|
||||
|
||||
if(jb->hist_ptr == 0) return;
|
||||
if (jb->hist_ptr == 0)
|
||||
return;
|
||||
|
||||
|
||||
/* initialize maxbuf/minbuf to the latest value */
|
||||
@ -233,7 +239,7 @@ static void history_calc_maxbuf(jitterbuf *jb)
|
||||
/* found where it fits */
|
||||
if (toins > jb->hist_maxbuf[j]) {
|
||||
/* move over */
|
||||
memmove(jb->hist_maxbuf+j+1,jb->hist_maxbuf+j, (JB_HISTORY_MAXBUF_SZ-(j+1)) * sizeof(long));
|
||||
memmove(jb->hist_maxbuf + j + 1, jb->hist_maxbuf + j, (JB_HISTORY_MAXBUF_SZ - (j + 1)) * sizeof(jb->hist_maxbuf[0]));
|
||||
/* insert */
|
||||
jb->hist_maxbuf[j] = toins;
|
||||
|
||||
@ -250,7 +256,7 @@ static void history_calc_maxbuf(jitterbuf *jb)
|
||||
/* found where it fits */
|
||||
if (toins < jb->hist_minbuf[j]) {
|
||||
/* move over */
|
||||
memmove(jb->hist_minbuf+j+1,jb->hist_minbuf+j, (JB_HISTORY_MAXBUF_SZ-(j+1)) * sizeof(long));
|
||||
memmove(jb->hist_minbuf + j + 1, jb->hist_minbuf + j, (JB_HISTORY_MAXBUF_SZ - (j + 1)) * sizeof(jb->hist_minbuf[0]));
|
||||
/* insert */
|
||||
jb->hist_minbuf[j] = toins;
|
||||
|
||||
@ -291,7 +297,8 @@ static void history_get(jitterbuf *jb)
|
||||
index = count * JB_HISTORY_DROPPCT / 100;
|
||||
|
||||
/* sanity checks for index */
|
||||
if(index > (JB_HISTORY_MAXBUF_SZ - 1)) index = JB_HISTORY_MAXBUF_SZ - 1;
|
||||
if (index > (JB_HISTORY_MAXBUF_SZ - 1))
|
||||
index = JB_HISTORY_MAXBUF_SZ - 1;
|
||||
|
||||
|
||||
if (index < 0) {
|
||||
@ -317,21 +324,16 @@ static void history_get(jitterbuf *jb)
|
||||
}
|
||||
|
||||
/* returns 1 if frame was inserted into head of queue, 0 otherwise */
|
||||
static int queue_put(jitterbuf *jb, void *data, int type, long ms, time_in_ms_t ts)
|
||||
static int queue_put(jitterbuf *jb, void *data, const enum jb_frame_type type, long ms, time_in_ms_t ts)
|
||||
{
|
||||
jb_frame *frame;
|
||||
jb_frame *p;
|
||||
int head = 0;
|
||||
time_in_ms_t resync_ts = ts - jb->info.resync_offset;
|
||||
|
||||
frame = jb->free;
|
||||
if(frame) {
|
||||
if ((frame = jb->free)) {
|
||||
jb->free = frame->next;
|
||||
} else {
|
||||
frame = malloc(sizeof(jb_frame));
|
||||
}
|
||||
|
||||
if(!frame) {
|
||||
} else if (!(frame = (jb_frame *)malloc(sizeof(*frame)))) {
|
||||
jb_err("cannot allocate frame\n");
|
||||
return 0;
|
||||
}
|
||||
@ -369,7 +371,7 @@ static int queue_put(jitterbuf *jb, void *data, int type, long ms, time_in_ms_t
|
||||
p = jb->frames;
|
||||
|
||||
/* frame is out of order */
|
||||
if(ts < p->prev->ts) jb->info.frames_ooo++;
|
||||
if (resync_ts < p->prev->ts) jb->info.frames_ooo++;
|
||||
|
||||
while (resync_ts < p->prev->ts && p->prev != jb->frames)
|
||||
p = p->prev;
|
||||
@ -385,14 +387,18 @@ static int queue_put(jitterbuf *jb, void *data, int type, long ms, time_in_ms_t
|
||||
|
||||
static time_in_ms_t queue_next(jitterbuf *jb)
|
||||
{
|
||||
if(jb->frames) return jb->frames->ts;
|
||||
else return -1;
|
||||
if (jb->frames)
|
||||
return jb->frames->ts;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
static time_in_ms_t queue_last(jitterbuf *jb)
|
||||
{
|
||||
if(jb->frames) return jb->frames->prev->ts;
|
||||
else return -1;
|
||||
if (jb->frames)
|
||||
return jb->frames->prev->ts;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
static jb_frame *_queue_get(jitterbuf *jb, time_in_ms_t ts, int all)
|
||||
@ -444,7 +450,8 @@ static jb_frame *queue_getall(jitterbuf *jb)
|
||||
/* some diagnostics */
|
||||
static void jb_dbginfo(jitterbuf *jb)
|
||||
{
|
||||
if(dbgf == NULL) return;
|
||||
if (dbgf == NULL)
|
||||
return;
|
||||
|
||||
jb_dbg("\njb info: fin=%ld fout=%ld flate=%ld flost=%ld fdrop=%ld fcur=%ld\n",
|
||||
jb->info.frames_in, jb->info.frames_out, jb->info.frames_late, jb->info.frames_lost, jb->info.frames_dropped, jb->info.frames_cur);
|
||||
@ -505,15 +512,18 @@ static void jb_dbgqueue(jitterbuf *jb)
|
||||
}
|
||||
#endif
|
||||
|
||||
int jb_put(jitterbuf *jb, void *data, int type, long ms, time_in_ms_t ts, time_in_ms_t now)
|
||||
enum jb_return_code jb_put(jitterbuf *jb, void *data, const enum jb_frame_type type, long ms, time_in_ms_t ts, time_in_ms_t now)
|
||||
{
|
||||
jb_dbg2("jb_put(%x,%x,%ld,%ld,%ld)\n", jb, data, ms, ts, now);
|
||||
|
||||
jb->info.frames_in++;
|
||||
|
||||
if (type == JB_TYPE_VOICE) {
|
||||
/* presently, I'm only adding VOICE frames to history and drift calculations; mostly because with the
|
||||
* IAX integrations, I'm sending retransmitted control frames with their awkward timestamps through */
|
||||
/* presently, I'm only adding VOICE frames to history and drift
|
||||
* calculations; mostly because with the IAX integrations, I'm
|
||||
* sending retransmitted control frames with their awkward
|
||||
* timestamps through
|
||||
*/
|
||||
if (history_put(jb,ts,now,ms))
|
||||
return JB_DROP;
|
||||
}
|
||||
@ -527,7 +537,7 @@ int jb_put(jitterbuf *jb, void *data, int type, long ms, time_in_ms_t ts, time_i
|
||||
}
|
||||
|
||||
|
||||
static int _jb_get(jitterbuf *jb, jb_frame *frameout, time_in_ms_t now, long interpl)
|
||||
static enum jb_return_code _jb_get(jitterbuf *jb, jb_frame *frameout, time_in_ms_t now, long interpl)
|
||||
{
|
||||
jb_frame *frame;
|
||||
time_in_ms_t diff;
|
||||
@ -538,7 +548,7 @@ static int _jb_get(jitterbuf *jb, jb_frame *frameout, time_in_ms_t now, long int
|
||||
|
||||
|
||||
/* target */
|
||||
jb->info.target = jb->info.jitter + jb->info.min + JB_TARGET_EXTRA;
|
||||
jb->info.target = jb->info.jitter + jb->info.min + jb->info.conf.target_extra;
|
||||
|
||||
/* if a hard clamp was requested, use it */
|
||||
if ((jb->info.conf.max_jitterbuf) && ((jb->info.target - jb->info.min) > jb->info.conf.max_jitterbuf)) {
|
||||
@ -559,16 +569,17 @@ static int _jb_get(jitterbuf *jb, jb_frame *frameout, time_in_ms_t now, long int
|
||||
(((jb->info.last_adjustment + JB_ADJUST_DELAY) < now) ||
|
||||
/* we need to grow more than the "length" we have left */
|
||||
(diff > queue_last(jb) - queue_next(jb)) ) ) {
|
||||
/* grow by interp frame len */
|
||||
/* grow by interp frame length */
|
||||
jb->info.current += interpl;
|
||||
jb->info.next_voice_ts += interpl;
|
||||
jb->info.last_voice_ms = interpl;
|
||||
jb->info.last_adjustment = now;
|
||||
jb->info.cnt_contig_interp++;
|
||||
jb_dbg("G");
|
||||
/* assume silence instead of continuing to interpolate */
|
||||
if (jb->info.conf.max_contig_interp && jb->info.cnt_contig_interp >= jb->info.conf.max_contig_interp)
|
||||
if (jb->info.conf.max_contig_interp && jb->info.cnt_contig_interp >= jb->info.conf.max_contig_interp) {
|
||||
jb->info.silence_begin_ts = jb->info.next_voice_ts - jb->info.current;
|
||||
}
|
||||
jb_dbg("G");
|
||||
return JB_INTERP;
|
||||
}
|
||||
|
||||
@ -624,9 +635,10 @@ static int _jb_get(jitterbuf *jb, jb_frame *frameout, time_in_ms_t now, long int
|
||||
/* unless we don't have a frame, then shrink 1 frame */
|
||||
/* every 80ms (though perhaps we can shrink even faster */
|
||||
/* in this case) */
|
||||
if(diff < -JB_TARGET_EXTRA &&
|
||||
if (diff < -jb->info.conf.target_extra &&
|
||||
((!frame && jb->info.last_adjustment + 80 < now) ||
|
||||
(jb->info.last_adjustment + 500 < now))) {
|
||||
|
||||
jb->info.last_adjustment = now;
|
||||
jb->info.cnt_contig_interp = 0;
|
||||
|
||||
@ -678,8 +690,9 @@ static int _jb_get(jitterbuf *jb, jb_frame *frameout, time_in_ms_t now, long int
|
||||
jb->info.last_voice_ms = interpl;
|
||||
jb->info.cnt_contig_interp++;
|
||||
/* assume silence instead of continuing to interpolate */
|
||||
if (jb->info.conf.max_contig_interp && jb->info.cnt_contig_interp >= jb->info.conf.max_contig_interp)
|
||||
if (jb->info.conf.max_contig_interp && jb->info.cnt_contig_interp >= jb->info.conf.max_contig_interp) {
|
||||
jb->info.silence_begin_ts = jb->info.next_voice_ts - jb->info.current;
|
||||
}
|
||||
jb_dbg("L");
|
||||
return JB_INTERP;
|
||||
}
|
||||
@ -688,8 +701,8 @@ static int _jb_get(jitterbuf *jb, jb_frame *frameout, time_in_ms_t now, long int
|
||||
*frameout = *frame;
|
||||
jb->info.next_voice_ts += frame->ms;
|
||||
jb->info.frames_out++;
|
||||
decrement_losspct(jb);
|
||||
jb->info.cnt_contig_interp = 0;
|
||||
decrement_losspct(jb);
|
||||
jb_dbg("v");
|
||||
return JB_OK;
|
||||
} else {
|
||||
@ -701,7 +714,7 @@ static int _jb_get(jitterbuf *jb, jb_frame *frameout, time_in_ms_t now, long int
|
||||
/* jb->info.silence_begin_ts = 0; */
|
||||
|
||||
/* shrink interpl len every 10ms during silence */
|
||||
if (diff < -JB_TARGET_EXTRA &&
|
||||
if (diff < -jb->info.conf.target_extra &&
|
||||
jb->info.last_adjustment + 10 <= now) {
|
||||
jb->info.current -= interpl;
|
||||
jb->info.last_adjustment = now;
|
||||
@ -746,22 +759,24 @@ static int _jb_get(jitterbuf *jb, jb_frame *frameout, time_in_ms_t now, long int
|
||||
time_in_ms_t jb_next(jitterbuf *jb)
|
||||
{
|
||||
if (jb->info.silence_begin_ts) {
|
||||
if (jb->frames) {
|
||||
time_in_ms_t next = queue_next(jb);
|
||||
if(next > 0) {
|
||||
history_get(jb);
|
||||
/* shrink during silence */
|
||||
if (jb->info.target - jb->info.current < -JB_TARGET_EXTRA)
|
||||
if (jb->info.target - jb->info.current < -jb->info.conf.target_extra)
|
||||
return jb->info.last_adjustment + 10;
|
||||
return next + jb->info.target;
|
||||
}
|
||||
else return JB_LONGMAX;
|
||||
else
|
||||
return JB_LONGMAX;
|
||||
} else {
|
||||
return jb->info.next_voice_ts;
|
||||
}
|
||||
}
|
||||
|
||||
int jb_get(jitterbuf *jb, jb_frame *frameout, time_in_ms_t now, long interpl)
|
||||
enum jb_return_code jb_get(jitterbuf *jb, jb_frame *frameout, time_in_ms_t now, long interpl)
|
||||
{
|
||||
int ret = _jb_get(jb,frameout,now,interpl);
|
||||
enum jb_return_code ret = _jb_get(jb, frameout, now, interpl);
|
||||
#if 0
|
||||
static int lastts=0;
|
||||
int thists = ((ret == JB_OK) || (ret == JB_DROP)) ? frameout->ts : 0;
|
||||
@ -772,7 +787,7 @@ int jb_get(jitterbuf *jb, jb_frame *frameout, time_in_ms_t now, long interpl)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int jb_getall(jitterbuf *jb, jb_frame *frameout)
|
||||
enum jb_return_code jb_getall(jitterbuf *jb, jb_frame *frameout)
|
||||
{
|
||||
jb_frame *frame;
|
||||
frame = queue_getall(jb);
|
||||
@ -786,9 +801,8 @@ int jb_getall(jitterbuf *jb, jb_frame *frameout)
|
||||
}
|
||||
|
||||
|
||||
int jb_getinfo(jitterbuf *jb, jb_info *stats)
|
||||
enum jb_return_code jb_getinfo(jitterbuf *jb, jb_info *stats)
|
||||
{
|
||||
|
||||
history_get(jb);
|
||||
|
||||
*stats = jb->info;
|
||||
@ -796,7 +810,7 @@ int jb_getinfo(jitterbuf *jb, jb_info *stats)
|
||||
return JB_OK;
|
||||
}
|
||||
|
||||
int jb_setconf(jitterbuf *jb, jb_conf *conf)
|
||||
enum jb_return_code jb_setconf(jitterbuf *jb, jb_conf *conf)
|
||||
{
|
||||
/* take selected settings from the struct */
|
||||
|
||||
@ -804,6 +818,16 @@ int jb_setconf(jitterbuf *jb, jb_conf *conf)
|
||||
jb->info.conf.resync_threshold = conf->resync_threshold;
|
||||
jb->info.conf.max_contig_interp = conf->max_contig_interp;
|
||||
|
||||
/* -1 indicates use of the default JB_TARGET_EXTRA value */
|
||||
jb->info.conf.target_extra = ( conf->target_extra == -1 )
|
||||
? JB_TARGET_EXTRA
|
||||
: conf->target_extra
|
||||
;
|
||||
|
||||
/* update these to match new target_extra setting */
|
||||
jb->info.current = jb->info.conf.target_extra;
|
||||
jb->info.target = jb->info.conf.target_extra;
|
||||
|
||||
return JB_OK;
|
||||
}
|
||||
|
||||
|
@ -35,27 +35,30 @@ extern "C" {
|
||||
/* ms between growing and shrinking; may not be honored if jitterbuffer runs out of space */
|
||||
#define JB_ADJUST_DELAY 40
|
||||
|
||||
|
||||
enum jb_return_code {
|
||||
/* return codes */
|
||||
#define JB_OK 0
|
||||
#define JB_EMPTY 1
|
||||
#define JB_NOFRAME 2
|
||||
#define JB_INTERP 3
|
||||
#define JB_DROP 4
|
||||
#define JB_SCHED 5
|
||||
JB_OK, /* 0 */
|
||||
JB_EMPTY, /* 1 */
|
||||
JB_NOFRAME, /* 2 */
|
||||
JB_INTERP, /* 3 */
|
||||
JB_DROP, /* 4 */
|
||||
JB_SCHED /* 5 */
|
||||
};
|
||||
|
||||
enum jb_frame_type {
|
||||
/* frame types */
|
||||
#define JB_TYPE_CONTROL 0
|
||||
#define JB_TYPE_VOICE 1
|
||||
#define JB_TYPE_VIDEO 2 /* reserved */
|
||||
#define JB_TYPE_SILENCE 3
|
||||
|
||||
JB_TYPE_CONTROL, /* 0 */
|
||||
JB_TYPE_VOICE, /* 1 */
|
||||
JB_TYPE_VIDEO, /* 2 - reserved */
|
||||
JB_TYPE_SILENCE /* 3 */
|
||||
};
|
||||
|
||||
typedef struct jb_conf {
|
||||
/* settings */
|
||||
long max_jitterbuf; /* defines a hard clamp to use in setting the jitter buffer delay */
|
||||
long resync_threshold; /* the jb will resync when delay increases to (2 * jitter) + this param */
|
||||
long max_contig_interp; /* the max interp frames to return in a row */
|
||||
long target_extra; /* amount of additional jitterbuffer adjustment, overrides JB_TARGET_EXTRA */
|
||||
} jb_conf;
|
||||
|
||||
typedef struct jb_info {
|
||||
@ -88,7 +91,7 @@ typedef struct jb_frame {
|
||||
void *data; /* the frame data */
|
||||
time_in_ms_t ts; /* the relative delivery time expected */
|
||||
long ms; /* the time covered by this frame, in sec/8000 */
|
||||
int type; /* the type of frame */
|
||||
enum jb_frame_type type; /* the type of frame */
|
||||
struct jb_frame *next, *prev;
|
||||
} jb_frame;
|
||||
|
||||
@ -102,22 +105,21 @@ typedef struct jitterbuf {
|
||||
time_in_ms_t hist_minbuf[JB_HISTORY_MAXBUF_SZ]; /* a sorted buffer of the min delays (lowest first) */
|
||||
int hist_maxbuf_valid; /* are the "maxbuf"/minbuf valid? */
|
||||
|
||||
|
||||
jb_frame *frames; /* queued frames */
|
||||
jb_frame *free; /* free frames (avoid malloc?) */
|
||||
} jitterbuf;
|
||||
|
||||
|
||||
/* new jitterbuf */
|
||||
extern jitterbuf * jb_new(void);
|
||||
jitterbuf * jb_new(void);
|
||||
|
||||
/* destroy jitterbuf */
|
||||
extern void jb_destroy(jitterbuf *jb);
|
||||
void jb_destroy(jitterbuf *jb);
|
||||
|
||||
/* reset jitterbuf */
|
||||
/* NOTE: The jitterbuffer should be empty before you call this, otherwise
|
||||
* you will leak queued frames, and some internal structures */
|
||||
extern void jb_reset(jitterbuf *jb);
|
||||
void jb_reset(jitterbuf *jb);
|
||||
|
||||
/* queue a frame data=frame data, timings (in ms): ms=length of frame (for voice), ts=ts (sender's time)
|
||||
* now=now (in receiver's time) return value is one of
|
||||
@ -125,7 +127,7 @@ extern void jb_reset(jitterbuf *jb);
|
||||
* JB_DROP: Drop this frame immediately
|
||||
* JB_SCHED: Frame added. Call jb_next() to get a new time for the next frame
|
||||
*/
|
||||
extern int jb_put(jitterbuf *jb, void *data, int type, long ms, time_in_ms_t ts, time_in_ms_t now);
|
||||
enum jb_return_code jb_put(jitterbuf *jb, void *data, const enum jb_frame_type type, long ms, time_in_ms_t ts, time_in_ms_t now);
|
||||
|
||||
/* get a frame for time now (receiver's time) return value is one of
|
||||
* JB_OK: You've got frame!
|
||||
@ -134,20 +136,20 @@ extern int jb_put(jitterbuf *jb, void *data, int type, long ms, time_in_ms_t
|
||||
* JB_INTERP: Please interpolate an interpl-length frame for this time (either we need to grow, or there was a lost frame)
|
||||
* JB_EMPTY: The jb is empty.
|
||||
*/
|
||||
extern int jb_get(jitterbuf *jb, jb_frame *frame, time_in_ms_t now, long interpl);
|
||||
enum jb_return_code jb_get(jitterbuf *jb, jb_frame *frame, time_in_ms_t now, long interpl);
|
||||
|
||||
/* unconditionally get frames from jitterbuf until empty */
|
||||
extern int jb_getall(jitterbuf *jb, jb_frame *frameout);
|
||||
enum jb_return_code jb_getall(jitterbuf *jb, jb_frame *frameout);
|
||||
|
||||
/* when is the next frame due out, in receiver's time (0=EMPTY)
|
||||
* This value may change as frames are added (esp non-audio frames) */
|
||||
extern time_in_ms_t jb_next(jitterbuf *jb);
|
||||
time_in_ms_t jb_next(jitterbuf *jb);
|
||||
|
||||
/* get jitterbuf info: only "statistics" may be valid */
|
||||
extern int jb_getinfo(jitterbuf *jb, jb_info *stats);
|
||||
enum jb_return_code jb_getinfo(jitterbuf *jb, jb_info *stats);
|
||||
|
||||
/* set jitterbuf conf */
|
||||
extern int jb_setconf(jitterbuf *jb, jb_conf *conf);
|
||||
enum jb_return_code jb_setconf(jitterbuf *jb, jb_conf *conf);
|
||||
|
||||
typedef void (*jb_output_function_t)(const char *fmt, ...);
|
||||
extern void jb_setoutput(jb_output_function_t err, jb_output_function_t warn, jb_output_function_t dbg);
|
||||
|
Loading…
x
Reference in New Issue
Block a user