[asterisk-commits] branch oej/jitterbuffer r9025 - /team/oej/jitterbuffer/

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Tue Jan 31 13:03:04 MST 2006


Author: oej
Date: Tue Jan 31 14:03:02 2006
New Revision: 9025

URL: http://svn.digium.com/view/asterisk?rev=9025&view=rev
Log:
missing files. THanks Damin!

Added:
    team/oej/jitterbuffer/scx_jitterbuf.c
    team/oej/jitterbuffer/scx_jitterbuf.h

Added: team/oej/jitterbuffer/scx_jitterbuf.c
URL: http://svn.digium.com/view/asterisk/team/oej/jitterbuffer/scx_jitterbuf.c?rev=9025&view=auto
==============================================================================
--- team/oej/jitterbuffer/scx_jitterbuf.c (added)
+++ team/oej/jitterbuffer/scx_jitterbuf.c Tue Jan 31 14:03:02 2006
@@ -1,0 +1,376 @@
+/*
+ * scx_jitterbuf: jitterbuffering algorithm
+ *
+ * Copyright (C) 2005, Attractel OOD
+ *
+ * Contributors:
+ * Slav Klenov <slav at securax.org>
+ *
+ * Copyright on this file is disclaimed to Digium for inclusion in Asterisk
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file 
+ * 
+ * \brief Jitterbuffering algorithm.
+ * 
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include "scx_jitterbuf.h"
+
+
+/* private scx_jb structure */
+struct scx_jb
+{
+	struct scx_jb_frame *frames;
+	struct scx_jb_frame *tail;
+	struct scx_jb_conf conf;
+	long rxcore;
+	long delay;
+	long next_delivery;
+	int force_resynch;
+};
+
+
+static struct scx_jb_frame * alloc_jb_frame(struct scx_jb *jb);
+static void release_jb_frame(struct scx_jb *jb, struct scx_jb_frame *frame);
+static void get_jb_head(struct scx_jb *jb, struct scx_jb_frame *frame);
+static int resynch_jb(struct scx_jb *jb, void *data, long ms, long ts, long now);
+
+
+static struct scx_jb_frame * alloc_jb_frame(struct scx_jb *jb)
+{
+	return (struct scx_jb_frame *) calloc(1, sizeof(struct scx_jb_frame));
+}
+
+
+static void release_jb_frame(struct scx_jb *jb, struct scx_jb_frame *frame)
+{
+	free(frame);
+}
+
+
+static void get_jb_head(struct scx_jb *jb, struct scx_jb_frame *frame)
+{
+	struct scx_jb_frame *fr;
+	
+	/* unlink the frame */
+	fr = jb->frames;
+	jb->frames = fr->next;
+	if(jb->frames != NULL)
+	{
+		jb->frames->prev = NULL;
+	}
+	else
+	{
+		/* the jb is empty - update tail */
+		jb->tail = NULL;
+	}
+	
+	/* update next */
+	jb->next_delivery = fr->delivery + fr->ms;
+	
+	/* copy the destination */
+	memcpy(frame, fr, sizeof(struct scx_jb_frame));
+	
+	/* and release the frame */
+	release_jb_frame(jb, fr);
+}
+
+
+struct scx_jb * scx_jb_new(struct scx_jb_conf *conf)
+{
+	struct scx_jb *jb;
+	
+	jb = calloc(1, sizeof(struct scx_jb));
+	if(jb == NULL)
+	{
+		return NULL;
+	}
+	
+	/* First copy our config */
+	memcpy(&jb->conf, conf, sizeof(struct scx_jb_conf));
+	/* we dont need the passed config anymore - continue working with the saved one */
+	conf = &jb->conf;
+	
+	/* validate the configuration */
+	if(conf->jbsize < 1)
+	{
+		conf->jbsize = SCX_JB_SIZE_DEFAULT;
+	}
+	if(conf->resync_threshold < 1)
+	{
+		conf->resync_threshold = SCX_JB_RESYNCH_THRESHOLD_DEFAULT;
+	}
+	
+	/* Set the constant delay to the jitterbuf */
+	jb->delay = conf->jbsize;
+	
+	return jb;
+}
+
+
+void scx_jb_destroy(struct scx_jb *jb)
+{
+	/* jitterbuf MUST be empty before it can be destroyed */
+	assert(jb->frames == NULL);
+	
+	free(jb);
+}
+
+
+static int resynch_jb(struct scx_jb *jb, void *data, long ms, long ts, long now)
+{
+	long diff, offset;
+	struct scx_jb_frame *frame;
+	
+	/* If jb is empty, just reinitialize the jb */
+	if(jb->frames == NULL)
+	{
+		/* debug check: tail should also be NULL */
+		assert(jb->tail == NULL);
+		
+		return scx_jb_put_first(jb, data, ms, ts, now);
+	}
+	
+	/* Adjust all jb state just as the new frame is with delivery = the delivery of the last
+	   frame (e.g. this one with max delivery) + the length of the last frame. */
+	
+	/* Get the diff in timestamps */
+	diff = ts - jb->tail->ts;
+	
+	/* Ideally this should be just the length of the last frame. The deviation is the desired
+	   offset */
+	offset = diff - jb->tail->ms;
+	
+	/* Do we really need to resynch, or this is just a frame for dropping? */
+	if(!jb->force_resynch && (offset < jb->conf.resync_threshold && offset > -jb->conf.resync_threshold))
+	{
+		return SCX_JB_DROP;
+	}
+	
+	/* Reset the force resynch flag */
+	jb->force_resynch = 0;
+	
+	/* apply the offset to the jb state */
+	jb->rxcore -= offset;
+	frame = jb->frames;
+	while(frame)
+	{
+		frame->ts += offset;
+		frame = frame->next;
+	}
+	
+	/* now jb_put() should add the frame at a last position */
+	return scx_jb_put(jb, data, ms, ts, now);
+}
+
+
+void scx_jb_set_force_resynch(struct scx_jb *jb)
+{
+	jb->force_resynch = 1;
+}
+
+
+int scx_jb_put_first(struct scx_jb *jb, void *data, long ms, long ts, long now)
+{
+	/* this is our first frame - set the base of the receivers time */
+	jb->rxcore = now - ts;
+	
+	/* init next for a first time - it should be the time the first frame should be played */
+	jb->next_delivery = now + jb->delay;
+	
+	/* put the frame */
+	return scx_jb_put(jb, data, ms, ts, now);
+}
+
+
+int scx_jb_put(struct scx_jb *jb, void *data, long ms, long ts, long now)
+{
+	struct scx_jb_frame *frame, *next, *newframe;
+	long delivery;
+	
+	/* debug check the validity of the input params */
+	assert(data != NULL);
+	/* do not allow frames shorter than 2 ms */
+	assert(ms >= 2);
+	assert(ts >= 0);
+	assert(now >= 0);
+	
+	delivery = jb->rxcore + jb->delay + ts;
+	
+	/* check if the new frame is not too late */
+	if(delivery < jb->next_delivery)
+	{
+		/* should drop the frame, but let first resynch_jb() check if this is not a jump in ts, or
+		   the force resynch flag was not set. */
+		return resynch_jb(jb, data, ms, ts, now);
+	}
+	
+	/* what if the delivery time is bigger than next + delay? Seems like a frame for the future.
+	   However, allow more resync_threshold ms in advance */
+	if(delivery > jb->next_delivery + jb->delay + jb->conf.resync_threshold)
+	{
+		/* should drop the frame, but let first resynch_jb() check if this is not a jump in ts, or
+		   the force resynch flag was not set. */
+		return resynch_jb(jb, data, ms, ts, now);
+	}
+
+	/* find the right place in the frames list, sorted by delivery time */
+	frame = jb->tail;
+	while(frame != NULL && frame->delivery > delivery)
+	{
+		frame = frame->prev;
+	}
+	
+	/* Check if the new delivery time is not covered already by the chosen frame */
+	if(frame && (frame->delivery == delivery ||
+		         delivery < frame->delivery + frame->ms ||
+		         (frame->next && delivery + ms > frame->next->delivery)))
+	{
+		/* TODO: Should we check for resynch here? Be careful to do not allow threshold smaller than
+		   the size of the jb */
+		
+		/* should drop the frame, but let first resynch_jb() check if this is not a jump in ts, or
+		   the force resynch flag was not set. */
+		return resynch_jb(jb, data, ms, ts, now);
+	}
+	
+	/* Reset the force resynch flag */
+	jb->force_resynch = 0;
+	
+	/* Get a new frame */
+	newframe = alloc_jb_frame(jb);
+	newframe->data = data;
+	newframe->ts = ts;
+	newframe->ms = ms;
+	newframe->delivery = delivery;
+	
+	/* and insert it right on place */
+	if(frame != NULL)
+	{
+		next = frame->next;
+		frame->next = newframe;
+		if(next != NULL)
+		{
+			newframe->next = next;
+			next->prev = newframe;
+		}
+		else
+		{
+			/* insert after the last frame - should update tail */
+			jb->tail = newframe;
+			newframe->next = NULL;
+		}
+		newframe->prev = frame;
+		
+		return SCX_JB_OK;
+	}
+	else if(jb->frames == NULL)
+	{
+		/* the frame list is empty or thats just the first frame ever */
+		/* tail should also be NULL is that case */
+		assert(jb->tail == NULL);
+		jb->frames = jb->tail = newframe;
+		newframe->next = NULL;
+		newframe->prev = NULL;
+		
+		return SCX_JB_OK;
+	}
+	else
+	{
+		/* insert on a first position - should update frames head */
+		newframe->next = jb->frames;
+		newframe->prev = NULL;
+		jb->frames->prev = newframe;
+		jb->frames = newframe;
+		
+		return SCX_JB_OK;
+	}
+}
+
+
+int scx_jb_get(struct scx_jb *jb, struct scx_jb_frame *frame, long now, long interpl)
+{
+	long halflen;
+	
+	assert(now >= 0);
+	assert(interpl >= 2);
+	
+	if(now < jb->next_delivery)
+	{
+		/* too early for the next frame */
+		return SCX_JB_NOFRAME;
+	}
+	
+	/* Is the jb empty? */
+	if(jb->frames == NULL)
+	{
+		/* should interpolate a frame */
+		/* update next */
+		jb->next_delivery += interpl;
+		
+		return SCX_JB_INTERP;
+	}
+	
+	halflen = (long) ((double) jb->frames->ms / 2.0);
+	
+	/* Isn't it too late for the first frame available in the jb? */
+	if(now > jb->frames->delivery + halflen)
+	{
+		/* yes - should drop this frame and update next to point the next frame (get_jb_head() does it) */
+		get_jb_head(jb, frame);
+		
+		return SCX_JB_DROP;
+	}
+	
+	/* isn't it too early to play the first frame available? */
+	if(now < jb->frames->delivery  - halflen)
+	{
+		/* yes - should interpolate one frame */
+		/* update next */
+		jb->next_delivery += interpl;
+		
+		return SCX_JB_INTERP;
+	}
+	
+	/* we have a frame for playing now (get_jb_head() updates next) */
+	get_jb_head(jb, frame);
+	
+	return SCX_JB_OK;
+}
+
+
+long scx_jb_next(struct scx_jb *jb)
+{
+	return jb->next_delivery;
+}
+
+
+int scx_jb_remove(struct scx_jb *jb, struct scx_jb_frame *frameout)
+{
+	if(jb->frames == NULL)
+	{
+		return SCX_JB_NOFRAME;
+	}
+	
+	get_jb_head(jb, frameout);
+	
+	return SCX_JB_OK;
+}
+
+
+

Added: team/oej/jitterbuffer/scx_jitterbuf.h
URL: http://svn.digium.com/view/asterisk/team/oej/jitterbuffer/scx_jitterbuf.h?rev=9025&view=auto
==============================================================================
--- team/oej/jitterbuffer/scx_jitterbuf.h (added)
+++ team/oej/jitterbuffer/scx_jitterbuf.h Tue Jan 31 14:03:02 2006
@@ -1,0 +1,93 @@
+/*
+ * scx_jitterbuf: jitterbuffering algorithm
+ *
+ * Copyright (C) 2005, Attractel OOD
+ *
+ * Contributors:
+ * Slav Klenov <slav at securax.org>
+ *
+ * Copyright on this file is disclaimed to Digium for inclusion in Asterisk
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file 
+ * 
+ * \brief Jitterbuffering algorithm.
+ * 
+ */
+
+#ifndef _SCX_JITTERBUF_H_
+#define _SCX_JITTERBUF_H_
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+
+/* return codes */
+#define SCX_JB_OK		0
+#define SCX_JB_DROP		1
+#define SCX_JB_INTERP	2
+#define SCX_JB_NOFRAME	3
+
+
+/* defaults */
+#define SCX_JB_SIZE_DEFAULT 200
+#define SCX_JB_RESYNCH_THRESHOLD_DEFAULT 1000
+
+
+/* jb configuration properties */
+struct scx_jb_conf
+{
+	long jbsize;
+ 	long resync_threshold;
+};
+
+
+struct scx_jb_frame
+{
+	void *data;
+	long ts;
+	long ms;
+	long delivery;
+	struct scx_jb_frame *next;
+	struct scx_jb_frame *prev;
+};
+
+
+struct scx_jb;
+
+
+/* jb interface */
+
+struct scx_jb * scx_jb_new(struct scx_jb_conf *conf);
+
+void scx_jb_destroy(struct scx_jb *jb);
+
+int scx_jb_put_first(struct scx_jb *jb, void *data, long ms, long ts, long now);
+
+int scx_jb_put(struct scx_jb *jb, void *data, long ms, long ts, long now);
+
+int scx_jb_get(struct scx_jb *jb, struct scx_jb_frame *frame, long now, long interpl);
+
+long scx_jb_next(struct scx_jb *jb);
+
+int scx_jb_remove(struct scx_jb *jb, struct scx_jb_frame *frameout);
+
+void scx_jb_set_force_resynch(struct scx_jb *jb);
+
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif /* _SCX_JITTERBUF_H_ */



More information about the asterisk-commits mailing list