Skip to content
This repository has been archived by the owner on Jan 14, 2020. It is now read-only.

Commit

Permalink
Add support for using a jitterbuffer for RTP on bridged calls. This i…
Browse files Browse the repository at this point in the history
…ncludes

a new implementation of a fixed size jitterbuffer, as well as support for the
existing adaptive jitterbuffer implementation. (issue #3854, Slav Klenov)

Thank you very much to Slav Klenov of Securax and all of the people involved
in the testing of this feature for all of your hard work!


git-svn-id: http://svn.asterisk.org/svn/asterisk/trunk@31052 f38db490-d61c-443f-a65b-d21fe96a405b
  • Loading branch information
russellb committed May 31, 2006
1 parent d5d491f commit 9953ec3
Show file tree
Hide file tree
Showing 20 changed files with 983 additions and 20 deletions.
2 changes: 1 addition & 1 deletion .cleancount
Original file line number Diff line number Diff line change
@@ -1 +1 @@
17
18
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ OBJS=io.o sched.o logger.o frame.o loader.o config.o channel.o \
astmm.o enum.o srv.o dns.o aescrypt.o aestab.o aeskey.o \
utils.o plc.o jitterbuf.o dnsmgr.o devicestate.o \
netsock.o slinfactory.o ast_expr2.o ast_expr2f.o \
cryptostub.o sha1.o http.o
cryptostub.o sha1.o http.o scx_jitterbuf.o abstract_jb.o

# we need to link in the objects statically, not as a library, because
# otherwise modules will not have them available if none of the static
Expand Down
29 changes: 26 additions & 3 deletions channel.c
Original file line number Diff line number Diff line change
Expand Up @@ -1012,6 +1012,9 @@ void ast_channel_free(struct ast_channel *chan)
while ((vardata = AST_LIST_REMOVE_HEAD(headp, entries)))
ast_var_delete(vardata);

/* Destroy the jitterbuffer */
ast_jb_destroy(chan);

ast_string_field_free_all(chan);
free(chan);
AST_LIST_UNLOCK(&channels);
Expand Down Expand Up @@ -3303,6 +3306,9 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct
int watch_c0_dtmf;
int watch_c1_dtmf;
void *pvt0, *pvt1;
/* Indicates whether a frame was queued into a jitterbuffer */
int frame_put_in_jb = 0;
int jb_in_use;
int to;

cs[0] = c0;
Expand All @@ -3314,6 +3320,9 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct
watch_c0_dtmf = config->flags & AST_BRIDGE_DTMF_CHANNEL_0;
watch_c1_dtmf = config->flags & AST_BRIDGE_DTMF_CHANNEL_1;

/* Check the need of a jitterbuffer for each channel */
jb_in_use = ast_jb_do_usecheck(c0, c1);

for (;;) {
struct ast_channel *who, *other;

Expand All @@ -3332,9 +3341,15 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct
}
} else
to = -1;
/* Calculate the appropriate max sleep interval - in general, this is the time,
left to the closest jb delivery moment */
if (jb_in_use)
to = ast_jb_get_when_to_wakeup(c0, c1, to);
who = ast_waitfor_n(cs, 2, &to);
if (!who) {
ast_log(LOG_DEBUG, "Nobody there, continuing...\n");
/* No frame received within the specified timeout - check if we have to deliver now */
if (jb_in_use)
ast_jb_get_and_deliver(c0, c1);
if (c0->_softhangup == AST_SOFTHANGUP_UNBRIDGE || c1->_softhangup == AST_SOFTHANGUP_UNBRIDGE) {
if (c0->_softhangup == AST_SOFTHANGUP_UNBRIDGE)
c0->_softhangup = 0;
Expand All @@ -3354,6 +3369,9 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct
}

other = (who == c0) ? c1 : c0; /* the 'other' channel */
/* Try add the frame info the who's bridged channel jitterbuff */
if (jb_in_use)
frame_put_in_jb = !ast_jb_put(other, f);

if ((f->frametype == AST_FRAME_CONTROL) && !(config->flags & AST_BRIDGE_IGNORE_SIGS)) {
int bridge_exit = 0;
Expand Down Expand Up @@ -3390,8 +3408,13 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct
ast_log(LOG_DEBUG, "Got DTMF on channel (%s)\n", who->name);
break;
}
/* other frames go to the other side */
ast_write(other, f);
/* Write immediately frames, not passed through jb */
if (!frame_put_in_jb)
ast_write(other, f);

/* Check if we have to deliver now */
if (jb_in_use)
ast_jb_get_and_deliver(c0, c1);
}
/* XXX do we want to pass on also frames not matched above ? */
ast_frfree(f);
Expand Down
22 changes: 22 additions & 0 deletions channels/chan_alsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,17 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "alsa-monitor.h"
#endif

#include "asterisk/abstract_jb.h"
/* Global jitterbuffer configuration - by default, jb is disabled */
static struct ast_jb_conf default_jbconf =
{
.flags = 0,
.max_size = -1,
.resync_threshold = -1,
.impl = ""
};
static struct ast_jb_conf global_jbconf;

#define DEBUG 0
/* Which device to use */
#define ALSA_INDEV "hw:0,0"
Expand Down Expand Up @@ -812,6 +823,8 @@ static struct ast_channel *alsa_new(struct chan_alsa_pvt *p, int state)
tmp = NULL;
}
}
if (tmp)
ast_jb_configure(tmp, &global_jbconf);
}
return tmp;
}
Expand Down Expand Up @@ -1051,9 +1064,18 @@ static int load_module(void *mod)
int x;
struct ast_config *cfg;
struct ast_variable *v;

/* Copy the default jb config over global_jbconf */
memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));

if ((cfg = ast_config_load(config))) {
v = ast_variable_browse(cfg, "general");
while(v) {
/* handle jb conf */
if (!ast_jb_read_conf(&global_jbconf, v->name, v->value)) {
v = v->next;
continue;
}
if (!strcasecmp(v->name, "autoanswer"))
autoanswer = ast_true(v->value);
else if (!strcasecmp(v->name, "silencesuppression"))
Expand Down
1 change: 1 addition & 0 deletions channels/chan_iax2.c
Original file line number Diff line number Diff line change
Expand Up @@ -1543,6 +1543,7 @@ static int __do_deliver(void *data)
the IAX thread with the iaxsl lock held. */
struct iax_frame *fr = data;
fr->retrans = -1;
fr->af.has_timing_info = 0;
if (iaxs[fr->callno] && !ast_test_flag(iaxs[fr->callno], IAX_ALREADYGONE))
iax2_queue_frame(fr->callno, &fr->af);
/* Free our iax frame */
Expand Down
48 changes: 48 additions & 0 deletions channels/chan_oss.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,17 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "ring10.h"
#include "answer.h"

#include "asterisk/abstract_jb.h"
/* Global jitterbuffer configuration - by default, jb is disabled */
static struct ast_jb_conf default_jbconf =
{
.flags = 0,
.max_size = -1,
.resync_threshold = -1,
.impl = ""
};
static struct ast_jb_conf global_jbconf;

/*
* Basic mode of operation:
*
Expand Down Expand Up @@ -141,6 +152,33 @@ START_CONFIG
; queuesize = 10 ; frames in device driver
; frags = 8 ; argument to SETFRAGMENT
;------------------------------ JITTER BUFFER CONFIGURATION --------------------------
; jbenable = yes ; Enables the use of a jitterbuffer on the receiving side of an
; OSS channel. Defaults to "no". An enabled jitterbuffer will
; be used only if the sending side can create and the receiving
; side can not accept jitter. The ZAP channel can't accept jitter,
; thus an enabled jitterbuffer on the receive ZAP side will always
; be used if the sending side can create jitter or if ZAP jb is
; forced.
; jbforce = no ; Forces the use of a jitterbuffer on the receive side of a ZAP
; channel. Defaults to "no".
; jbmaxsize = 200 ; Max length of the jitterbuffer in milliseconds.
; jbresyncthreshold = 1000 ; Jump in the frame timestamps over which the jitterbuffer is
; resynchronized. Useful to improve the quality of the voice, with
; big jumps in/broken timestamps, usualy sent from exotic devices
; and programs. Defaults to 1000.
; jbimpl = fixed ; Jitterbuffer implementation, used on the receiving side of a SIP
; channel. Two implementation are currenlty available - "fixed"
; (with size always equals to jbmax-size) and "adaptive" (with
; variable size, actually the new jb of IAX2). Defaults to fixed.
; jblog = no ; Enables jitterbuffer frame logging. Defaults to "no".
;-----------------------------------------------------------------------------------
[card1]
; device = /dev/dsp1 ; alternate device
Expand Down Expand Up @@ -981,6 +1019,9 @@ static struct ast_channel *oss_new(struct chan_oss_pvt *o,
/* XXX what about usecnt ? */
}
}
if (c)
ast_jb_configure(c, &global_jbconf);

return c;
}

Expand Down Expand Up @@ -1407,6 +1448,10 @@ static struct chan_oss_pvt * store_config(struct ast_config *cfg, char *ctg)
for (v = ast_variable_browse(cfg, ctg);v; v=v->next) {
M_START(v->name, v->value);

/* handle jb conf */
if (!ast_jb_read_conf(&global_jbconf, v->name, v->value))
continue;

M_BOOL("autoanswer", o->autoanswer)
M_BOOL("autohangup", o->autohangup)
M_BOOL("overridecontext", o->overridecontext)
Expand Down Expand Up @@ -1472,6 +1517,9 @@ static int load_module(void *mod)
int i;
struct ast_config *cfg;

/* Copy the default jb config over global_jbconf */
memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));

/* load config file */
cfg = ast_config_load(config);
if (cfg != NULL) {
Expand Down
31 changes: 28 additions & 3 deletions channels/chan_sip.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,17 @@ static int expiry = DEFAULT_EXPIRY;

#define INITIAL_CSEQ 101 /*!< our initial sip sequence number */

#include "asterisk/abstract_jb.h"
/* Global jitterbuffer configuration - by default, jb is disabled */
static struct ast_jb_conf default_jbconf =
{
.flags = 0,
.max_size = -1,
.resync_threshold = -1,
.impl = ""
};
static struct ast_jb_conf global_jbconf;

static const char tdesc[] = "Session Initiation Protocol (SIP)";
static const char config[] = "sip.conf";
static const char notify_config[] = "sip_notify.conf";
Expand Down Expand Up @@ -850,6 +861,7 @@ static struct sip_pvt {
struct ast_variable *chanvars; /*!< Channel variables to set for inbound call */
struct sip_pvt *next; /*!< Next dialog in chain */
struct sip_invite_param *options; /*!< Options for INVITE */
struct ast_jb_conf jbconf;
} *iflist = NULL;

#define FLAG_RESPONSE (1 << 0)
Expand Down Expand Up @@ -1256,7 +1268,7 @@ static const struct ast_channel_tech sip_tech = {
.type = "SIP",
.description = "Session Initiation Protocol (SIP)",
.capabilities = ((AST_FORMAT_MAX_AUDIO << 1) - 1),
.properties = AST_CHAN_TP_WANTSJITTER,
.properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER,
.requester = sip_request_call,
.devicestate = sip_devicestate,
.call = sip_call,
Expand Down Expand Up @@ -3312,7 +3324,11 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit

if (recordhistory)
append_history(i, "NewChan", "Channel %s - from %s", tmp->name, i->callid);


/* Configure the new channel jb */
if (tmp && i && i->rtp)
ast_jb_configure(tmp, &i->jbconf);

return tmp;
}

Expand Down Expand Up @@ -3647,6 +3663,9 @@ static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *si
p->noncodeccapability |= AST_RTP_DTMF;
ast_string_field_set(p, context, default_context);

/* Assign default jb conf to the new sip_pvt */
memcpy(&p->jbconf, &global_jbconf, sizeof(struct ast_jb_conf));

/* Add to active dialog list */
ast_mutex_lock(&iflock);
p->next = iflist;
Expand Down Expand Up @@ -13247,7 +13266,6 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, int
for (; v; v = v->next) {
if (handle_common_options(&peerflags[0], &mask[0], v))
continue;

if (realtime && !strcasecmp(v->name, "regseconds")) {
ast_get_time_t(v->value, &regseconds, 0, NULL);
} else if (realtime && !strcasecmp(v->name, "ipaddr") && !ast_strlen_zero(v->value) ) {
Expand Down Expand Up @@ -13540,12 +13558,19 @@ static int reload_config(enum channelreloadreason reason)
global_relaxdtmf = FALSE;
global_callevents = FALSE;
global_t1min = DEFAULT_T1MIN;

/* Copy the default jb config over global_jbconf */
memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));

ast_clear_flag(&global_flags[1], SIP_PAGE2_VIDEOSUPPORT);

/* Read the [general] config section of sip.conf (or from realtime config) */
for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
if (handle_common_options(&global_flags[0], &dummy[0], v))
continue;
/* handle jb conf */
if (!ast_jb_read_conf(&global_jbconf, v->name, v->value))
continue;

/* Create the interface list */
if (!strcasecmp(v->name, "context")) {
Expand Down
23 changes: 23 additions & 0 deletions channels/chan_zap.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,17 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#define SMDI_MD_WAIT_TIMEOUT 1500 /* 1.5 seconds */
#endif

#include "asterisk/abstract_jb.h"
/* Global jitterbuffer configuration - by default, jb is disabled */
static struct ast_jb_conf default_jbconf =
{
.flags = 0,
.max_size = -1,
.resync_threshold = -1,
.impl = ""
};
static struct ast_jb_conf global_jbconf;

#if !defined(ZT_SIG_EM_E1) || (defined(HAVE_LIBPRI) && !defined(ZT_SIG_HARDHDLC))
#error "Your zaptel is too old. please update"
#endif
Expand Down Expand Up @@ -684,6 +695,7 @@ static struct zt_pvt {
#endif
int polarity;
int dsp_features;
struct ast_jb_conf jbconf;

} *iflist = NULL, *ifend = NULL;

Expand Down Expand Up @@ -5195,6 +5207,9 @@ static struct ast_channel *zt_new(struct zt_pvt *i, int state, int startpbx, int
}
} else
ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
/* Configure the new channel jb */
if (tmp && i)
ast_jb_configure(tmp, &i->jbconf);
return tmp;
}

Expand Down Expand Up @@ -6988,6 +7003,8 @@ static struct zt_pvt *mkintf(int channel, int signalling, int outsignalling, int
for (x=0;x<3;x++)
tmp->subs[x].zfd = -1;
tmp->channel = channel;
/* Assign default jb conf to the new zt_pvt */
memcpy(&tmp->jbconf, &global_jbconf, sizeof(struct ast_jb_conf));
}

if (tmp) {
Expand Down Expand Up @@ -10200,6 +10217,7 @@ static int setup_zap(int reload)
{
struct ast_config *cfg;
struct ast_variable *v;
struct ast_variable *vjb;
struct zt_pvt *tmp;
char *chan;
char *c;
Expand Down Expand Up @@ -10289,6 +10307,11 @@ static int setup_zap(int reload)
}
#endif
v = ast_variable_browse(cfg, "channels");
/* Copy the default jb config over global_jbconf */
memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
/* Traverse all variables to handle jb conf */
for (vjb = v; vjb; vjb = vjb->next)
ast_jb_read_conf(&global_jbconf, vjb->name, vjb->value);
while(v) {
/* Create the interface list */
if (!strcasecmp(v->name, "channel")
Expand Down
Loading

0 comments on commit 9953ec3

Please sign in to comment.