[asterisk-commits] dvossel: trunk r314509 - in /trunk: ./ funcs/ include/asterisk/ main/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Apr 20 15:52:17 CDT 2011


Author: dvossel
Date: Wed Apr 20 15:52:15 2011
New Revision: 314509

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=314509
Log:
Introduction of the JITTERBUFFER dialplan function.

Added:
    trunk/funcs/func_jitterbuffer.c   (with props)
Modified:
    trunk/CHANGES
    trunk/include/asterisk/abstract_jb.h
    trunk/include/asterisk/channel.h
    trunk/main/abstract_jb.c
    trunk/main/channel.c

Modified: trunk/CHANGES
URL: http://svnview.digium.com/svn/asterisk/trunk/CHANGES?view=diff&rev=314509&r1=314508&r2=314509
==============================================================================
--- trunk/CHANGES (original)
+++ trunk/CHANGES Wed Apr 20 15:52:15 2011
@@ -66,6 +66,10 @@
 
 Dialplan Functions
 ------------------
+ * Addition of the JITTERBUFFER dialplan function. This function allows
+   for jitterbuffering to occur on the read side of a channel.  By using
+   this function conference applications such as ConfBridge and MeetMe can
+   have the rx streams jitterbuffered before conference mixing occurs.
  * Added DB_KEYS, which lists the next set of keys in the Asterisk database
    hierarchy.
 

Added: trunk/funcs/func_jitterbuffer.c
URL: http://svnview.digium.com/svn/asterisk/trunk/funcs/func_jitterbuffer.c?view=auto&rev=314509
==============================================================================
--- trunk/funcs/func_jitterbuffer.c (added)
+++ trunk/funcs/func_jitterbuffer.c Wed Apr 20 15:52:15 2011
@@ -1,0 +1,369 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2011, Digium, Inc.
+ *
+ * David Vossel <dvossel at digium.com>
+ *
+ * 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 Put a jitterbuffer on the read side of a channel
+ *
+ * \author David Vossel <dvossel at digium.com>
+ *
+ * \ingroup functions
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/module.h"
+#include "asterisk/channel.h"
+#include "asterisk/framehook.h"
+#include "asterisk/pbx.h"
+#include "asterisk/abstract_jb.h"
+#include "asterisk/timing.h"
+#include "asterisk/app.h"
+
+/*** DOCUMENTATION
+	<function name="JITTERBUFFER" language="en_US">
+		<synopsis>
+			Add a Jitterbuffer to the Read side of the channel.  This dejitters the audio stream before it reaches the Asterisk core. This is a write only function.
+		</synopsis>
+		<syntax>
+			<parameter name="jitterbuffer type" required="true">
+				<para>Jitterbuffer type can be either <literal>fixed</literal> or <literal>adaptive</literal>.</para>
+				<para>Used as follows. </para>
+				<para>Set(JITTERBUFFER(type)=max_size[,resync_threshold[,target_extra]])</para>
+				<para>Set(JITTERBUFFER(type)=default) </para>
+			</parameter>
+		</syntax>
+		<description>
+			<para>max_size: Defaults to 200 ms</para>
+			<para>Length in milliseconds of buffer.</para>
+			<para> </para>
+			<para>resync_threshold: Defaults to 1000ms </para>
+			<para>The length in milliseconds over which a timestamp difference will result in resyncing the jitterbuffer. </para>
+			<para> </para>
+			<para>target_extra: Defaults to 40ms</para>
+			<para>This option only affects the adaptive jitterbuffer. It represents the amount time in milliseconds by which the new jitter buffer will pad its size.</para>
+			<para> </para>
+			<para>Examples:</para>
+			<para>exten => 1,1,Set(JITTERBUFFER(fixed)=default);Fixed with defaults. </para>
+			<para>exten => 1,1,Set(JITTERBUFFER(fixed)=200);Fixed with max size 200ms, default resync threshold and target extra. </para>
+			<para>exten => 1,1,Set(JITTERBUFFER(fixed)=200,1500);Fixed with max size 200ms resync threshold 1500. </para>
+			<para>exten => 1,1,Set(JITTERBUFFER(adaptive)=default);Adaptive with defaults. </para>
+			<para>exten => 1,1,Set(JITTERBUFFER(adaptive)=200,,60);Adaptive with max size 200ms, default resync threshold and 40ms target extra. </para>
+		</description>
+	</function>
+ ***/
+
+#define DEFAULT_TIMER_INTERVAL 20
+#define DEFAULT_SIZE  200
+#define DEFAULT_TARGET_EXTRA  40
+#define DEFAULT_RESYNC  1000
+#define DEFAULT_TYPE AST_JB_FIXED
+
+struct jb_framedata {
+	const struct ast_jb_impl *jb_impl;
+	struct ast_jb_conf jb_conf;
+	struct timeval start_tv;
+	struct ast_format last_format;
+	struct ast_timer *timer;
+	int timer_interval; /* ms between deliveries */
+	int timer_fd;
+	int first;
+	void *jb_obj;
+};
+
+static void jb_framedata_destroy(struct jb_framedata *framedata)
+{
+	if (framedata->timer) {
+		ast_timer_close(framedata->timer);
+		framedata->timer = NULL;
+	}
+	if (framedata->jb_impl && framedata->jb_obj) {
+		struct ast_frame *f;
+		while (framedata->jb_impl->remove(framedata->jb_obj, &f) == AST_JB_IMPL_OK) {
+			ast_frfree(f);
+		}
+		framedata->jb_impl->destroy(framedata->jb_obj);
+		framedata->jb_obj = NULL;
+	}
+	ast_free(framedata);
+}
+
+static void jb_conf_default(struct ast_jb_conf *conf)
+{
+	conf->max_size = DEFAULT_SIZE;
+	conf->resync_threshold = DEFAULT_RESYNC;
+	ast_copy_string(conf->impl, "fixed", sizeof(conf->impl));
+	conf->target_extra = DEFAULT_TARGET_EXTRA;
+}
+
+/* set defaults */
+static int jb_framedata_init(struct jb_framedata *framedata, const char *data, const char *value)
+{
+	int jb_impl_type = DEFAULT_TYPE;
+
+	/* Initialize defaults */
+	framedata->timer_fd = -1;
+	jb_conf_default(&framedata->jb_conf);
+	if (!(framedata->jb_impl = ast_jb_get_impl(jb_impl_type))) {
+		return -1;
+	}
+	if (!(framedata->timer = ast_timer_open())) {
+		return -1;
+	}
+	framedata->timer_fd = ast_timer_fd(framedata->timer);
+	framedata->timer_interval = DEFAULT_TIMER_INTERVAL;
+	ast_timer_set_rate(framedata->timer, 1000 / framedata->timer_interval);
+	framedata->start_tv = ast_tvnow();
+
+
+
+	/* Now check user options to see if any of the defaults need to change. */
+	if (!ast_strlen_zero(data)) {
+		if (!strcasecmp(data, "fixed")) {
+			jb_impl_type = AST_JB_FIXED;
+		} else if (!strcasecmp(data, "adaptive")) {
+			jb_impl_type = AST_JB_ADAPTIVE;
+		} else {
+			ast_log(LOG_WARNING, "Unknown Jitterbuffer type %s. Failed to create jitterbuffer.\n", data);
+			return -1;
+		}
+		ast_copy_string(framedata->jb_conf.impl, data, sizeof(framedata->jb_conf.impl));
+	}
+
+	if (!ast_strlen_zero(value) && strcasecmp(value, "default")) {
+		char *parse = ast_strdupa(value);
+		int res = 0;
+		AST_DECLARE_APP_ARGS(args,
+			AST_APP_ARG(max_size);
+			AST_APP_ARG(resync_threshold);
+			AST_APP_ARG(target_extra);
+		);
+
+		AST_STANDARD_APP_ARGS(args, parse);
+		if (!ast_strlen_zero(args.max_size)) {
+			res |= ast_jb_read_conf(&framedata->jb_conf,
+				"jbmaxsize",
+				args.max_size);
+		}
+		if (!ast_strlen_zero(args.resync_threshold)) {
+			res |= ast_jb_read_conf(&framedata->jb_conf,
+				"jbresyncthreshold",
+				args.resync_threshold);
+		}
+		if (!ast_strlen_zero(args.target_extra)) {
+			res |= ast_jb_read_conf(&framedata->jb_conf,
+				"jbtargetextra",
+				args.target_extra);
+		}
+		if (res) {
+			ast_log(LOG_WARNING, "Invalid jitterbuffer parameters %s\n", value);
+		}
+	}
+
+	/* now that all the user parsing is done and nothing will change, create the jb obj */
+	framedata->jb_obj = framedata->jb_impl->create(&framedata->jb_conf, framedata->jb_conf.resync_threshold);
+	return 0;
+}
+
+static void datastore_destroy_cb(void *data) {
+	ast_free(data);
+	ast_debug(1, "JITTERBUFFER datastore destroyed\n");
+}
+
+static const struct ast_datastore_info jb_datastore = {
+	.type = "jitterbuffer",
+	.destroy = datastore_destroy_cb
+};
+
+static void hook_destroy_cb(void *framedata)
+{
+	ast_debug(1, "JITTERBUFFER hook destroyed\n");
+	jb_framedata_destroy((struct jb_framedata *) framedata);
+}
+
+static struct ast_frame *hook_event_cb(struct ast_channel *chan, struct ast_frame *frame, enum ast_framehook_event event, void *data)
+{
+	struct jb_framedata *framedata = data;
+	struct timeval now_tv;
+	unsigned long now;
+
+	switch (event) {
+	case AST_FRAMEHOOK_EVENT_READ:
+		break;
+	case AST_FRAMEHOOK_EVENT_ATTACHED:
+	case AST_FRAMEHOOK_EVENT_DETACHED:
+	case AST_FRAMEHOOK_EVENT_WRITE:
+		return frame;
+	}
+
+	if (chan->fdno == AST_JITTERBUFFER_FD && framedata->timer) {
+		ast_timer_ack(framedata->timer, 1);
+	}
+
+	if (!frame) {
+		return frame;
+	}
+
+	now_tv = ast_tvnow();
+	now = ast_tvdiff_ms(now_tv, framedata->start_tv);
+
+	if (frame->frametype == AST_FRAME_VOICE) {
+		int res;
+		struct ast_frame *jbframe;
+
+		if (!ast_test_flag(frame, AST_FRFLAG_HAS_TIMING_INFO) || frame->len < 2 || frame->ts < 0) {
+			/* only frames with timing info can enter the jitterbuffer */
+			return frame;
+		}
+
+		jbframe = ast_frisolate(frame);
+		ast_format_copy(&framedata->last_format, &frame->subclass.format);
+
+		if (frame->len && (frame->len != framedata->timer_interval)) {
+			framedata->timer_interval = frame->len;
+			ast_timer_set_rate(framedata->timer, 1000 / framedata->timer_interval);
+		}
+		if (!framedata->first) {
+			framedata->first = 1;
+			res = framedata->jb_impl->put_first(framedata->jb_obj, jbframe, now);
+		} else {
+			res = framedata->jb_impl->put(framedata->jb_obj, jbframe, now);
+		}
+		if (res == AST_JB_IMPL_OK) {
+			frame = &ast_null_frame;
+		}
+	}
+
+	if (frame->frametype == AST_FRAME_NULL) {
+		int res;
+		long next = framedata->jb_impl->next(framedata->jb_obj);
+
+		if (now < next) {
+			return frame;
+		}
+		res = framedata->jb_impl->get(framedata->jb_obj, &frame, now, framedata->timer_interval);
+		switch (res) {
+		case AST_JB_IMPL_OK:
+			/* got it, and pass it through */
+			break;
+		case AST_JB_IMPL_DROP:
+			ast_frfree(frame);
+			frame = &ast_null_frame;
+			break;
+		case AST_JB_IMPL_INTERP:
+			if (framedata->last_format.id) {
+				struct ast_frame tmp = { 0, };
+				tmp.frametype = AST_FRAME_VOICE;
+				ast_format_copy(&tmp.subclass.format, &framedata->last_format);
+				/* example: 8000hz / (1000 / 20ms) = 160 samples */
+				tmp.samples = ast_format_rate(&framedata->last_format) / (1000 / framedata->timer_interval);
+				tmp.delivery = ast_tvadd(framedata->start_tv, ast_samp2tv(next, 1000));
+				tmp.offset = AST_FRIENDLY_OFFSET;
+				tmp.src  = "func_jitterbuffer interpolation";
+				frame = ast_frdup(&tmp);
+				break;
+			}
+			/* else fall through */
+		case AST_JB_IMPL_NOFRAME:
+			frame = &ast_null_frame;
+			break;
+		}
+	}
+
+	return frame;
+}
+
+static int jb_helper(struct ast_channel *chan, const char *cmd, char *data, const char *value)
+{
+	struct jb_framedata *framedata;
+	struct ast_datastore *datastore = NULL;
+	struct ast_framehook_interface interface = {
+		.version = AST_FRAMEHOOK_INTERFACE_VERSION,
+		.event_cb = hook_event_cb,
+		.destroy_cb = hook_destroy_cb,
+	};
+	int i = 0;
+
+	if (!(framedata = ast_calloc(1, sizeof(*framedata)))) {
+		return 0;
+	}
+
+	if (jb_framedata_init(framedata, data, value)) {
+		jb_framedata_destroy(framedata);
+		return 0;
+	}
+
+	interface.data = framedata;
+
+	ast_channel_lock(chan);
+	i = ast_framehook_attach(chan, &interface);
+	if (i >= 0) {
+		int *id;
+		if ((datastore = ast_channel_datastore_find(chan, &jb_datastore, NULL))) {
+			id = datastore->data;
+			ast_framehook_detach(chan, *id);
+			ast_channel_datastore_remove(chan, datastore);
+		}
+
+		if (!(datastore = ast_datastore_alloc(&jb_datastore, NULL))) {
+			ast_framehook_detach(chan, i);
+			ast_channel_unlock(chan);
+			return 0;
+		}
+
+		if (!(id = ast_calloc(1, sizeof(int)))) {
+			ast_datastore_free(datastore);
+			ast_framehook_detach(chan, i);
+			ast_channel_unlock(chan);
+			return 0;
+		}
+
+		*id = i; /* Store off the id. The channel is still locked so it is safe to access this ptr. */
+		datastore->data = id;
+		ast_channel_datastore_add(chan, datastore);
+
+		ast_channel_set_fd(chan, AST_JITTERBUFFER_FD, framedata->timer_fd);
+	} else {
+		jb_framedata_destroy(framedata);
+		framedata = NULL;
+	}
+	ast_channel_unlock(chan);
+
+	return 0;
+}
+
+static struct ast_custom_function jb_function = {
+	.name = "JITTERBUFFER",
+	.write = jb_helper,
+};
+
+static int unload_module(void)
+{
+	return ast_custom_function_unregister(&jb_function);
+}
+
+static int load_module(void)
+{
+	int res = ast_custom_function_register(&jb_function);
+	return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;
+}
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Jitter buffer for read side of channel.");
+

Propchange: trunk/funcs/func_jitterbuffer.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: trunk/funcs/func_jitterbuffer.c
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: trunk/funcs/func_jitterbuffer.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: trunk/include/asterisk/abstract_jb.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/abstract_jb.h?view=diff&rev=314509&r1=314508&r2=314509
==============================================================================
--- trunk/include/asterisk/abstract_jb.h (original)
+++ trunk/include/asterisk/abstract_jb.h Wed Apr 20 15:52:15 2011
@@ -45,6 +45,19 @@
 	AST_JB_ENABLED = (1 << 0),
 	AST_JB_FORCED =  (1 << 1),
 	AST_JB_LOG =     (1 << 2)
+};
+
+enum ast_jb_type {
+	AST_JB_FIXED,
+	AST_JB_ADAPTIVE,
+};
+
+/*! Abstract return codes */
+enum {
+	AST_JB_IMPL_OK,
+	AST_JB_IMPL_DROP,
+	AST_JB_IMPL_INTERP,
+	AST_JB_IMPL_NOFRAME
 };
 
 #define AST_JB_IMPL_NAME_SIZE 12
@@ -77,9 +90,44 @@
 #define AST_JB_CONF_IMPL "impl"
 #define AST_JB_CONF_LOG "log"
 
-
-struct ast_jb_impl;
-
+/* Hooks for the abstract jb implementation */
+/*! \brief Create */
+typedef void * (*jb_create_impl)(struct ast_jb_conf *general_config, long resynch_threshold);
+/*! \brief Destroy */
+typedef void (*jb_destroy_impl)(void *jb);
+/*! \brief Put first frame */
+typedef int (*jb_put_first_impl)(void *jb, struct ast_frame *fin, long now);
+/*! \brief Put frame */
+typedef int (*jb_put_impl)(void *jb, struct ast_frame *fin, long now);
+/*! \brief Get frame for now */
+typedef int (*jb_get_impl)(void *jb, struct ast_frame **fout, long now, long interpl);
+/*! \brief Get next */
+typedef long (*jb_next_impl)(void *jb);
+/*! \brief Remove first frame */
+typedef int (*jb_remove_impl)(void *jb, struct ast_frame **fout);
+/*! \brief Force resynch */
+typedef void (*jb_force_resynch_impl)(void *jb);
+/*! \brief Empty and reset jb */
+typedef void (*jb_empty_and_reset_impl)(void *jb);
+
+
+/*!
+ * \brief Jitterbuffer implementation struct.
+ */
+struct ast_jb_impl
+{
+	char name[AST_JB_IMPL_NAME_SIZE];
+	enum ast_jb_type type;
+	jb_create_impl create;
+	jb_destroy_impl destroy;
+	jb_put_first_impl put_first;
+	jb_put_impl put;
+	jb_get_impl get;
+	jb_next_impl next;
+	jb_remove_impl remove;
+	jb_force_resynch_impl force_resync;
+	jb_empty_and_reset_impl empty_and_reset;
+};
 
 /*!
  * \brief General jitterbuffer state.
@@ -224,6 +272,8 @@
  */
 void ast_jb_empty_and_reset(struct ast_channel *c0, struct ast_channel *c1);
 
+const struct ast_jb_impl *ast_jb_get_impl(enum ast_jb_type type);
+
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif

Modified: trunk/include/asterisk/channel.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/channel.h?view=diff&rev=314509&r1=314508&r2=314509
==============================================================================
--- trunk/include/asterisk/channel.h (original)
+++ trunk/include/asterisk/channel.h Wed Apr 20 15:52:15 2011
@@ -154,7 +154,7 @@
 
 #define DATASTORE_INHERIT_FOREVER	INT_MAX
 
-#define AST_MAX_FDS		10
+#define AST_MAX_FDS		11
 /*
  * We have AST_MAX_FDS file descriptors in a channel.
  * Some of them have a fixed use:
@@ -163,6 +163,7 @@
 #define AST_TIMING_FD	(AST_MAX_FDS-2)		/*!< used for timingfd */
 #define AST_AGENT_FD	(AST_MAX_FDS-3)		/*!< used by agents for pass through */
 #define AST_GENERATOR_FD	(AST_MAX_FDS-4)	/*!< used by generator */
+#define AST_JITTERBUFFER_FD	(AST_MAX_FDS-5)	/*!< used by generator */
 
 enum ast_bridge_result {
 	AST_BRIDGE_COMPLETE = 0,

Modified: trunk/main/abstract_jb.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/abstract_jb.c?view=diff&rev=314509&r1=314508&r2=314509
==============================================================================
--- trunk/main/abstract_jb.c (original)
+++ trunk/main/abstract_jb.c Wed Apr 20 15:52:15 2011
@@ -49,43 +49,6 @@
 	JB_CREATED =              (1 << 2)
 };
 
-/* Hooks for the abstract jb implementation */
-
-/*! \brief Create */
-typedef void * (*jb_create_impl)(struct ast_jb_conf *general_config, long resynch_threshold);
-/*! \brief Destroy */
-typedef void (*jb_destroy_impl)(void *jb);
-/*! \brief Put first frame */
-typedef int (*jb_put_first_impl)(void *jb, struct ast_frame *fin, long now);
-/*! \brief Put frame */
-typedef int (*jb_put_impl)(void *jb, struct ast_frame *fin, long now);
-/*! \brief Get frame for now */
-typedef int (*jb_get_impl)(void *jb, struct ast_frame **fout, long now, long interpl);
-/*! \brief Get next */
-typedef long (*jb_next_impl)(void *jb);
-/*! \brief Remove first frame */
-typedef int (*jb_remove_impl)(void *jb, struct ast_frame **fout);
-/*! \brief Force resynch */
-typedef void (*jb_force_resynch_impl)(void *jb);
-/*! \brief Empty and reset jb */
-typedef void (*jb_empty_and_reset_impl)(void *jb);
-
-/*!
- * \brief Jitterbuffer implementation private struct.
- */
-struct ast_jb_impl
-{
-	char name[AST_JB_IMPL_NAME_SIZE];
-	jb_create_impl create;
-	jb_destroy_impl destroy;
-	jb_put_first_impl put_first;
-	jb_put_impl put;
-	jb_get_impl get;
-	jb_next_impl next;
-	jb_remove_impl remove;
-	jb_force_resynch_impl force_resync;
-	jb_empty_and_reset_impl empty_and_reset;
-};
 
 /* Implementation functions */
 /* fixed */
@@ -113,6 +76,7 @@
 static const struct ast_jb_impl avail_impl[] = {
 	{
 		.name = "fixed",
+		.type = AST_JB_FIXED,
 		.create = jb_create_fixed,
 		.destroy = jb_destroy_fixed,
 		.put_first = jb_put_first_fixed,
@@ -125,6 +89,7 @@
 	},
 	{
 		.name = "adaptive",
+		.type = AST_JB_ADAPTIVE,
 		.create = jb_create_adaptive,
 		.destroy = jb_destroy_adaptive,
 		.put_first = jb_put_first_adaptive,
@@ -139,20 +104,11 @@
 
 static int default_impl = 0;
 
-
-/*! Abstract return codes */
-enum {
-	JB_IMPL_OK,
-	JB_IMPL_DROP,
-	JB_IMPL_INTERP,
-	JB_IMPL_NOFRAME
-};
-
 /* Translations between impl and abstract return codes */
 static const int fixed_to_abstract_code[] =
-	{JB_IMPL_OK, JB_IMPL_DROP, JB_IMPL_INTERP, JB_IMPL_NOFRAME};
+	{AST_JB_IMPL_OK, AST_JB_IMPL_DROP, AST_JB_IMPL_INTERP, AST_JB_IMPL_NOFRAME};
 static const int adaptive_to_abstract_code[] =
-	{JB_IMPL_OK, JB_IMPL_NOFRAME, JB_IMPL_NOFRAME, JB_IMPL_INTERP, JB_IMPL_DROP, JB_IMPL_OK};
+	{AST_JB_IMPL_OK, AST_JB_IMPL_NOFRAME, AST_JB_IMPL_NOFRAME, AST_JB_IMPL_INTERP, AST_JB_IMPL_DROP, AST_JB_IMPL_OK};
 
 /* JB_GET actions (used only for the frames log) */
 static const char * const jb_get_actions[] = {"Delivered", "Dropped", "Interpolated", "No"};
@@ -346,7 +302,7 @@
 		return 0;
 	} else {
 		now = get_now(jb, NULL);
-		if (jbimpl->put(jbobj, frr, now) != JB_IMPL_OK) {
+		if (jbimpl->put(jbobj, frr, now) != AST_JB_IMPL_OK) {
 			jb_framelog("JB_PUT {now=%ld}: Dropped frame with ts=%ld and len=%ld\n", now, frr->ts, frr->len);
 			ast_frfree(frr);
 			/*return -1;*/
@@ -403,16 +359,16 @@
 		res = jbimpl->get(jbobj, &f, now, interpolation_len);
 
 		switch (res) {
-		case JB_IMPL_OK:
+		case AST_JB_IMPL_OK:
 			/* deliver the frame */
 			ast_write(chan, f);
-		case JB_IMPL_DROP:
+		case AST_JB_IMPL_DROP:
 			jb_framelog("\tJB_GET {now=%ld}: %s frame with ts=%ld and len=%ld\n",
 				now, jb_get_actions[res], f->ts, f->len);
 			ast_format_copy(&jb->last_format, &f->subclass.format);
 			ast_frfree(f);
 			break;
-		case JB_IMPL_INTERP:
+		case AST_JB_IMPL_INTERP:
 			/* interpolate a frame */
 			f = &finterp;
 			ast_format_copy(&f->subclass.format, &jb->last_format);
@@ -424,9 +380,9 @@
 			ast_write(chan, f);
 			jb_framelog("\tJB_GET {now=%ld}: Interpolated frame with len=%d\n", now, interpolation_len);
 			break;
-		case JB_IMPL_NOFRAME:
+		case AST_JB_IMPL_NOFRAME:
 			ast_log(LOG_WARNING,
-				"JB_IMPL_NOFRAME is returned from the %s jb when now=%ld >= next=%ld, jbnext=%ld!\n",
+				"AST_JB_IMPL_NOFRAME is returned from the %s jb when now=%ld >= next=%ld, jbnext=%ld!\n",
 				jbimpl->name, now, jb->next, jbimpl->next(jbobj));
 			jb_framelog("\tJB_GET {now=%ld}: No frame for now!?\n", now);
 			return;
@@ -464,7 +420,7 @@
 
 	/* The result of putting the first frame should not differ from OK. However, its possible
 	   some implementations (i.e. adaptive's when resynch_threshold is specified) to drop it. */
-	if (res != JB_IMPL_OK) {
+	if (res != AST_JB_IMPL_OK) {
 		ast_log(LOG_WARNING, "Failed to put first frame in the jitterbuffer on channel '%s'\n", chan->name);
 		/*
 		jbimpl->destroy(jbobj);
@@ -508,7 +464,7 @@
 			}
 		}
 
-		if (res == JB_IMPL_OK) {
+		if (res == AST_JB_IMPL_OK) {
 			jb_framelog("JB_PUT_FIRST {now=%ld}: Queued frame with ts=%ld and len=%ld\n",
 				now, frr->ts, frr->len);
 		} else {
@@ -520,7 +476,7 @@
 	ast_verb(3, "%s jitterbuffer created on channel %s\n", jbimpl->name, chan->name);
 
 	/* Free the frame if it has not been queued in the jb */
-	if (res != JB_IMPL_OK) {
+	if (res != AST_JB_IMPL_OK) {
 		ast_frfree(frr);
 	}
 
@@ -542,7 +498,7 @@
 
 	if (ast_test_flag(jb, JB_CREATED)) {
 		/* Remove and free all frames still queued in jb */
-		while (jbimpl->remove(jbobj, &f) == JB_IMPL_OK) {
+		while (jbimpl->remove(jbobj, &f) == AST_JB_IMPL_OK) {
 			ast_frfree(f);
 		}
 
@@ -831,3 +787,14 @@
 
 	jb_reset(adaptivejb);
 }
+
+const struct ast_jb_impl *ast_jb_get_impl(enum ast_jb_type type)
+{
+	int i;
+	for (i = 0; i < ARRAY_LEN(avail_impl); i++) {
+		if (avail_impl[i].type == type) {
+			return &avail_impl[i];
+		}
+	}
+	return NULL;
+}

Modified: trunk/main/channel.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/channel.c?view=diff&rev=314509&r1=314508&r2=314509
==============================================================================
--- trunk/main/channel.c (original)
+++ trunk/main/channel.c Wed Apr 20 15:52:15 2011
@@ -3878,15 +3878,15 @@
 			ast_log(LOG_WARNING, "No read routine on channel %s\n", chan->name);
 	}
 
+	/* Perform the framehook read event here. After the frame enters the framehook list
+	 * there is no telling what will happen, <insert mad scientist laugh here>!!! */
+	f = ast_framehook_list_read_event(chan->framehooks, f);
+
 	/*
 	 * Reset the recorded file descriptor that triggered this read so that we can
 	 * easily detect when ast_read() is called without properly using ast_waitfor().
 	 */
 	chan->fdno = -1;
-
-	/* Perform the framehook read event here. After the frame enters the framehook list
-	 * there is no telling what will happen, <insert mad scientist laugh here>!!! */
-	f = ast_framehook_list_read_event(chan->framehooks, f);
 
 	if (f) {
 		struct ast_frame *readq_tail = AST_LIST_LAST(&chan->readq);




More information about the asterisk-commits mailing list