? sip.diff
Index: rtp.c
===================================================================
RCS file: /usr/cvsroot/asterisk/rtp.c,v
retrieving revision 1.142
diff -u -r1.142 rtp.c
--- rtp.c	12 Aug 2005 18:59:43 -0000	1.142
+++ rtp.c	25 Aug 2005 17:53:03 -0000
@@ -68,6 +68,62 @@
 
 #define FLAG_3389_WARNING (1 << 0)
 
+
+/* Slav - some static jitterbuffer stuff */
+#ifdef USE_JB
+#include "jitterbuf.h"
+#include <assert.h>
+#include <asterisk/term.h>
+#include <linux/limits.h>
+
+
+/* Macros for JB logs */
+/*#define jb_verbose(...) ast_verbose(VERBOSE_PREFIX_3 " ***[RTP JB LOG]*** " __VA_ARGS__)*/
+#define jb_verbose(...) if(1){\
+	char tmp[192];\
+	char msg[128];\
+	snprintf(msg, sizeof(msg), VERBOSE_PREFIX_3 "***[RTP JB LOG]*** " __VA_ARGS__);\
+	ast_verbose("%s\n", term_color(tmp, msg, COLOR_BRGREEN, 0, sizeof(tmp)));}
+
+/* Macros for the frame log files */
+#define jb_framelog(...) if(rtp->jb_logfile) {fprintf(rtp->jb_logfile, __VA_ARGS__); fflush(rtp->jb_logfile);}
+
+/* Macros for getting string representation of the jb type */
+static const char *jb_types[] = {"JB_TYPE_CONTROL", "JB_TYPE_VOICE", "JB_TYPE_VIDEO", "JB_TYPE_SILENCE"};
+#define jb_type(type) ((type >= 0 && type <= 3) ? jb_types[type] : "UNKNOWN")
+
+/* Counter for the frame log files */
+static int rtp_framelog_counter = 0;
+
+/* Counter for jb create-destroy debuging */
+static int jb_alloc_counter = 0;
+
+/* Scheduler context for the jitterbuffer */
+static struct sched_context *jb_sched;
+
+/* Scheduler thread */
+static pthread_t jb_sched_thread;
+
+/* Mutex for the scheduler queue synchronization */
+AST_MUTEX_DEFINE_STATIC(jb_sched_lock);
+
+/* Conditional variable for the scheduler queue synchronization */
+static pthread_cond_t jb_sched_flag = PTHREAD_COND_INITIALIZER;
+
+/* JB function prototypes */
+static void * jb_scheduler_thread(void *data);
+static struct ast_frame *ast_rtp_read_real(struct ast_rtp *rtp);
+static int put_in_jb(struct ast_rtp *rtp, struct ast_frame *f);
+static int get_from_jb(void *data);
+static void rtp_jb_clear(struct ast_rtp *rtp);
+static void rtp_jb_destroy(struct ast_rtp *rtp);
+static int calc_rxstamp_jb(struct ast_rtp *rtp);
+static void recalc_rxcore(struct ast_rtp *rtp);
+static void jb_get_timespec(struct timespec *ts, int millisec_offset);
+#endif
+/* End Slav */
+
+
 struct ast_rtp {
 	int s;
 	char resp;
@@ -106,6 +162,26 @@
 	int rtp_lookup_code_cache_result;
 	int rtp_offered_from_local;
 	struct ast_rtcp *rtcp;
+	/* Slav - jitterbuffer related members */
+#ifdef USE_JB
+	/* The jitterbuffer itself */
+	jitterbuf *jb;
+	/* Scheduler id */
+	int jbid;
+	/* Mutex for synchronization of the jb_put() - jb_get() operations and for destroy safety also */
+	ast_mutex_t jblock;
+	/* Indicates that this rtp has passed ast_rtp_destroy() */
+	int destroyed;
+	/* The pvt helper */
+	struct ast_rtp_pvt_helper pvt_helper;
+	/* is the channel up? */
+	int isup;
+	/* File for frame timestamp tracing */
+	FILE *jb_logfile;
+	/* Pathname of the log file */
+	char jb_logfile_pathname[PATH_MAX];
+#endif
+	/* End Slav */
 };
 
 struct ast_rtcp {
@@ -306,6 +382,532 @@
 	return f;
 }
 
+
+
+
+
+
+/* Slav - ******************************************************
+   ******************** Utility functions **********************
+   *************************************************************/
+
+/* Slav - calculates the time now [ms] in receivers time, e.g. counted from the time of the first frame
+   received (actually from the "zero" of the received frames time, which can be less than the time of
+   the first frame received). */
+#ifdef USE_JB
+static int calc_rxstamp_jb(struct ast_rtp *rtp)
+{
+	struct timeval tv;
+	
+	gettimeofday(&tv, NULL);
+	return (tv.tv_sec - rtp->rxcore.tv_sec) * 1000 + (1000000 + tv.tv_usec - rtp->rxcore.tv_usec) / 1000 - 1000;
+}
+#endif
+/* End Slav */
+
+
+/* Slav  - recalculates the zero of the receiver time scale, based on the time now and the last
+   rtp timestamp. */
+#ifdef USE_JB
+static void recalc_rxcore(struct ast_rtp *rtp)
+{
+	unsigned int timestamp = rtp->lastrxts;
+	
+	gettimeofday(&rtp->rxcore, NULL);
+	rtp->rxcore.tv_sec -= timestamp / 8000;
+	rtp->rxcore.tv_usec -= (timestamp % 8000) * 125;
+	/* Round to 20ms for nice, pretty timestamps */
+	rtp->rxcore.tv_usec -= rtp->rxcore.tv_usec % 20000;
+	if(rtp->rxcore.tv_usec < 0)
+	{
+		/* Adjust appropriately if necessary */
+		rtp->rxcore.tv_usec += 1000000;
+		rtp->rxcore.tv_sec -= 1;
+	}
+
+	timestamp = (rtp->rxcore.tv_sec * 1000 + rtp->rxcore.tv_usec / 1000);
+	jb_framelog("JB_PUT[%p] Recalc rxcore=%u\n", rtp, timestamp);
+}
+#endif
+/* End Slav */
+
+
+/* Slav - utility function - fills in the members of a timespec struct with the time now + millisec_offset
+   millisec_offset must be between 0 and 1000 */
+#ifdef USE_JB
+static void jb_get_timespec(struct timespec *ts, int millisec_offset)
+{
+	struct timeval tv;
+	
+	gettimeofday(&tv, NULL);
+	
+	ts->tv_sec = tv.tv_sec;
+	ts->tv_nsec = tv.tv_usec * 1000 + millisec_offset * 1000000;
+	if(ts->tv_nsec >= 1000000000)
+	{
+		ts->tv_sec += 1;
+		ts->tv_nsec -= 1000000000;
+	}
+}
+#endif
+/* End Slav */
+
+/* End Slav - **************************************************
+   ****************** End Utility functions ********************
+   *************************************************************/
+
+
+
+
+/* Slav - ******************************************************
+   ***************** Jitterbuf main functions ******************
+   *************************************************************/
+
+/* Slav - puts a frame into the jitterbuf */
+#ifdef USE_JB
+static int put_in_jb(struct ast_rtp *rtp, struct ast_frame *f)
+{
+	long ts;
+	long now;
+	int type;
+	int len;
+	struct ast_frame *frame;
+	
+	/* if the call is not yet answered, don't put the frame into the jb - just let it go through
+	   the regular way. */
+	if(rtp->pvt_helper.get_chan_state(rtp->pvt_helper.pvt) != AST_STATE_UP)
+	{
+		return -1;
+	}
+	else if(!rtp->isup)
+	{
+		/* The channel is up for the very first time. */
+		rtp->isup = 1;
+		
+		//recalc_rxcore(rtp);
+		jb_framelog("JB_PUT[%p] {now=%ld}: The call was answered.\n", rtp, (now = calc_rxstamp_jb(rtp)));
+		
+		/* lock the queue mutex */
+		ast_mutex_lock(&jb_sched_lock);
+		
+		/* add a schedule for get_from_jb() to happens after 20ms */
+		rtp->jbid = ast_sched_add(jb_sched, 20, get_from_jb, rtp);
+		
+		/* signal the schedule queue to wakeup the scheduler (if its waiting) */
+		pthread_cond_signal(&jb_sched_flag);
+		
+		/* unlock the queue mutex */
+		ast_mutex_unlock(&jb_sched_lock);
+		
+		jb_verbose("Jitterbuffer started.");
+	}
+
+	/* convert the timestamp of the frame from samples to millisec */
+	ts = rtp->lastrxts / 8;
+	
+	type = JB_TYPE_CONTROL;
+	len = 0;
+	
+	if(f->frametype == AST_FRAME_VOICE)
+	{
+		type = JB_TYPE_VOICE;
+		len = ast_codec_get_samples(f) / 8;
+	}
+	else if(f->frametype == AST_FRAME_CNG)
+	{
+		type = JB_TYPE_SILENCE;
+	}
+
+	/* Allocate a new frame */
+	frame = ast_frisolate(f);
+	if(frame == NULL)
+	{
+		ast_log(LOG_ERROR, "Cannot isolate frame for the jitterbuffer.\n");
+		return -1;
+	}
+	
+	/* lock the jb mutex */
+	ast_mutex_lock(&rtp->jblock);
+
+	/* The moment now in receivers time (in millisec) */
+	now = calc_rxstamp_jb(rtp);
+	
+	/* Put into the jitterbuffer. If jb_put returns JB_DROP, the frame should be dropped */
+	if(jb_put(rtp->jb, frame, type, len, ts, now) == JB_DROP)
+	{
+		jb_framelog("JB_PUT[%p] {now=%ld}: Dropped %s frame with ts=%lu\n", rtp, now, jb_type(type), ts);
+
+		/* unlock the jb mutex */
+		ast_mutex_unlock(&rtp->jblock);
+		
+		/* Drop the frame - just do nothing, except of cource, freeing the isolated frame. */
+		ast_frfree(frame);
+	}
+	else
+	{
+		jb_framelog("JB_PUT[%p] {now=%ld}: Queued %s frame with ts=%lu\n", rtp, now, jb_type(type), ts);
+
+		/* unlock the jb mutex */
+		ast_mutex_unlock(&rtp->jblock);
+	}
+	
+	return 0;
+}
+#endif
+/* End Slav */
+
+
+/* Slav - gets a frame from the jitterbuf for time now */
+#ifdef USE_JB
+static int get_from_jb(void *data)
+{
+	struct ast_rtp *rtp = (struct ast_rtp *) data;
+	jb_frame frame;
+	struct ast_frame af;
+	int ret;
+	long now;
+	long next;
+	long when;
+	long tmp;
+	struct timeval tv;
+	
+	if(rtp == NULL)
+	{
+		/* this should never happens */
+		ast_log(LOG_ERROR, "Received NULL rtp data!\n");
+		/* if in debug - abort asterisk */
+		assert(0);
+		/* if no - it will crash on the next line */
+	}
+	
+	/* lock the jb mutex */
+	ast_mutex_lock(&rtp->jblock);
+	
+	/* check for destroy conditon */
+	if(rtp->destroyed)
+	{
+		/* unlock the jb mutex */
+		ast_mutex_unlock(&rtp->jblock);
+		
+		/* set jbid to -1. TODO: No sense to do this since rtp is destroyed 2 lines below */
+		rtp->jbid = -1;
+		
+		/* Clear and destroy the jb and the rtp */
+		rtp_jb_clear(rtp);
+		rtp_jb_destroy(rtp);
+		
+		/* return 0 - no reschedules of this jb should happen after this. */
+		return 0;
+	}
+
+    gettimeofday(&tv,NULL);
+    /* round up a millisecond since ast_sched_runq does;
+       prevents us from spinning while waiting for our now to catch up with runq's now */
+    tv.tv_usec += 1000;
+	/* The moment now in receivers time (in millisec) */
+    now = (tv.tv_sec - rtp->rxcore.tv_sec) * 1000 + (tv.tv_usec - rtp->rxcore.tv_usec) / 1000;
+	
+	/* is it time for the next frame in the jb? */
+	if(now >= (next = jb_next(rtp->jb)))
+	{
+		/* get a frame from the jb for time now */
+		ret = jb_get(rtp->jb, &frame, now, ast_codec_interp_len(rtp->lastrxformat));
+		
+		/* Proceed with the frame timestamps logging while still holding the jb mutex lock */
+		if(rtp->jb_logfile != NULL && rtp->pvt_helper.get_chan_state(rtp->pvt_helper.pvt) == AST_STATE_UP)
+		{
+			switch(ret)
+			{
+			case JB_OK:
+				jb_framelog("\tJB_GET[%p] {now=%ld}: Delivered %s frame with timestamp %ld\n",
+					rtp, now, jb_type(frame.type), frame.ts);
+				break;
+			case JB_INTERP:
+				jb_framelog("\tJB_GET[%p] {now=%ld}: Interpolated frame\n", rtp, now);
+				break;
+			case JB_DROP:
+				jb_framelog("\tJB_GET[%p] {now=%ld}: Dropped %s frame with timestamp %ld\n",
+					rtp, now, jb_type(frame.type), frame.ts);
+				break;
+			case JB_NOFRAME:
+				jb_framelog("\tJB_GET[%p] {now=%ld}: No frame\n", rtp, now);
+				break;
+			case JB_EMPTY:
+				jb_framelog("\tJB_GET[%p] {now=%ld}: Jb is empty\n", rtp, now);
+				break;
+			default:
+				ast_log(LOG_ERROR, "This should never happens!");
+				break;
+			}
+		}
+		
+		/* unlock the jb mutex */
+		ast_mutex_unlock(&rtp->jblock);
+		
+		switch(ret)
+		{
+		case JB_OK:
+			/* don't deliver if the channel is not up */
+			if(rtp->pvt_helper.get_chan_state(rtp->pvt_helper.pvt) == AST_STATE_UP)
+			{
+				/* deliver the frame into the channel's queue (internally locks the channel mutex!) */
+				rtp->pvt_helper.queue_frame(rtp->pvt_helper.pvt, frame.data);
+			}
+			ast_frfree(frame.data);
+			break;
+		case JB_INTERP:
+			/* don't interpolate if the channel is not up */
+			if(rtp->pvt_helper.get_chan_state(rtp->pvt_helper.pvt) == AST_STATE_UP)
+			{
+				/* Create an interpolation frame */
+				memset(&af, 0, sizeof(struct ast_frame));
+				// TODO: Remove the unnecessary member zero initializations
+				af.frametype = AST_FRAME_VOICE;
+				af.subclass = rtp->pvt_helper.get_nativeformats(rtp->pvt_helper.pvt);
+				af.datalen = 0;
+				af.samples = frame.ms * 8;
+				/* Mark as non malloced, because of ast_queue_frame? */
+				af.mallocd = 0;
+				af.src = "SIP JB interpolation";
+				af.data = NULL;
+				// TODO: Do we need to set a delivery timeval?
+				af.delivery.tv_sec = rtp->rxcore.tv_sec;
+				af.delivery.tv_usec = rtp->rxcore.tv_usec;
+				af.delivery.tv_sec += next / 1000;
+				af.delivery.tv_usec += (next % 1000) * 1000;
+				af.offset=AST_FRIENDLY_OFFSET;
+				if(af.delivery.tv_usec >= 1000000)
+				{
+					af.delivery.tv_usec -= 1000000;
+					af.delivery.tv_sec += 1;
+				}
+				/* deliver the frame into the channel's queue (internally locks the channel mutex!) */
+				rtp->pvt_helper.queue_frame(rtp->pvt_helper.pvt, &af);
+			}
+			break;
+		case JB_DROP:
+			/* Just free the frame */
+			ast_frfree(frame.data);
+			break;
+		case JB_NOFRAME:
+			break;
+		case JB_EMPTY:
+			break;
+		default:
+			ast_log(LOG_ERROR, "This should never happens!");
+			break;
+		}
+	}
+	else
+	{
+		jb_framelog("\tJB_GET[%p] {now=%ld}: now < next=%ld\n", rtp, now, next);
+
+		/* unlock the jb mutex */
+		ast_mutex_unlock(&rtp->jblock);
+	}
+	
+	/* Calc how many millisec remains to the next time a frame should be delivered */
+	next = jb_next(rtp->jb);
+	when = next - now;
+	/* Don't use when < 2ms and > 30ms! */
+	if(when < 2)
+	{
+		when = 2;
+	}
+	if(when > 30)
+	{
+		/* Obviously the jitterbuffer is confused. Use the length of the last frame. */
+		tmp = ast_codec_interp_len(rtp->lastrxformat);
+		tmp = (tmp >= 10 && tmp <= 30) ? tmp : 20;
+		jb_framelog("\tJB_GET[%p] {now=%ld}: Invalid when=%ld, next=%ld. Resetting to %ld ms.\n",
+			rtp, now, when, next, tmp);
+		when = tmp;
+	}
+
+	/* reschedule (adds again this schedule) */
+	rtp->jbid = ast_sched_add(jb_sched, when, get_from_jb, rtp);
+	
+	return 0;
+}
+#endif
+/* End Slav */
+
+
+/* Slav - called from a channel who wants a jitterbuff enabled - preforms jitterbuff initialization */
+#ifdef USE_JB
+void ast_rtp_jb_enable(struct ast_rtp *rtp, struct ast_rtp_pvt_helper *pvt_helper,
+	struct sched_context *ex_sched, struct io_context *ex_io)
+{
+	jb_conf jbinfo;
+	
+	/* Shouldn't be called more than once on a given rtp! */
+	assert(rtp->jb == NULL);
+	
+	/* Initialize the destroy flag */
+	rtp->destroyed = 0;
+
+	/* Initialize the jb sched id */
+	rtp->jbid = -1;
+	
+	/* Create the jitterbuf */
+	rtp->jb = jb_new();
+
+	/* Is the new jitterbuf successfuly created? */
+	if(rtp->jb != NULL)
+	{
+		/* Copy the pvt_helper data. TODO: Make sure the pvt_helper members are valid */
+		memcpy(&rtp->pvt_helper, pvt_helper, sizeof(struct ast_rtp_pvt_helper));
+		
+		/* Set the maximum lenght of the jitterbuffer (in milliseconds) */
+		jbinfo.max_jitterbuf = 1000;
+		jbinfo.resync_threshold = 1000;
+		jb_setconf(rtp->jb,&jbinfo);
+		
+		/* Initialize the jb mutex */
+		ast_mutex_init(&rtp->jblock);
+		
+		/* lock the queue mutex */
+		ast_mutex_lock(&jb_sched_lock);
+
+		/* Create a frame log file */
+		/*
+		snprintf(rtp->jb_logfile_pathname, sizeof(rtp->jb_logfile_pathname),
+			"/tmp/jb_frames_%.5d.log", rtp_framelog_counter++);
+		rtp->jb_logfile = fopen(rtp->jb_logfile_pathname, "w+b");
+		*/
+		
+		/* Increment the jb alloc counter */
+		jb_alloc_counter++;
+		
+		/* add a new schedule for get_from_jb() (scheduled each 20 ms?) */
+		//rtp->jbid = ast_sched_add(jb_sched, 20, get_from_jb, rtp);
+		
+		/* signal the schedule queue to wakeup the scheduler (if its waiting) */
+		//pthread_cond_signal(&jb_sched_flag);
+		
+		jb_verbose("Jitterbuffer enabled. jb_alloc=%d.", jb_alloc_counter);
+		
+		/* unlock the queue mutex */
+		ast_mutex_unlock(&jb_sched_lock);
+	}
+	else
+	{
+		/* Cannot allocate memory for the jb - only log a warning and continue using the
+		   channel without a jb */
+		ast_log(LOG_WARNING, "Unable to allocate new jitterbuffer.\n");
+	}
+}
+#endif
+/* End Slav */
+
+
+/* Slav - removes all remaining frames from the jb and frees them */
+#ifdef USE_JB
+static void rtp_jb_clear(struct ast_rtp *rtp)
+{
+	jb_frame frame;
+	
+	/* remove and free any remaining frames in the jb */
+	while(jb_getall(rtp->jb,&frame) == JB_OK)
+	{
+		ast_frfree(frame.data);
+	}
+}
+#endif
+/* End Slav */
+
+
+/* Slav - destroys the jitterbuf and the jb mutex and frees its rtp container */
+#ifdef USE_JB
+static void rtp_jb_destroy(struct ast_rtp *rtp)
+{
+	/* destroy the jitterbuffer */
+	jb_destroy(rtp->jb);
+	rtp->jb = NULL;
+
+	/* close the framelog file */
+	if(rtp->jb_logfile != NULL)
+	{
+		fseek(rtp->jb_logfile, 0, SEEK_END);
+		int len = ftell(rtp->jb_logfile);
+		fclose(rtp->jb_logfile);
+		rtp->jb_logfile = NULL;
+
+		/* If there is less than 1024 bytes logged in this file - delete it */
+		if(len < 1024)
+		{
+			remove(rtp->jb_logfile_pathname);
+		}
+	}
+	
+	/* Decrement the jb_alloc_counter (Called with the jb_sched_lock held) */
+	jb_alloc_counter--;
+	
+	/* destroy the jb mutex */
+	ast_mutex_destroy(&rtp->jblock);
+	
+	/* finally free the rtp */
+	free(rtp);
+	
+	jb_verbose("Jitterbuffer destroyed. *** *** jb_alloc_counter=%d *** ***.", jb_alloc_counter);
+}
+#endif
+/* End Slav */
+
+
+/* Slav - jitterbuffer scheduler thread function */
+#ifdef USE_JB
+static void * jb_scheduler_thread(void *data)
+{
+	int when;
+	struct timespec abstime;
+	
+	jb_verbose("The rtp jitterbuffer scheduler thread is running.");
+	
+	while(1)
+	{
+		/* lock the queue mutex */
+		ast_mutex_lock(&jb_sched_lock);
+		
+		/* get how many millisecs to wait until the first event scheduled */
+		when = ast_sched_wait(jb_sched);
+		/* don't wait more than 1 sec. when < 0 means that the sched queue is empty */
+		if(when < 0 || when > 1000)
+		{
+			when = 1000;
+		}
+		
+		/* wait until its time for the first schedule - can be interrupted by adding new schedule
+		   (internally unlocks the queue mutex and locks it after the waiting is finished) */
+		if(when > 0)
+		{
+			jb_get_timespec(&abstime, when);
+			pthread_cond_timedwait(&jb_sched_flag, &jb_sched_lock, &abstime);
+		}
+		
+		/* unlock the queue mutex */
+		ast_mutex_unlock(&jb_sched_lock);
+		
+		/* exec all for time now */
+		ast_sched_runq(jb_sched);
+	}
+	
+	return NULL;
+}
+#endif
+/* End Slav */
+
+
+/* End Slav - **************************************************
+   *************** End Jitterbuf main functions ****************
+   *************************************************************/
+
+
+
+
+
+
+
 static int rtpread(int *id, int fd, short events, void *cbdata)
 {
 	struct ast_rtp *rtp = cbdata;
@@ -374,8 +976,47 @@
 	*tv = ast_tvadd(rtp->rxcore, ts);
 }
 
+
+/* Slav - the jitterbuf version of ast_rtp_read(). Returns AST_FRAME_NULL if the jb is used */
+#ifdef USE_JB
 struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
 {
+	static struct ast_frame *frr, nf = { AST_FRAME_NULL, };
+
+	/* Is a jitterbuffer used for this rtp? */
+	if(rtp->jb != NULL)
+	{
+		/* Read a frame from the network */
+		frr = ast_rtp_read_real(rtp);
+
+		/* Put the frame into the jb. */
+		if(put_in_jb(rtp, frr) == 0)
+		{
+			return &nf;
+		}
+		
+		/* If put_in_jb() returns non zero (e.g. the channel is not up), deliver the frame immediately. */
+		return frr;
+	}
+	
+	/* If not using jb, deliver the frame immediately. */
+	return ast_rtp_read_real(rtp);
+}
+#endif
+/* End Slav */
+
+
+/* Slav - the real ast_rtp_read() function will be used if the jitterbuffer is not used */
+#ifndef USE_JB
+/* End Slav */
+struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
+/* Slav - else predefine the real ast_rtp_read() func, so the jb version will be used from
+   all rtp channels */
+#else
+static struct ast_frame *ast_rtp_read_real(struct ast_rtp *rtp)
+#endif
+/* End Slav */
+{
 	int res;
 	struct sockaddr_in sin;
 	socklen_t len;
@@ -1015,7 +1656,39 @@
 		close(rtp->rtcp->s);
 		free(rtp->rtcp);
 	}
+	/* Slav - don't free the rtp here if we are using the jb - just add it to the free list. */
+#ifndef USE_JB
+	/* End Slav */
 	free(rtp);
+	/* Slav - set the destroy flag to the rtp, but only if a jb is enabled */
+#else
+	jb_verbose("ast_rtp_destroy() invoked.");
+	/* Does a jitterbuf is used for this rtp? */
+	if(rtp->jb != NULL)
+	{
+		/* lock the jb mutex */
+		ast_mutex_lock(&rtp->jblock);
+		
+		/* set the destroy flag to let get_from_jb() knows that the rtp is on the free list */
+		rtp->destroyed = 1;
+		
+		/* unlock the jb mutex */
+		ast_mutex_unlock(&rtp->jblock);
+		
+		/* If there was no sched added yet (the channel was never up), destroy here */
+		if(rtp->jbid == -1)
+		{
+			rtp_jb_clear(rtp);
+			rtp_jb_destroy(rtp);
+		}
+	}
+	else
+	{
+		/* No - free the rtp */
+		free(rtp);
+	}
+#endif
+	/* End Slav */
 }
 
 static unsigned int calc_txstamp(struct ast_rtp *rtp, struct timeval *delivery)
@@ -1773,4 +2446,25 @@
 	ast_cli_register(&cli_debug_ip);
 	ast_cli_register(&cli_no_debug);
 	ast_rtp_reload();
+	
+	/* Slav - init the rtp jb scheduler stuff */
+#ifdef USE_JB
+	/* Create a scheduler context */
+	jb_sched = sched_context_create();
+	if(jb_sched == NULL)
+	{
+		ast_log(LOG_ERROR, "Unable to create rtp jb scheduler context.\n");
+		assert(0);
+	}
+	
+	/* Start the scheduler thread */
+	if(ast_pthread_create(&jb_sched_thread, NULL, jb_scheduler_thread, NULL) < 0)
+	{
+		ast_log(LOG_ERROR, "Unable to start rtp jb scheduler thread.\n");
+		assert(0);
+	}
+	
+	jb_verbose("Started the rtp jitterbuffer scheduler thread.");
+#endif
+	/* End Slav */
 }
Index: channels/chan_sip.c
===================================================================
RCS file: /usr/cvsroot/asterisk/channels/chan_sip.c,v
retrieving revision 1.820
diff -u -r1.820 chan_sip.c
--- channels/chan_sip.c	25 Aug 2005 03:44:22 -0000	1.820
+++ channels/chan_sip.c	25 Aug 2005 17:53:13 -0000
@@ -2887,10 +2887,60 @@
 		snprintf(callid, len, "@%s", ast_inet_ntoa(iabuf, sizeof(iabuf), ourip));
 }
 
+
+/* Slav - functions for the rtp pvt helper */
+#ifdef USE_JB
+static int sip_queue_frame(void *pvt, struct ast_frame *f)
+{
+	struct sip_pvt *p = (struct sip_pvt *) pvt;
+	if(p->owner != NULL)
+	{
+		return ast_queue_frame(p->owner, f);
+	}
+	else
+	{
+		return -1;
+	}
+}
+
+static int sip_get_chan_state(void *pvt)
+{
+	struct sip_pvt *p = (struct sip_pvt *) pvt;
+	if(p->owner != NULL)
+	{
+		return p->owner->_state;
+	}
+	else
+	{
+		return -1;
+	}
+}
+
+static int sip_get_nativeformats(void *pvt)
+{
+	struct sip_pvt *p = (struct sip_pvt *) pvt;
+	if(p->owner != NULL)
+	{
+		return p->owner->nativeformats;
+	}
+	else
+	{
+		return -1;
+	}
+}
+#endif
+/* End Slav */
+
+
 /*--- sip_alloc: Allocate SIP_PVT structure and set defaults ---*/
 static struct sip_pvt *sip_alloc(char *callid, struct sockaddr_in *sin, int useglobal_nat, const int intended_method)
 {
 	struct sip_pvt *p;
+	/* Slav - pvt_helper fot the rtp jitterbuffer */
+#ifdef USE_JB
+	struct ast_rtp_pvt_helper pvt_helper;
+#endif
+	/* End Slav */
 
 	p = malloc(sizeof(struct sip_pvt));
 	if (!p)
@@ -2924,6 +2974,19 @@
 
 	if (sip_methods[intended_method].need_rtp) {
 		p->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
+		
+		/* Slav - enable a jitterbuffer on the newly created rtp */
+#ifdef USE_JB
+		/* Init the pvt helper functions */
+		pvt_helper.pvt = p;
+		pvt_helper.queue_frame = sip_queue_frame;
+		pvt_helper.get_chan_state = sip_get_chan_state;
+		pvt_helper.get_nativeformats = sip_get_nativeformats;
+		/* enable the jitterbuffer */
+		ast_rtp_jb_enable(p->rtp, &pvt_helper, sched, io);
+#endif
+		/* End Slav */
+		
 		if (videosupport)
 			p->vrtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
 		if (!p->rtp) {
Index: include/asterisk/rtp.h
===================================================================
RCS file: /usr/cvsroot/asterisk/include/asterisk/rtp.h,v
retrieving revision 1.22
diff -u -r1.22 rtp.h
--- include/asterisk/rtp.h	21 Apr 2005 06:02:44 -0000	1.22
+++ include/asterisk/rtp.h	25 Aug 2005 17:53:13 -0000
@@ -25,6 +25,12 @@
 extern "C" {
 #endif
 
+
+/* Slav - define USE_JB to enable the jitterbuffer for all rtp channels */
+#define USE_JB
+/* End Slav */
+
+
 /* Codes for RTP-specific data - not defined by our AST_FORMAT codes */
 /*! DTMF (RFC2833) */
 #define AST_RTP_DTMF            (1 << 0)
@@ -48,6 +54,33 @@
 };
 
 struct ast_rtp;
+
+
+/* Slav - jitterbuffer related stuff */
+#ifdef USE_JB
+typedef int (*pvt_queue_frame)(void *pvt, struct ast_frame *f);
+typedef int (*pvt_get_chan_state)(void *pvt);
+typedef int (*pvt_get_nativeformats)(void *pvt);
+
+/* Defines technology independent way to access some channel functionality */
+struct ast_rtp_pvt_helper
+{
+	/* Pointer to the tech private structure */
+	void *pvt;
+	/* Pointer to a function for queueing a frame into a channel */
+	pvt_queue_frame queue_frame;
+	/* Pointer to a function, returning the current channel state */
+	pvt_get_chan_state get_chan_state;
+	/* Pointer to a function, returning the supported from the channel formats */
+	pvt_get_nativeformats get_nativeformats;
+};
+
+/* Enables the jitterbuff for the specified channel (and rtp). Performs jitterbuff initialization */
+void ast_rtp_jb_enable(struct ast_rtp *rtp, struct ast_rtp_pvt_helper *pvt_helper,
+	struct sched_context *ex_sched, struct io_context *ex_io);
+#endif
+/* End Slav */
+
 
 typedef int (*ast_rtp_callback)(struct ast_rtp *rtp, struct ast_frame *f, void *data);
 
