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:
Michael Jerris 2007-05-11 21:20:13 +00:00
parent 343d77a408
commit 9c475bb692
4 changed files with 1010 additions and 970 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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;
}

View File

@ -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);