Index: channel.c =================================================================== --- channel.c (Revision 8696) +++ channel.c (Arbeitskopie) @@ -988,6 +988,11 @@ while ((vardata = AST_LIST_REMOVE_HEAD(headp, entries))) ast_var_delete(vardata); +#ifdef AST_JB + /* Destroy the jitterbuffer */ + ast_jb_destroy(chan); +#endif /* AST_JB */ + free(chan); AST_LIST_UNLOCK(&channels); @@ -3280,6 +3285,11 @@ int watch_c1_dtmf; void *pvt0, *pvt1; int to; + +#ifdef AST_JB + /* Indicates whether a frame was queued into a jitterbuffer */ + int frame_put_in_jb; +#endif /* AST_JB */ cs[0] = c0; cs[1] = c1; @@ -3290,6 +3300,11 @@ watch_c0_dtmf = config->flags & AST_BRIDGE_DTMF_CHANNEL_0; watch_c1_dtmf = config->flags & AST_BRIDGE_DTMF_CHANNEL_1; +#ifdef AST_JB + /* Check the need of a jitterbuffer for each channel */ + ast_jb_do_usecheck(c0, c1); +#endif /* AST_JB */ + for (;;) { if ((c0->tech_pvt != pvt0) || (c1->tech_pvt != pvt1) || (o0nativeformats != c0->nativeformats) || @@ -3328,6 +3343,11 @@ break; } +#ifdef AST_JB + /* Try add the frame info the who's bridged channel jitterbuff */ + frame_put_in_jb = !ast_jb_put((who == c0) ? c1 : c0, f); +#endif /* AST_JB */ + if ((f->frametype == AST_FRAME_CONTROL) && !(config->flags & AST_BRIDGE_IGNORE_SIGS)) { if ((f->subclass == AST_CONTROL_HOLD) || (f->subclass == AST_CONTROL_UNHOLD) || (f->subclass == AST_CONTROL_VIDUPDATE)) { @@ -3368,7 +3388,18 @@ last = who; #endif tackygoto: +#ifdef AST_JB + /* Write immediately frames, not passed through jb */ + if(!frame_put_in_jb) + { + ast_write((who == c0) ? c1 : c0, f); + } + + /* Check if we have to deliver now */ + ast_jb_get_and_deliver(c0, c1); +#else /* AST_JB */ ast_write((who == c0) ? c1 : c0, f); +#endif /* AST_JB */ } } ast_frfree(f); Index: channels/chan_zap.c =================================================================== --- channels/chan_zap.c (Revision 8696) +++ channels/chan_zap.c (Arbeitskopie) @@ -101,6 +101,19 @@ #include "asterisk/utils.h" #include "asterisk/transcap.h" +#ifdef AST_JB +#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; +#endif /* AST_JB */ + #ifndef ZT_SIG_EM_E1 #error "Your zaptel is too old. please cvs update" #endif @@ -689,6 +702,9 @@ #endif int polarity; int dsp_features; +#ifdef AST_JB + struct ast_jb_conf jbconf; +#endif /* AST_JB */ } *iflist = NULL, *ifend = NULL; @@ -5200,6 +5216,13 @@ } } else ast_log(LOG_WARNING, "Unable to allocate channel structure\n"); +#ifdef AST_JB + /* Configure the new channel jb */ + if(tmp != NULL && i != NULL) + { + ast_jb_configure(tmp, &i->jbconf); + } +#endif /* AST_JB */ return tmp; } @@ -6983,6 +7006,10 @@ for (x=0;x<3;x++) tmp->subs[x].zfd = -1; tmp->channel = channel; +#ifdef AST_JB + /* Assign default jb conf to the new zt_pvt */ + memcpy(&tmp->jbconf, &global_jbconf, sizeof(struct ast_jb_conf)); +#endif /* AST_JB */ } if (tmp) { @@ -10309,8 +10336,20 @@ } } #endif +#ifdef AST_JB + /* Copy the default jb config over global_jbconf */ + memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf)); +#endif /* AST_JB */ v = ast_variable_browse(cfg, "channels"); while(v) { +#ifdef AST_JB + /* handle jb conf */ + if(ast_jb_read_conf(&global_jbconf, v->name, v->value) == 0) + { + v = v->next; + continue; + } +#endif /* AST_JB */ /* Create the interface list */ if (!strcasecmp(v->name, "channel") #ifdef ZAPATA_PRI Index: channels/chan_sip.c =================================================================== --- channels/chan_sip.c (Revision 8696) +++ channels/chan_sip.c (Arbeitskopie) @@ -154,6 +154,19 @@ #define SIP_MAX_LINES 64 /*!< Max amount of lines in SIP attachment (like SDP) */ +#ifdef AST_JB +#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; +#endif /* AST_JB */ + static const char desc[] = "Session Initiation Protocol (SIP)"; static const char channeltype[] = "SIP"; static const char config[] = "sip.conf"; @@ -711,6 +724,9 @@ struct ast_variable *chanvars; /*!< Channel variables to set for call */ struct sip_pvt *next; /*!< Next dialog in chain */ struct sip_invite_param *options; /*!< Options for INVITE */ +#ifdef AST_JB + struct ast_jb_conf jbconf; +#endif /* AST_JB */ } *iflist = NULL; #define FLAG_RESPONSE (1 << 0) @@ -952,7 +968,11 @@ .type = channeltype, .description = "Session Initiation Protocol (SIP)", .capabilities = ((AST_FORMAT_MAX_AUDIO << 1) - 1), +#ifdef AST_JB + .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER, +#else /* AST_JB */ .properties = AST_CHAN_TP_WANTSJITTER, +#endif /* AST_JB */ .requester = sip_request_call, .devicestate = sip_devicestate, .call = sip_call, @@ -2899,6 +2919,14 @@ for (v = i->chanvars ; v ; v = v->next) pbx_builtin_setvar_helper(tmp,v->name,v->value); +#ifdef AST_JB + /* Configure the new channel jb */ + if(tmp != NULL && i != NULL && i->rtp != NULL) + { + ast_jb_configure(tmp, &i->jbconf); + } +#endif /* AST_JB */ + return tmp; } @@ -3195,6 +3223,11 @@ p->noncodeccapability |= AST_RTP_DTMF; ast_string_field_set(p, context, default_context); +#ifdef AST_JB + /* Assign default jb conf to the new sip_pvt */ + memcpy(&p->jbconf, &global_jbconf, sizeof(struct ast_jb_conf)); +#endif /* AST_JB */ + /* Add to active dialog list */ ast_mutex_lock(&iflock); p->next = iflist; @@ -12151,6 +12184,14 @@ v = v->next; continue; } +#ifdef AST_JB + /* handle jb conf */ + if(ast_jb_read_conf(&global_jbconf, v->name, v->value) == 0) + { + v = v->next; + continue; + } +#endif /* AST_JB */ if (realtime && !strcasecmp(v->name, "regseconds")) { if (sscanf(v->value, "%ld", (time_t *)®seconds) != 1) @@ -12417,6 +12458,10 @@ /* Misc settings for the channel */ relaxdtmf = 0; callevents = 0; +#ifdef AST_JB + /* Copy the default jb config over global_jbconf */ + memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf)); +#endif /* AST_JB */ /* Read the [general] config section of sip.conf (or from realtime config) */ for (v = ast_variable_browse(cfg, "general"); v; v = v->next) { Index: channels/chan_iax2.c =================================================================== --- channels/chan_iax2.c (Revision 8696) +++ channels/chan_iax2.c (Arbeitskopie) @@ -1410,6 +1410,9 @@ the IAX thread with the iaxsl lock held. */ struct iax_frame *fr = data; fr->retrans = -1; +#ifdef AST_JB + fr->af.has_timing_info = 0; +#endif /* AST_JB */ if (iaxs[fr->callno] && !ast_test_flag(iaxs[fr->callno], IAX_ALREADYGONE)) iax2_queue_frame(fr->callno, &fr->af); /* Free our iax frame */ Index: Makefile =================================================================== --- Makefile (Revision 8696) +++ Makefile (Arbeitskopie) @@ -79,6 +79,9 @@ # Uncomment next one to enable ast_frame tracing (for debugging) TRACE_FRAMES = #-DTRACE_FRAMES +# Uncomment next one to enable the asterisk generic jitterbuffer +GENERIC_JB = -DAST_JB + # Uncomment next one to enable malloc debugging # You can view malloc debugging with: # *CLI> show memory allocations [filename] @@ -334,6 +337,7 @@ ASTCFLAGS+= $(DEBUG_THREADS) ASTCFLAGS+= $(TRACE_FRAMES) +ASTCFLAGS+= $(GENERIC_JB) ASTCFLAGS+= $(MALLOC_DEBUG) ASTCFLAGS+= $(BUSYDETECT) ASTCFLAGS+= $(OPTIONS) @@ -349,7 +353,7 @@ cdr.o tdd.o acl.o rtp.o udptl.o manager.o asterisk.o \ dsp.o chanvars.o indications.o autoservice.o db.o privacy.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 \ + utils.o plc.o jitterbuf.o scx_jitterbuf.o abstract_jb.o dnsmgr.o devicestate.o \ netsock.o slinfactory.o ast_expr2.o ast_expr2f.o \ cryptostub.o Index: translate.c =================================================================== --- translate.c (Revision 8696) +++ translate.c (Arbeitskopie) @@ -156,6 +156,17 @@ struct ast_trans_pvt *p; struct ast_frame *out; struct timeval delivery; +#ifdef AST_JB + int has_timing_info; + long ts; + long len; + int seqno; + + has_timing_info = f->has_timing_info; + ts = f->ts; + len = f->len; + seqno = f->seqno; +#endif /* AST_JB */ p = path; /* Feed the first frame into the first translator */ p->step->framein(p->state, f); @@ -210,6 +221,15 @@ /* Invalidate prediction if we're entering a silence period */ if (out->frametype == AST_FRAME_CNG) path->nextout = ast_tv(0, 0); +#ifdef AST_JB + out->has_timing_info = has_timing_info; + if(has_timing_info) + { + out->ts = ts; + out->len = len; + out->seqno = seqno; + } +#endif /* AST_JB */ return out; } p = p->next; Index: include/asterisk/channel.h =================================================================== --- include/asterisk/channel.h (Revision 8696) +++ include/asterisk/channel.h (Arbeitskopie) @@ -86,6 +86,10 @@ #ifndef _ASTERISK_CHANNEL_H #define _ASTERISK_CHANNEL_H +#ifdef AST_JB +#include "asterisk/abstract_jb.h" +#endif /* AST_JB */ + #include #ifdef POLLCOMPAT #include "asterisk/poll-compat.h" @@ -412,6 +416,11 @@ /*! For easy linking */ AST_LIST_ENTRY(ast_channel) list; + +#ifdef AST_JB + /*! The jitterbuffer state */ + struct ast_jb jb; +#endif /* AST_JB */ }; /* \defgroup chanprop Channel tech properties: @@ -419,6 +428,13 @@ /* @{ */ #define AST_CHAN_TP_WANTSJITTER (1 << 0) +#ifdef AST_JB +/* \defgroup chanprop Channel tech properties: + \brief Channels have this property if they can create jitter; i.e. most VoIP channels */ +/* @{ */ +#define AST_CHAN_TP_CREATESJITTER (1 << 1) +#endif /* AST_JB */ + /* This flag has been deprecated by the transfercapbilty data member in struct ast_channel */ /* #define AST_FLAG_DIGITAL (1 << 0) */ /* if the call is a digital ISDN call */ #define AST_FLAG_DEFER_DTMF (1 << 1) /*!< if dtmf should be deferred */ Index: include/asterisk/frame.h =================================================================== --- include/asterisk/frame.h (Revision 8696) +++ include/asterisk/frame.h (Arbeitskopie) @@ -109,6 +109,16 @@ struct ast_frame *prev; /*! Next/Prev for linking stand alone frames */ struct ast_frame *next; +#ifdef AST_JB + /*! Timing data flag */ + int has_timing_info; + /*! Timestamp in milliseconds */ + long ts; + /*! Length in milliseconds */ + long len; + /*! Sequence number */ + int seqno; +#endif /* AST_JB */ }; #define AST_FRIENDLY_OFFSET 64 /*! It's polite for a a new frame to Index: rtp.c =================================================================== --- rtp.c (Revision 8696) +++ rtp.c (Arbeitskopie) @@ -430,7 +430,10 @@ int padding; int mark; int ext; + /* Remove the variable for the pointless loop */ +#ifndef AST_JB int x; +#endif /* AST_JB */ char iabuf[INET_ADDRSTRLEN]; unsigned int timestamp; unsigned int *rtpheader; @@ -571,6 +574,8 @@ if (!rtp->lastrxts) rtp->lastrxts = timestamp; + /* Remove this pointless loop - it will generate unnecessary CPU load on a big jump in seqno. */ +#ifndef AST_JB if (rtp->rxseqno) { for (x=rtp->rxseqno + 1; x < seqno; x++) { /* Queue empty frames */ @@ -582,6 +587,7 @@ rtp->f.src = "RTPMissedFrame"; } } +#endif /* AST_JB */ rtp->rxseqno = seqno; if (rtp->dtmfcount) { @@ -613,6 +619,13 @@ if (rtp->f.subclass == AST_FORMAT_SLINEAR) ast_frame_byteswap_be(&rtp->f); calc_rxstamp(&rtp->f.delivery, rtp, timestamp, mark); +#ifdef AST_JB + /* Add timing data to let ast_generic_bridge() put the frame into a jitterbuf */ + rtp->f.has_timing_info = 1; + rtp->f.ts = timestamp / 8; + rtp->f.len = rtp->f.samples / 8; + rtp->f.seqno = seqno; +#endif /* AST_JB */ } else { /* Video -- samples is # of samples vs. 90000 */ if (!rtp->lastividtimestamp) Index: frame.c =================================================================== --- frame.c (Revision 8696) +++ frame.c (Arbeitskopie) @@ -319,6 +319,16 @@ out->offset = fr->offset; out->src = NULL; out->data = fr->data; +#ifdef AST_JB + /* Copy the timing data */ + out->has_timing_info = fr->has_timing_info; + if(fr->has_timing_info) + { + out->ts = fr->ts; + out->len = fr->len; + out->seqno = fr->seqno; + } +#endif /* AST_JB */ } else { out = fr; } @@ -382,6 +392,15 @@ out->prev = NULL; out->next = NULL; memcpy(out->data, f->data, out->datalen); +#ifdef AST_JB + out->has_timing_info = f->has_timing_info; + if(f->has_timing_info) + { + out->ts = f->ts; + out->len = f->len; + out->seqno = f->seqno; + } +#endif /* AST_JB */ return out; } Index: configs/sip.conf.sample =================================================================== --- configs/sip.conf.sample (Revision 8696) +++ configs/sip.conf.sample (Arbeitskopie) @@ -243,6 +243,32 @@ ; destinations which do not have a prior ; account relationship with your server. +;------------------------------ JITTER BUFFER CONFIGURATION -------------------------- +; jb-enable = yes ; Enables the use of a jitterbuffer on the receiving side of a + ; SIP 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 SIP channel can accept jitter, + ; thus a jitterbuffer on the receive SIP side will be used only + ; if it is forced and enabled. + +; jb-force = no ; Forces the use of a jitterbuffer on the receive side of a SIP + ; channel. Defaults to "no". + +; jb-max-size = 200 ; Max length of the jitterbuffer in milliseconds. + +; jb-resynch-threshold = 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. + +; jb-impl = fixed ; Jitterbuffer implementation, used on the receiving side of a SIP + ; channel. Two implementation are currenlty available - "fixed" + ; (with size always equals to jb-max-size) and "adaptive" (with + ; variable size, actually the new jb of IAX2). Defaults to fixed. + +; jb-log = no ; Enables jitterbuffer frame logging. Defaults to "no". +;----------------------------------------------------------------------------------- + [authentication] ; Global credentials for outbound calls, i.e. when a proxy challenges your ; Asterisk server for authentication. These credentials override Index: configs/zapata.conf.sample =================================================================== --- configs/zapata.conf.sample (Revision 8696) +++ configs/zapata.conf.sample (Arbeitskopie) @@ -476,6 +476,33 @@ ; ;jitterbuffers=4 ; +;------------------------------ JITTER BUFFER CONFIGURATION -------------------------- +; jb-enable = yes ; Enables the use of a jitterbuffer on the receiving side of a + ; ZAP 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. + +; jb-force = no ; Forces the use of a jitterbuffer on the receive side of a ZAP + ; channel. Defaults to "no". + +; jb-max-size = 200 ; Max length of the jitterbuffer in milliseconds. + +; jb-resynch-threshold = 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. + +; jb-impl = fixed ; Jitterbuffer implementation, used on the receiving side of a SIP + ; channel. Two implementation are currenlty available - "fixed" + ; (with size always equals to jb-max-size) and "adaptive" (with + ; variable size, actually the new jb of IAX2). Defaults to fixed. + +; jb-log = no ; Enables jitterbuffer frame logging. Defaults to "no". +;----------------------------------------------------------------------------------- +; ; You can define your own custom ring cadences here. You can define up to 8 ; pairs. If the silence is negative, it indicates where the callerid spill is ; to be placed. Also, if you define any custom cadences, the default cadences