mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-04-28 21:23:44 +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 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 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);
|
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_get_peer_ip(struct iax_session *session);
|
||||||
extern char *iax_event_get_apparent_ip(struct iax_event *event);
|
extern char *iax_event_get_apparent_ip(struct iax_event *event);
|
||||||
extern void iax_set_samplerate(struct iax_session *session, unsigned short samplemask);
|
extern void iax_set_samplerate(struct iax_session *session, unsigned short samplemask);
|
||||||
|
@ -140,6 +140,9 @@ static int netfd = -1;
|
|||||||
/* Max timeouts */
|
/* Max timeouts */
|
||||||
static int maxretries = 10;
|
static int maxretries = 10;
|
||||||
|
|
||||||
|
/* configurable jitterbuffer options */
|
||||||
|
static long jb_target_extra = -1;
|
||||||
|
|
||||||
static int do_shutdown = 0;
|
static int do_shutdown = 0;
|
||||||
|
|
||||||
/* external global networking replacements */
|
/* external global networking replacements */
|
||||||
@ -521,6 +524,7 @@ struct iax_session *iax_session_new(void)
|
|||||||
jbconf.max_jitterbuf = 0;
|
jbconf.max_jitterbuf = 0;
|
||||||
jbconf.resync_threshold = 1000;
|
jbconf.resync_threshold = 1000;
|
||||||
jbconf.max_contig_interp = 0;
|
jbconf.max_contig_interp = 0;
|
||||||
|
jbconf.target_extra = jb_target_extra;
|
||||||
jb_setconf(s->jb, &jbconf);
|
jb_setconf(s->jb, &jbconf);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -944,6 +948,12 @@ int iax_shutdown(void)
|
|||||||
return do_shutdown++;
|
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 iax_init(char *ip, int preferredportno)
|
||||||
{
|
{
|
||||||
int portno = preferredportno;
|
int portno = preferredportno;
|
||||||
|
@ -14,17 +14,19 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "iax2.h"
|
#include "iax2.h"
|
||||||
#include "jitterbuf.h"
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include "jitterbuf.h"
|
||||||
|
|
||||||
/* define these here, just for ancient compiler systems */
|
/* define these here, just for ancient compiler systems */
|
||||||
#define JB_LONGMAX 2147483647L
|
#define JB_LONGMAX 2147483647L
|
||||||
#define JB_LONGMIN (-JB_LONGMAX - 1L)
|
#define JB_LONGMIN (-JB_LONGMAX - 1L)
|
||||||
|
|
||||||
/* MS VC can't do __VA_ARGS__ */
|
/* 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_warn if (warnf) warnf
|
||||||
#define jb_err if (errf) errf
|
#define jb_err if (errf) errf
|
||||||
#define jb_dbg if (dbgf) dbgf
|
#define jb_dbg if (dbgf) dbgf
|
||||||
@ -72,11 +74,11 @@ void jb_reset(jitterbuf *jb)
|
|||||||
{
|
{
|
||||||
/* only save settings */
|
/* only save settings */
|
||||||
jb_conf s = jb->info.conf;
|
jb_conf s = jb->info.conf;
|
||||||
memset(jb,0,sizeof(jitterbuf));
|
memset(jb, 0, sizeof(*jb));
|
||||||
jb->info.conf = s;
|
jb->info.conf = s;
|
||||||
|
|
||||||
/* initialize length */
|
/* initialize length, using the configured value */
|
||||||
jb->info.current = jb->info.target = JB_TARGET_EXTRA;
|
jb->info.current = jb->info.target = jb->info.conf.target_extra;
|
||||||
jb->info.silence_begin_ts = -1;
|
jb->info.silence_begin_ts = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,9 +86,10 @@ jitterbuf * jb_new()
|
|||||||
{
|
{
|
||||||
jitterbuf *jb;
|
jitterbuf *jb;
|
||||||
|
|
||||||
|
if (!(jb = (jitterbuf *)malloc(sizeof(*jb))))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
jb = malloc(sizeof(jitterbuf));
|
jb->info.conf.target_extra = JB_TARGET_EXTRA;
|
||||||
if(!jb) return NULL;
|
|
||||||
|
|
||||||
jb_reset(jb);
|
jb_reset(jb);
|
||||||
|
|
||||||
@ -101,7 +104,7 @@ void jb_destroy(jitterbuf *jb)
|
|||||||
|
|
||||||
/* free all the frames on the "free list" */
|
/* free all the frames on the "free list" */
|
||||||
frame = jb->free;
|
frame = jb->free;
|
||||||
while(frame != NULL) {
|
while (frame != NULL) {
|
||||||
jb_frame *next = frame->next;
|
jb_frame *next = frame->next;
|
||||||
free(frame);
|
free(frame);
|
||||||
frame = next;
|
frame = next;
|
||||||
@ -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
|
#if 0
|
||||||
static int longcmp(const void *a, const void *b)
|
static int longcmp(const void *a, const void *b)
|
||||||
{
|
{
|
||||||
@ -124,6 +123,10 @@ static int longcmp(const void *a, const void *b)
|
|||||||
}
|
}
|
||||||
#endif
|
#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)
|
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);
|
time_in_ms_t delay = now - (ts - jb->info.resync_offset);
|
||||||
@ -156,36 +159,38 @@ 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;
|
jb->history[(jb->hist_ptr++) % JB_HISTORY_SZ] = delay;
|
||||||
|
|
||||||
/* optimization; the max/min buffers don't need to be recalculated, if this packet's
|
/* optimization; the max/min buffers don't need to be recalculated,
|
||||||
* entry doesn't change them. This happens if this packet is not involved, _and_ any packet
|
* if this packet's entry doesn't change them. This happens if this
|
||||||
* that got kicked out of the history is also not involved
|
* packet is not involved, _and_ any packet that got kicked out of
|
||||||
* We do a number of comparisons, but it's probably still worthwhile, because it will usually
|
* the history is also not involved. We do a number of comparisons,
|
||||||
* succeed, and should be a lot faster than going through all 500 packets in history */
|
* but it's probably still worthwhile, because it will usually
|
||||||
if(!jb->hist_maxbuf_valid)
|
* succeed, and should be a lot faster than going through all 500
|
||||||
|
* packets in history */
|
||||||
|
if (!jb->hist_maxbuf_valid)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* don't do this until we've filled history
|
/* don't do this until we've filled history
|
||||||
* (reduces some edge cases below) */
|
* (reduces some edge cases below) */
|
||||||
if(jb->hist_ptr < JB_HISTORY_SZ)
|
if (jb->hist_ptr < JB_HISTORY_SZ)
|
||||||
goto invalidate;
|
goto invalidate;
|
||||||
|
|
||||||
/* if the new delay would go into min */
|
/* if the new delay would go into min */
|
||||||
if(delay < jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1])
|
if (delay < jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1])
|
||||||
goto invalidate;
|
goto invalidate;
|
||||||
|
|
||||||
/* or max.. */
|
/* or max.. */
|
||||||
if(delay > jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1])
|
if (delay > jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1])
|
||||||
goto invalidate;
|
goto invalidate;
|
||||||
|
|
||||||
/* or the kicked delay would be in min */
|
/* or the kicked delay would be in min */
|
||||||
if(kicked <= jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1])
|
if (kicked <= jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1])
|
||||||
goto invalidate;
|
goto invalidate;
|
||||||
|
|
||||||
if(kicked >= jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1])
|
if (kicked >= jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1])
|
||||||
goto invalidate;
|
goto invalidate;
|
||||||
|
|
||||||
/* if we got here, we don't need to invalidate, 'cause this delay didn't
|
/* if we got here, we don't need to invalidate, 'cause this delay didn't
|
||||||
@ -203,12 +208,13 @@ static void history_calc_maxbuf(jitterbuf *jb)
|
|||||||
{
|
{
|
||||||
int i,j;
|
int i,j;
|
||||||
|
|
||||||
if(jb->hist_ptr == 0) return;
|
if (jb->hist_ptr == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
|
||||||
/* initialize maxbuf/minbuf to the latest value */
|
/* initialize maxbuf/minbuf to the latest value */
|
||||||
for(i=0;i<JB_HISTORY_MAXBUF_SZ;i++) {
|
for (i=0;i<JB_HISTORY_MAXBUF_SZ;i++) {
|
||||||
/*
|
/*
|
||||||
* jb->hist_maxbuf[i] = jb->history[(jb->hist_ptr-1) % JB_HISTORY_SZ];
|
* jb->hist_maxbuf[i] = jb->history[(jb->hist_ptr-1) % JB_HISTORY_SZ];
|
||||||
* jb->hist_minbuf[i] = jb->history[(jb->hist_ptr-1) % JB_HISTORY_SZ];
|
* jb->hist_minbuf[i] = jb->history[(jb->hist_ptr-1) % JB_HISTORY_SZ];
|
||||||
*/
|
*/
|
||||||
@ -222,18 +228,18 @@ static void history_calc_maxbuf(jitterbuf *jb)
|
|||||||
/* start at the beginning, or JB_HISTORY_SZ frames ago */
|
/* start at the beginning, or JB_HISTORY_SZ frames ago */
|
||||||
i = (jb->hist_ptr > JB_HISTORY_SZ) ? (jb->hist_ptr - JB_HISTORY_SZ) : 0;
|
i = (jb->hist_ptr > JB_HISTORY_SZ) ? (jb->hist_ptr - JB_HISTORY_SZ) : 0;
|
||||||
|
|
||||||
for(;i<jb->hist_ptr;i++) {
|
for (;i<jb->hist_ptr;i++) {
|
||||||
time_in_ms_t toins = jb->history[i % JB_HISTORY_SZ];
|
time_in_ms_t toins = jb->history[i % JB_HISTORY_SZ];
|
||||||
|
|
||||||
/* if the maxbuf should get this */
|
/* if the maxbuf should get this */
|
||||||
if(toins > jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1]) {
|
if (toins > jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1]) {
|
||||||
|
|
||||||
/* insertion-sort it into the maxbuf */
|
/* insertion-sort it into the maxbuf */
|
||||||
for(j=0;j<JB_HISTORY_MAXBUF_SZ;j++) {
|
for (j=0;j<JB_HISTORY_MAXBUF_SZ;j++) {
|
||||||
/* found where it fits */
|
/* found where it fits */
|
||||||
if(toins > jb->hist_maxbuf[j]) {
|
if (toins > jb->hist_maxbuf[j]) {
|
||||||
/* move over */
|
/* 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 */
|
/* insert */
|
||||||
jb->hist_maxbuf[j] = toins;
|
jb->hist_maxbuf[j] = toins;
|
||||||
|
|
||||||
@ -243,14 +249,14 @@ static void history_calc_maxbuf(jitterbuf *jb)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* if the minbuf should get this */
|
/* if the minbuf should get this */
|
||||||
if(toins < jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1]) {
|
if (toins < jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1]) {
|
||||||
|
|
||||||
/* insertion-sort it into the maxbuf */
|
/* insertion-sort it into the maxbuf */
|
||||||
for(j=0;j<JB_HISTORY_MAXBUF_SZ;j++) {
|
for (j=0;j<JB_HISTORY_MAXBUF_SZ;j++) {
|
||||||
/* found where it fits */
|
/* found where it fits */
|
||||||
if(toins < jb->hist_minbuf[j]) {
|
if (toins < jb->hist_minbuf[j]) {
|
||||||
/* move over */
|
/* 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 */
|
/* insert */
|
||||||
jb->hist_minbuf[j] = toins;
|
jb->hist_minbuf[j] = toins;
|
||||||
|
|
||||||
@ -259,14 +265,14 @@ static void history_calc_maxbuf(jitterbuf *jb)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(0) {
|
if (0) {
|
||||||
int k;
|
int k;
|
||||||
fprintf(stderr, "toins = %ld\n", toins);
|
fprintf(stderr, "toins = %ld\n", toins);
|
||||||
fprintf(stderr, "maxbuf =");
|
fprintf(stderr, "maxbuf =");
|
||||||
for(k=0;k<JB_HISTORY_MAXBUF_SZ;k++)
|
for (k=0;k<JB_HISTORY_MAXBUF_SZ;k++)
|
||||||
fprintf(stderr, "%ld ", jb->hist_maxbuf[k]);
|
fprintf(stderr, "%ld ", jb->hist_maxbuf[k]);
|
||||||
fprintf(stderr, "\nminbuf =");
|
fprintf(stderr, "\nminbuf =");
|
||||||
for(k=0;k<JB_HISTORY_MAXBUF_SZ;k++)
|
for (k=0;k<JB_HISTORY_MAXBUF_SZ;k++)
|
||||||
fprintf(stderr, "%ld ", jb->hist_minbuf[k]);
|
fprintf(stderr, "%ld ", jb->hist_minbuf[k]);
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
}
|
}
|
||||||
@ -281,7 +287,7 @@ static void history_get(jitterbuf *jb)
|
|||||||
int index;
|
int index;
|
||||||
int count;
|
int count;
|
||||||
|
|
||||||
if(!jb->hist_maxbuf_valid)
|
if (!jb->hist_maxbuf_valid)
|
||||||
history_calc_maxbuf(jb);
|
history_calc_maxbuf(jb);
|
||||||
|
|
||||||
/* count is how many items in history we're examining */
|
/* count is how many items in history we're examining */
|
||||||
@ -291,10 +297,11 @@ static void history_get(jitterbuf *jb)
|
|||||||
index = count * JB_HISTORY_DROPPCT / 100;
|
index = count * JB_HISTORY_DROPPCT / 100;
|
||||||
|
|
||||||
/* sanity checks for index */
|
/* 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) {
|
if (index < 0) {
|
||||||
jb->info.min = 0;
|
jb->info.min = 0;
|
||||||
jb->info.jitter = 0;
|
jb->info.jitter = 0;
|
||||||
return;
|
return;
|
||||||
@ -317,21 +324,16 @@ static void history_get(jitterbuf *jb)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* returns 1 if frame was inserted into head of queue, 0 otherwise */
|
/* 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 *frame;
|
||||||
jb_frame *p;
|
jb_frame *p;
|
||||||
int head = 0;
|
int head = 0;
|
||||||
time_in_ms_t resync_ts = ts - jb->info.resync_offset;
|
time_in_ms_t resync_ts = ts - jb->info.resync_offset;
|
||||||
|
|
||||||
frame = jb->free;
|
if ((frame = jb->free)) {
|
||||||
if(frame) {
|
|
||||||
jb->free = frame->next;
|
jb->free = frame->next;
|
||||||
} else {
|
} else if (!(frame = (jb_frame *)malloc(sizeof(*frame)))) {
|
||||||
frame = malloc(sizeof(jb_frame));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!frame) {
|
|
||||||
jb_err("cannot allocate frame\n");
|
jb_err("cannot allocate frame\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -348,7 +350,7 @@ static int queue_put(jitterbuf *jb, void *data, int type, long ms, time_in_ms_t
|
|||||||
* jb->frames->prev points to the highest ts
|
* jb->frames->prev points to the highest ts
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if(!jb->frames) { /* queue is empty */
|
if (!jb->frames) { /* queue is empty */
|
||||||
jb->frames = frame;
|
jb->frames = frame;
|
||||||
frame->next = frame;
|
frame->next = frame;
|
||||||
frame->prev = frame;
|
frame->prev = frame;
|
||||||
@ -369,7 +371,7 @@ static int queue_put(jitterbuf *jb, void *data, int type, long ms, time_in_ms_t
|
|||||||
p = jb->frames;
|
p = jb->frames;
|
||||||
|
|
||||||
/* frame is out of order */
|
/* 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)
|
while (resync_ts < p->prev->ts && p->prev != jb->frames)
|
||||||
p = p->prev;
|
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)
|
static time_in_ms_t queue_next(jitterbuf *jb)
|
||||||
{
|
{
|
||||||
if(jb->frames) return jb->frames->ts;
|
if (jb->frames)
|
||||||
else return -1;
|
return jb->frames->ts;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static time_in_ms_t queue_last(jitterbuf *jb)
|
static time_in_ms_t queue_last(jitterbuf *jb)
|
||||||
{
|
{
|
||||||
if(jb->frames) return jb->frames->prev->ts;
|
if (jb->frames)
|
||||||
else return -1;
|
return jb->frames->prev->ts;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static jb_frame *_queue_get(jitterbuf *jb, time_in_ms_t ts, int all)
|
static jb_frame *_queue_get(jitterbuf *jb, time_in_ms_t ts, int all)
|
||||||
@ -400,17 +406,17 @@ static jb_frame *_queue_get(jitterbuf *jb, time_in_ms_t ts, int all)
|
|||||||
jb_frame *frame;
|
jb_frame *frame;
|
||||||
frame = jb->frames;
|
frame = jb->frames;
|
||||||
|
|
||||||
if(!frame)
|
if (!frame)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/*jb_warn("queue_get: ASK %ld FIRST %ld\n", ts, frame->ts); */
|
/*jb_warn("queue_get: ASK %ld FIRST %ld\n", ts, frame->ts); */
|
||||||
|
|
||||||
if(all || ts >= frame->ts) {
|
if (all || ts >= frame->ts) {
|
||||||
/* remove this frame */
|
/* remove this frame */
|
||||||
frame->prev->next = frame->next;
|
frame->prev->next = frame->next;
|
||||||
frame->next->prev = frame->prev;
|
frame->next->prev = frame->prev;
|
||||||
|
|
||||||
if(frame->next == frame)
|
if (frame->next == frame)
|
||||||
jb->frames = NULL;
|
jb->frames = NULL;
|
||||||
else
|
else
|
||||||
jb->frames = frame->next;
|
jb->frames = frame->next;
|
||||||
@ -444,15 +450,16 @@ static jb_frame *queue_getall(jitterbuf *jb)
|
|||||||
/* some diagnostics */
|
/* some diagnostics */
|
||||||
static void jb_dbginfo(jitterbuf *jb)
|
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_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);
|
jb->info.frames_in, jb->info.frames_out, jb->info.frames_late, jb->info.frames_lost, jb->info.frames_dropped, jb->info.frames_cur);
|
||||||
|
|
||||||
jb_dbg(" jitter=%ld current=%ld target=%ld min=%ld sil=%d len=%d len/fcur=%ld\n",
|
jb_dbg("jitter=%ld current=%ld target=%ld min=%ld sil=%d len=%d len/fcur=%ld\n",
|
||||||
jb->info.jitter, jb->info.current, jb->info.target, jb->info.min, jb->info.silence_begin_ts, jb->info.current - jb->info.min,
|
jb->info.jitter, jb->info.current, jb->info.target, jb->info.min, jb->info.silence_begin_ts, jb->info.current - jb->info.min,
|
||||||
jb->info.frames_cur ? (jb->info.current - jb->info.min)/jb->info.frames_cur : -8);
|
jb->info.frames_cur ? (jb->info.current - jb->info.min)/jb->info.frames_cur : -8);
|
||||||
if(jb->info.frames_in > 0)
|
if (jb->info.frames_in > 0)
|
||||||
jb_dbg("jb info: Loss PCT = %ld%%, Late PCT = %ld%%\n",
|
jb_dbg("jb info: Loss PCT = %ld%%, Late PCT = %ld%%\n",
|
||||||
jb->info.frames_lost * 100/(jb->info.frames_in + jb->info.frames_lost),
|
jb->info.frames_lost * 100/(jb->info.frames_in + jb->info.frames_lost),
|
||||||
jb->info.frames_late * 100/jb->info.frames_in);
|
jb->info.frames_late * 100/jb->info.frames_in);
|
||||||
@ -471,12 +478,12 @@ static void jb_chkqueue(jitterbuf *jb)
|
|||||||
int i=0;
|
int i=0;
|
||||||
jb_frame *p = jb->frames;
|
jb_frame *p = jb->frames;
|
||||||
|
|
||||||
if(!p) {
|
if (!p) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if(p->next == NULL) {
|
if (p->next == NULL) {
|
||||||
jb_err("Queue is BROKEN at item [%d]", i);
|
jb_err("Queue is BROKEN at item [%d]", i);
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
@ -491,7 +498,7 @@ static void jb_dbgqueue(jitterbuf *jb)
|
|||||||
|
|
||||||
jb_dbg("queue: ");
|
jb_dbg("queue: ");
|
||||||
|
|
||||||
if(!p) {
|
if (!p) {
|
||||||
jb_dbg("EMPTY\n");
|
jb_dbg("EMPTY\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -505,15 +512,18 @@ static void jb_dbgqueue(jitterbuf *jb)
|
|||||||
}
|
}
|
||||||
#endif
|
#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_dbg2("jb_put(%x,%x,%ld,%ld,%ld)\n", jb, data, ms, ts, now);
|
||||||
|
|
||||||
jb->info.frames_in++;
|
jb->info.frames_in++;
|
||||||
|
|
||||||
if(type == JB_TYPE_VOICE) {
|
if (type == JB_TYPE_VOICE) {
|
||||||
/* presently, I'm only adding VOICE frames to history and drift calculations; mostly because with the
|
/* presently, I'm only adding VOICE frames to history and drift
|
||||||
* IAX integrations, I'm sending retransmitted control frames with their awkward timestamps through */
|
* 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))
|
if (history_put(jb,ts,now,ms))
|
||||||
return JB_DROP;
|
return JB_DROP;
|
||||||
}
|
}
|
||||||
@ -527,21 +537,21 @@ 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;
|
jb_frame *frame;
|
||||||
time_in_ms_t diff;
|
time_in_ms_t diff;
|
||||||
|
|
||||||
/*if((now - jb_next(jb)) > 2 * jb->info.last_voice_ms) jb_warn("SCHED: %ld", (now - jb_next(jb))); */
|
/*if ((now - jb_next(jb)) > 2 * jb->info.last_voice_ms) jb_warn("SCHED: %ld", (now - jb_next(jb))); */
|
||||||
/* get jitter info */
|
/* get jitter info */
|
||||||
history_get(jb);
|
history_get(jb);
|
||||||
|
|
||||||
|
|
||||||
/* target */
|
/* 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 a hard clamp was requested, use it */
|
||||||
if((jb->info.conf.max_jitterbuf) && ((jb->info.target - jb->info.min) > jb->info.conf.max_jitterbuf)) {
|
if ((jb->info.conf.max_jitterbuf) && ((jb->info.target - jb->info.min) > jb->info.conf.max_jitterbuf)) {
|
||||||
jb_dbg("clamping target from %d to %d\n", (jb->info.target - jb->info.min), jb->info.conf.max_jitterbuf);
|
jb_dbg("clamping target from %d to %d\n", (jb->info.target - jb->info.min), jb->info.conf.max_jitterbuf);
|
||||||
jb->info.target = jb->info.min + jb->info.conf.max_jitterbuf;
|
jb->info.target = jb->info.min + jb->info.conf.max_jitterbuf;
|
||||||
}
|
}
|
||||||
@ -552,32 +562,33 @@ static int _jb_get(jitterbuf *jb, jb_frame *frameout, time_in_ms_t now, long int
|
|||||||
/* jb->info.last_voice_ms, jb->info.last_adjustment, now); */
|
/* jb->info.last_voice_ms, jb->info.last_adjustment, now); */
|
||||||
|
|
||||||
/* let's work on non-silent case first */
|
/* let's work on non-silent case first */
|
||||||
if(!jb->info.silence_begin_ts) {
|
if (!jb->info.silence_begin_ts) {
|
||||||
/* we want to grow */
|
/* we want to grow */
|
||||||
if( (diff > 0) &&
|
if ((diff > 0) &&
|
||||||
/* we haven't grown in the delay length */
|
/* we haven't grown in the delay length */
|
||||||
(((jb->info.last_adjustment + JB_ADJUST_DELAY) < now) ||
|
(((jb->info.last_adjustment + JB_ADJUST_DELAY) < now) ||
|
||||||
/* we need to grow more than the "length" we have left */
|
/* we need to grow more than the "length" we have left */
|
||||||
(diff > queue_last(jb) - queue_next(jb)) ) ) {
|
(diff > queue_last(jb) - queue_next(jb)) ) ) {
|
||||||
/* grow by interp frame len */
|
/* grow by interp frame length */
|
||||||
jb->info.current += interpl;
|
jb->info.current += interpl;
|
||||||
jb->info.next_voice_ts += interpl;
|
jb->info.next_voice_ts += interpl;
|
||||||
jb->info.last_voice_ms = interpl;
|
jb->info.last_voice_ms = interpl;
|
||||||
jb->info.last_adjustment = now;
|
jb->info.last_adjustment = now;
|
||||||
jb->info.cnt_contig_interp++;
|
jb->info.cnt_contig_interp++;
|
||||||
jb_dbg("G");
|
|
||||||
/* assume silence instead of continuing to interpolate */
|
/* 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->info.silence_begin_ts = jb->info.next_voice_ts - jb->info.current;
|
||||||
|
}
|
||||||
|
jb_dbg("G");
|
||||||
return JB_INTERP;
|
return JB_INTERP;
|
||||||
}
|
}
|
||||||
|
|
||||||
frame = queue_get(jb, jb->info.next_voice_ts - jb->info.current);
|
frame = queue_get(jb, jb->info.next_voice_ts - jb->info.current);
|
||||||
|
|
||||||
/* not a voice frame; just return it. */
|
/* not a voice frame; just return it. */
|
||||||
if(frame && frame->type != JB_TYPE_VOICE) {
|
if (frame && frame->type != JB_TYPE_VOICE) {
|
||||||
/* track start of silence */
|
/* track start of silence */
|
||||||
if(frame->type == JB_TYPE_SILENCE) {
|
if (frame->type == JB_TYPE_SILENCE) {
|
||||||
jb->info.silence_begin_ts = frame->ts;
|
jb->info.silence_begin_ts = frame->ts;
|
||||||
jb->info.cnt_contig_interp = 0;
|
jb->info.cnt_contig_interp = 0;
|
||||||
}
|
}
|
||||||
@ -589,7 +600,7 @@ static int _jb_get(jitterbuf *jb, jb_frame *frameout, time_in_ms_t now, long int
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* voice frame is later than expected */
|
/* voice frame is later than expected */
|
||||||
if(frame && frame->ts + jb->info.current < jb->info.next_voice_ts) {
|
if (frame && frame->ts + jb->info.current < jb->info.next_voice_ts) {
|
||||||
if (frame->ts + jb->info.current > jb->info.next_voice_ts - jb->info.last_voice_ms) {
|
if (frame->ts + jb->info.current > jb->info.next_voice_ts - jb->info.last_voice_ms) {
|
||||||
/* either we interpolated past this frame in the last jb_get */
|
/* either we interpolated past this frame in the last jb_get */
|
||||||
/* or the frame is still in order, but came a little too quick */
|
/* or the frame is still in order, but came a little too quick */
|
||||||
@ -616,7 +627,7 @@ static int _jb_get(jitterbuf *jb, jb_frame *frameout, time_in_ms_t now, long int
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* keep track of frame sizes, to allow for variable sized-frames */
|
/* keep track of frame sizes, to allow for variable sized-frames */
|
||||||
if(frame && frame->ms > 0) {
|
if (frame && frame->ms > 0) {
|
||||||
jb->info.last_voice_ms = frame->ms;
|
jb->info.last_voice_ms = frame->ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -624,13 +635,14 @@ 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 */
|
/* unless we don't have a frame, then shrink 1 frame */
|
||||||
/* every 80ms (though perhaps we can shrink even faster */
|
/* every 80ms (though perhaps we can shrink even faster */
|
||||||
/* in this case) */
|
/* in this case) */
|
||||||
if(diff < -JB_TARGET_EXTRA &&
|
if (diff < -jb->info.conf.target_extra &&
|
||||||
((!frame && jb->info.last_adjustment + 80 < now) ||
|
((!frame && jb->info.last_adjustment + 80 < now) ||
|
||||||
(jb->info.last_adjustment + 500 < now))) {
|
(jb->info.last_adjustment + 500 < now))) {
|
||||||
|
|
||||||
jb->info.last_adjustment = now;
|
jb->info.last_adjustment = now;
|
||||||
jb->info.cnt_contig_interp = 0;
|
jb->info.cnt_contig_interp = 0;
|
||||||
|
|
||||||
if(frame) {
|
if (frame) {
|
||||||
*frameout = *frame;
|
*frameout = *frame;
|
||||||
/* shrink by frame size we're throwing out */
|
/* shrink by frame size we're throwing out */
|
||||||
jb->info.current -= frame->ms;
|
jb->info.current -= frame->ms;
|
||||||
@ -650,7 +662,7 @@ static int _jb_get(jitterbuf *jb, jb_frame *frameout, time_in_ms_t now, long int
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* lost frame */
|
/* lost frame */
|
||||||
if(!frame) {
|
if (!frame) {
|
||||||
/* this is a bit of a hack for now, but if we're close to
|
/* this is a bit of a hack for now, but if we're close to
|
||||||
* target, and we find a missing frame, it makes sense to
|
* target, and we find a missing frame, it makes sense to
|
||||||
* grow, because the frame might just be a bit late;
|
* grow, because the frame might just be a bit late;
|
||||||
@ -666,7 +678,7 @@ static int _jb_get(jitterbuf *jb, jb_frame *frameout, time_in_ms_t now, long int
|
|||||||
* But, this still seemed like a good idea, except that it ended up making a single actual
|
* But, this still seemed like a good idea, except that it ended up making a single actual
|
||||||
* lost frame get interpolated two or more times, when there was "room" to grow, so it might
|
* lost frame get interpolated two or more times, when there was "room" to grow, so it might
|
||||||
* be a bit of a bad idea overall */
|
* be a bit of a bad idea overall */
|
||||||
/*if(diff > -1 * jb->info.last_voice_ms) {
|
/*if (diff > -1 * jb->info.last_voice_ms) {
|
||||||
jb->info.current += jb->info.last_voice_ms;
|
jb->info.current += jb->info.last_voice_ms;
|
||||||
jb->info.last_adjustment = now;
|
jb->info.last_adjustment = now;
|
||||||
jb_warn("g");
|
jb_warn("g");
|
||||||
@ -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.last_voice_ms = interpl;
|
||||||
jb->info.cnt_contig_interp++;
|
jb->info.cnt_contig_interp++;
|
||||||
/* assume silence instead of continuing to interpolate */
|
/* 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->info.silence_begin_ts = jb->info.next_voice_ts - jb->info.current;
|
||||||
|
}
|
||||||
jb_dbg("L");
|
jb_dbg("L");
|
||||||
return JB_INTERP;
|
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;
|
*frameout = *frame;
|
||||||
jb->info.next_voice_ts += frame->ms;
|
jb->info.next_voice_ts += frame->ms;
|
||||||
jb->info.frames_out++;
|
jb->info.frames_out++;
|
||||||
decrement_losspct(jb);
|
|
||||||
jb->info.cnt_contig_interp = 0;
|
jb->info.cnt_contig_interp = 0;
|
||||||
|
decrement_losspct(jb);
|
||||||
jb_dbg("v");
|
jb_dbg("v");
|
||||||
return JB_OK;
|
return JB_OK;
|
||||||
} else {
|
} else {
|
||||||
@ -701,14 +714,14 @@ static int _jb_get(jitterbuf *jb, jb_frame *frameout, time_in_ms_t now, long int
|
|||||||
/* jb->info.silence_begin_ts = 0; */
|
/* jb->info.silence_begin_ts = 0; */
|
||||||
|
|
||||||
/* shrink interpl len every 10ms during silence */
|
/* 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.last_adjustment + 10 <= now) {
|
||||||
jb->info.current -= interpl;
|
jb->info.current -= interpl;
|
||||||
jb->info.last_adjustment = now;
|
jb->info.last_adjustment = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
frame = queue_get(jb, now - jb->info.current);
|
frame = queue_get(jb, now - jb->info.current);
|
||||||
if(!frame) {
|
if (!frame) {
|
||||||
return JB_NOFRAME;
|
return JB_NOFRAME;
|
||||||
} else if (frame->type != JB_TYPE_VOICE) {
|
} else if (frame->type != JB_TYPE_VOICE) {
|
||||||
/* normal case; in silent mode, got a non-voice frame */
|
/* normal case; in silent mode, got a non-voice frame */
|
||||||
@ -745,39 +758,41 @@ static int _jb_get(jitterbuf *jb, jb_frame *frameout, time_in_ms_t now, long int
|
|||||||
|
|
||||||
time_in_ms_t jb_next(jitterbuf *jb)
|
time_in_ms_t jb_next(jitterbuf *jb)
|
||||||
{
|
{
|
||||||
if(jb->info.silence_begin_ts) {
|
if (jb->info.silence_begin_ts) {
|
||||||
|
if (jb->frames) {
|
||||||
time_in_ms_t next = queue_next(jb);
|
time_in_ms_t next = queue_next(jb);
|
||||||
if(next > 0) {
|
history_get(jb);
|
||||||
/* shrink during silence */
|
/* 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 jb->info.last_adjustment + 10;
|
||||||
return next + jb->info.target;
|
return next + jb->info.target;
|
||||||
}
|
}
|
||||||
else return JB_LONGMAX;
|
else
|
||||||
|
return JB_LONGMAX;
|
||||||
} else {
|
} else {
|
||||||
return jb->info.next_voice_ts;
|
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
|
#if 0
|
||||||
static int lastts=0;
|
static int lastts=0;
|
||||||
int thists = ((ret == JB_OK) || (ret == JB_DROP)) ? frameout->ts : 0;
|
int thists = ((ret == JB_OK) || (ret == JB_DROP)) ? frameout->ts : 0;
|
||||||
jb_warn("jb_get(%x,%x,%ld) = %d (%d)\n", jb, frameout, now, ret, thists);
|
jb_warn("jb_get(%x,%x,%ld) = %d (%d)\n", jb, frameout, now, ret, thists);
|
||||||
if(thists && thists < lastts) jb_warn("XXXX timestamp roll-back!!!\n");
|
if (thists && thists < lastts) jb_warn("XXXX timestamp roll-back!!!\n");
|
||||||
lastts = thists;
|
lastts = thists;
|
||||||
#endif
|
#endif
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int jb_getall(jitterbuf *jb, jb_frame *frameout)
|
enum jb_return_code jb_getall(jitterbuf *jb, jb_frame *frameout)
|
||||||
{
|
{
|
||||||
jb_frame *frame;
|
jb_frame *frame;
|
||||||
frame = queue_getall(jb);
|
frame = queue_getall(jb);
|
||||||
|
|
||||||
if(!frame) {
|
if (!frame) {
|
||||||
return JB_NOFRAME;
|
return JB_NOFRAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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);
|
history_get(jb);
|
||||||
|
|
||||||
*stats = jb->info;
|
*stats = jb->info;
|
||||||
@ -796,7 +810,7 @@ int jb_getinfo(jitterbuf *jb, jb_info *stats)
|
|||||||
return JB_OK;
|
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 */
|
/* 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.resync_threshold = conf->resync_threshold;
|
||||||
jb->info.conf.max_contig_interp = conf->max_contig_interp;
|
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;
|
return JB_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,27 +35,30 @@ extern "C" {
|
|||||||
/* ms between growing and shrinking; may not be honored if jitterbuffer runs out of space */
|
/* ms between growing and shrinking; may not be honored if jitterbuffer runs out of space */
|
||||||
#define JB_ADJUST_DELAY 40
|
#define JB_ADJUST_DELAY 40
|
||||||
|
|
||||||
|
enum jb_return_code {
|
||||||
|
/* return codes */
|
||||||
|
JB_OK, /* 0 */
|
||||||
|
JB_EMPTY, /* 1 */
|
||||||
|
JB_NOFRAME, /* 2 */
|
||||||
|
JB_INTERP, /* 3 */
|
||||||
|
JB_DROP, /* 4 */
|
||||||
|
JB_SCHED /* 5 */
|
||||||
|
};
|
||||||
|
|
||||||
/* return codes */
|
enum jb_frame_type {
|
||||||
#define JB_OK 0
|
|
||||||
#define JB_EMPTY 1
|
|
||||||
#define JB_NOFRAME 2
|
|
||||||
#define JB_INTERP 3
|
|
||||||
#define JB_DROP 4
|
|
||||||
#define JB_SCHED 5
|
|
||||||
|
|
||||||
/* frame types */
|
/* frame types */
|
||||||
#define JB_TYPE_CONTROL 0
|
JB_TYPE_CONTROL, /* 0 */
|
||||||
#define JB_TYPE_VOICE 1
|
JB_TYPE_VOICE, /* 1 */
|
||||||
#define JB_TYPE_VIDEO 2 /* reserved */
|
JB_TYPE_VIDEO, /* 2 - reserved */
|
||||||
#define JB_TYPE_SILENCE 3
|
JB_TYPE_SILENCE /* 3 */
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct jb_conf {
|
typedef struct jb_conf {
|
||||||
/* settings */
|
/* settings */
|
||||||
long max_jitterbuf; /* defines a hard clamp to use in setting the jitter buffer delay */
|
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 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 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;
|
} jb_conf;
|
||||||
|
|
||||||
typedef struct jb_info {
|
typedef struct jb_info {
|
||||||
@ -88,7 +91,7 @@ typedef struct jb_frame {
|
|||||||
void *data; /* the frame data */
|
void *data; /* the frame data */
|
||||||
time_in_ms_t ts; /* the relative delivery time expected */
|
time_in_ms_t ts; /* the relative delivery time expected */
|
||||||
long ms; /* the time covered by this frame, in sec/8000 */
|
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;
|
struct jb_frame *next, *prev;
|
||||||
} jb_frame;
|
} 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) */
|
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? */
|
int hist_maxbuf_valid; /* are the "maxbuf"/minbuf valid? */
|
||||||
|
|
||||||
|
|
||||||
jb_frame *frames; /* queued frames */
|
jb_frame *frames; /* queued frames */
|
||||||
jb_frame *free; /* free frames (avoid malloc?) */
|
jb_frame *free; /* free frames (avoid malloc?) */
|
||||||
} jitterbuf;
|
} jitterbuf;
|
||||||
|
|
||||||
|
|
||||||
/* new jitterbuf */
|
/* new jitterbuf */
|
||||||
extern jitterbuf * jb_new(void);
|
jitterbuf * jb_new(void);
|
||||||
|
|
||||||
/* destroy jitterbuf */
|
/* destroy jitterbuf */
|
||||||
extern void jb_destroy(jitterbuf *jb);
|
void jb_destroy(jitterbuf *jb);
|
||||||
|
|
||||||
/* reset jitterbuf */
|
/* reset jitterbuf */
|
||||||
/* NOTE: The jitterbuffer should be empty before you call this, otherwise
|
/* NOTE: The jitterbuffer should be empty before you call this, otherwise
|
||||||
* you will leak queued frames, and some internal structures */
|
* 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)
|
/* 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
|
* 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_DROP: Drop this frame immediately
|
||||||
* JB_SCHED: Frame added. Call jb_next() to get a new time for the next frame
|
* 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
|
/* get a frame for time now (receiver's time) return value is one of
|
||||||
* JB_OK: You've got frame!
|
* 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_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.
|
* 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 */
|
/* 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)
|
/* 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) */
|
* 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 */
|
/* 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 */
|
/* 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, ...);
|
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);
|
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