[asterisk-commits] rmudgett: branch rmudgett/bridge_phase r387627 - in /team/rmudgett/bridge_pha...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri May 3 19:08:24 CDT 2013


Author: rmudgett
Date: Fri May  3 19:08:21 2013
New Revision: 387627

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=387627
Log:
Initial separation of local channel code from unreal local channel derivative framework.

Still to do:
* Rename ast_bridge_local_optimized_out() to ast_bridge_unreal_optimized_out().
* Create ast_local_setup_bridge().
* Create ast_local_setup_masquerade().
* Create ast_local_setup_dialplan().
* Separate local_call() from unreal channel start.
* Separate local_alloc() from unreal private setup.
* Separate local_new() from unreal channel setup.
* Create ast_unreal_new().
* Separate local_request() from unreal channel setup.
* Move channels/chan_local.c to main/core_local.c and make it not dynamically loadable.

Added:
    team/rmudgett/bridge_phase/include/asterisk/core_local.h   (with props)
Modified:
    team/rmudgett/bridge_phase/channels/chan_local.c

Modified: team/rmudgett/bridge_phase/channels/chan_local.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/channels/chan_local.c?view=diff&rev=387627&r1=387626&r2=387627
==============================================================================
--- team/rmudgett/bridge_phase/channels/chan_local.c (original)
+++ team/rmudgett/bridge_phase/channels/chan_local.c Fri May  3 19:08:21 2013
@@ -55,6 +55,7 @@
 #include "asterisk/devicestate.h"
 #include "asterisk/astobj2.h"
 #include "asterisk/bridging.h"
+#include "asterisk/core_local.h"
 
 /*** DOCUMENTATION
 	<manager name="LocalOptimizeAway" language="en_US">
@@ -77,57 +78,36 @@
 
 static const char tdesc[] = "Local Proxy Channel Driver";
 
-#define IS_OUTBOUND(a,b) (a == b->chan ? 1 : 0)
-
 static struct ao2_container *locals;
 
 static unsigned int name_sequence = 0;
 
-static struct ast_jb_conf g_jb_conf = {
-	.flags = 0,
-	.max_size = -1,
-	.resync_threshold = -1,
-	.impl = "",
-	.target_extra = -1,
-};
-
 static struct ast_channel *local_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause);
-static int local_digit_begin(struct ast_channel *ast, char digit);
-static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
 static int local_call(struct ast_channel *ast, const char *dest, int timeout);
 static int local_hangup(struct ast_channel *ast);
-static int local_answer(struct ast_channel *ast);
-static struct ast_frame *local_read(struct ast_channel *ast);
-static int local_write(struct ast_channel *ast, struct ast_frame *f);
-static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
-static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
-static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
-static int local_sendtext(struct ast_channel *ast, const char *text);
 static int local_devicestate(const char *data);
-static int local_queryoption(struct ast_channel *ast, int option, void *data, int *datalen);
-static int local_setoption(struct ast_channel *chan, int option, void *data, int datalen);
 
 /* PBX interface structure for channel registration */
 static struct ast_channel_tech local_tech = {
 	.type = "Local",
 	.description = tdesc,
 	.requester = local_request,
-	.send_digit_begin = local_digit_begin,
-	.send_digit_end = local_digit_end,
+	.send_digit_begin = ast_unreal_digit_begin,
+	.send_digit_end = ast_unreal_digit_end,
 	.call = local_call,
 	.hangup = local_hangup,
-	.answer = local_answer,
-	.read = local_read,
-	.write = local_write,
-	.write_video = local_write,
-	.exception = local_read,
-	.indicate = local_indicate,
-	.fixup = local_fixup,
-	.send_html = local_sendhtml,
-	.send_text = local_sendtext,
+	.answer = ast_unreal_answer,
+	.read = ast_unreal_read,
+	.write = ast_unreal_write,
+	.write_video = ast_unreal_write,
+	.exception = ast_unreal_read,
+	.indicate = ast_unreal_indicate,
+	.fixup = ast_unreal_fixup,
+	.send_html = ast_unreal_sendhtml,
+	.send_text = ast_unreal_sendtext,
 	.devicestate = local_devicestate,
-	.queryoption = local_queryoption,
-	.setoption = local_setoption,
+	.queryoption = ast_unreal_queryoption,
+	.setoption = ast_unreal_setoption,
 };
 
 /*!
@@ -135,32 +115,16 @@
  *
  * The local channel pvt has two ast_chan objects - the "owner" and the "next channel", the outbound channel
  *
- * ast_chan owner -> local_pvt -> ast_chan chan -> yet-another-pvt-depending-on-channel-type
+ * ast_chan owner -> ast_local_pvt -> ast_chan chan
  */
-struct local_pvt {
-	struct ast_channel *owner;      /*!< Master Channel - Bridging happens here */
-	struct ast_channel *chan;       /*!< Outbound channel - PBX is run here */
-	struct ast_format_cap *reqcap;  /*!< Requested format capabilities */
-	struct ast_jb_conf jb_conf;     /*!< jitterbuffer configuration for this local channel */
-	unsigned int flags;             /*!< Private flags */
+struct ast_local_pvt {
+	/*! Unreal channel driver base class values. */
+	struct ast_unreal_pvt base;
 	char context[AST_MAX_CONTEXT];  /*!< Context to call */
 	char exten[AST_MAX_EXTENSION];  /*!< Extension to call */
 };
 
-#define LOCAL_LAUNCHED_PBX    (1 << 0) /*!< PBX was launched */
-#define LOCAL_NO_OPTIMIZATION (1 << 1) /*!< Do not optimize using masquerading */
-#define LOCAL_MOH_PASSTHRU    (1 << 2) /*!< Pass through music on hold start/stop frames */
-
-/*!
- * \brief Send a pvt in with no locks held and get all locks
- *
- * \note NO locks should be held prior to calling this function
- * \note The pvt must have a ref held before calling this function
- * \note if outchan or outowner is set != NULL after calling this function
- *       those channels are locked and reffed.
- * \note Batman.
- */
-static void awesome_locking(struct local_pvt *p, struct ast_channel **outchan, struct ast_channel **outowner)
+void ast_unreal_lock_all(struct ast_unreal_pvt *p, struct ast_channel **outchan, struct ast_channel **outowner)
 {
 	struct ast_channel *chan = NULL;
 	struct ast_channel *owner = NULL;
@@ -209,11 +173,42 @@
 	*outchan = p->chan;
 }
 
+struct ast_channel *ast_local_get_peer(struct ast_channel *ast)
+{
+	struct ast_local_pvt *p = ast_channel_tech_pvt(ast);
+	struct ast_local_pvt *found;
+	struct ast_channel *peer;
+
+	if (!p) {
+		return NULL;
+	}
+
+	found = p ? ao2_find(locals, p, 0) : NULL;
+	if (!found) {
+		/* ast is either not a local channel or it has alredy been hungup */
+		return NULL;
+	}
+	ao2_lock(found);
+	if (ast == p->base.owner) {
+		peer = p->base.chan;
+	} else if (ast == p->base.chan) {
+		peer = p->base.owner;
+	} else {
+		peer = NULL;
+	}
+	if (peer) {
+		ast_channel_ref(peer);
+	}
+	ao2_unlock(found);
+	ao2_ref(found, -1);
+	return peer;
+}
+
 /* Called with ast locked */
-static int local_setoption(struct ast_channel *ast, int option, void *data, int datalen)
+int ast_unreal_setoption(struct ast_channel *ast, int option, void *data, int datalen)
 {
 	int res = 0;
-	struct local_pvt *p;
+	struct ast_unreal_pvt *p;
 	struct ast_channel *otherchan = NULL;
 	ast_chan_write_info_t *write_info;
 
@@ -230,7 +225,7 @@
 
 	if (!strcmp(write_info->function, "CHANNEL")
 		&& !strncasecmp(write_info->data, "hangup_handler_", 15)) {
-		/* Block CHANNEL(hangup_handler_xxx) writes to the other local channel. */
+		/* Block CHANNEL(hangup_handler_xxx) writes to the other unreal channel. */
 		return 0;
 	}
 
@@ -271,11 +266,12 @@
 /*! \brief Adds devicestate to local channels */
 static int local_devicestate(const char *data)
 {
+	int is_inuse = 0;
+	int res = AST_DEVICE_INVALID;
 	char *exten = ast_strdupa(data);
 	char *context;
 	char *opts;
-	int res;
-	struct local_pvt *lp;
+	struct ast_local_pvt *lp;
 	struct ao2_iterator it;
 
 	/* Strip options if they exist */
@@ -292,23 +288,17 @@
 	}
 	*context++ = '\0';
 
-	ast_debug(3, "Checking if extension %s@%s exists (devicestate)\n", exten, context);
-	res = ast_exists_extension(NULL, context, exten, 1, NULL);
-	if (!res) {
-		return AST_DEVICE_INVALID;
-	}
-
-	res = AST_DEVICE_NOT_INUSE;
-
 	it = ao2_iterator_init(locals, 0);
 	for (; (lp = ao2_iterator_next(&it)); ao2_ref(lp, -1)) {
-		int is_inuse;
-
 		ao2_lock(lp);
-		is_inuse = !strcmp(exten, lp->exten)
-			&& !strcmp(context, lp->context)
-			&& lp->owner
-			&& ast_test_flag(lp, LOCAL_LAUNCHED_PBX);
+		if (!strcmp(exten, lp->exten)
+			&& !strcmp(context, lp->context)) {
+			res = AST_DEVICE_NOT_INUSE;
+			if (lp->base.owner
+				&& ast_test_flag(&lp->base, AST_UNREAL_CARETAKER_THREAD)) {
+				is_inuse = 1;
+			}
+		}
 		ao2_unlock(lp);
 		if (is_inuse) {
 			res = AST_DEVICE_INUSE;
@@ -318,13 +308,20 @@
 	}
 	ao2_iterator_destroy(&it);
 
+	if (res == AST_DEVICE_INVALID) {
+		ast_debug(3, "Checking if extension %s@%s exists (devicestate)\n", exten, context);
+		if (ast_exists_extension(NULL, context, exten, 1, NULL)) {
+			res = AST_DEVICE_NOT_INUSE;
+		}
+	}
+
 	return res;
 }
 
 /* Called with ast locked */
-static int local_queryoption(struct ast_channel *ast, int option, void *data, int *datalen)
-{
-	struct local_pvt *p;
+int ast_unreal_queryoption(struct ast_channel *ast, int option, void *data, int *datalen)
+{
+	struct ast_unreal_pvt *p;
 	struct ast_channel *peer;
 	struct ast_channel *other;
 	int res = 0;
@@ -340,7 +337,7 @@
 	}
 
 	ao2_lock(p);
-	other = IS_OUTBOUND(ast, p) ? p->owner : p->chan;
+	other = AST_UNREAL_IS_OUTBOUND(ast, p) ? p->owner : p->chan;
 	if (!other) {
 		ao2_unlock(p);
 		return -1;
@@ -363,16 +360,16 @@
 /*!
  * \brief queue a frame onto either the p->owner or p->chan
  *
- * \note the local_pvt MUST have it's ref count bumped before entering this function and
+ * \note the ast_unreal_pvt MUST have it's ref count bumped before entering this function and
  * decremented after this function is called.  This is a side effect of the deadlock
  * avoidance that is necessary to lock 2 channels and a tech_pvt.  Without a ref counted
- * local_pvt, it is impossible to guarantee it will not be destroyed by another thread
+ * ast_unreal_pvt, it is impossible to guarantee it will not be destroyed by another thread
  * during deadlock avoidance.
  */
-static int local_queue_frame(struct local_pvt *p, int isoutbound, struct ast_frame *f,
+static int unreal_queue_frame(struct ast_unreal_pvt *p, int isoutbound, struct ast_frame *f,
 	struct ast_channel *us, int us_locked)
 {
-	struct ast_channel *other = NULL;
+	struct ast_channel *other;
 
 	/* Recalculate outbound channel */
 	other = isoutbound ? p->owner : p->chan;
@@ -380,7 +377,7 @@
 		return 0;
 	}
 
-	/* do not queue frame if generator is on both local channels */
+	/* do not queue frame if generator is on both unreal channels */
 	if (us && ast_channel_generator(us) && ast_channel_generator(other)) {
 		return 0;
 	}
@@ -407,9 +404,9 @@
 	return 0;
 }
 
-static int local_answer(struct ast_channel *ast)
-{
-	struct local_pvt *p = ast_channel_tech_pvt(ast);
+int ast_unreal_answer(struct ast_channel *ast)
+{
+	struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
 	int isoutbound;
 	int res = -1;
 
@@ -419,14 +416,15 @@
 
 	ao2_ref(p, 1);
 	ao2_lock(p);
-	isoutbound = IS_OUTBOUND(ast, p);
+	isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
 	if (isoutbound) {
 		/* Pass along answer since somebody answered us */
 		struct ast_frame answer = { AST_FRAME_CONTROL, { AST_CONTROL_ANSWER } };
 
-		res = local_queue_frame(p, isoutbound, &answer, ast, 1);
+		res = unreal_queue_frame(p, isoutbound, &answer, ast, 1);
 	} else {
-		ast_log(LOG_WARNING, "Huh?  Local is being asked to answer?\n");
+		ast_log(LOG_WARNING, "Huh?  %s is being asked to answer?\n",
+			ast_channel_name(ast));
 	}
 	ao2_unlock(p);
 	ao2_ref(p, -1);
@@ -435,25 +433,26 @@
 
 /*!
  * \internal
- * \brief Check and optimize out the local channels between bridges.
+ * \brief Check and optimize out the unreal channels between bridges.
  * \since 12.0.0
  *
- * \param ast Channel writing a frame into the local channels.
+ * \param ast Channel writing a frame into the unreal channels.
  * \param p Local channel private.
  *
  * \note It is assumed that ast is locked.
  * \note It is assumed that p is locked.
  *
- * \retval 0 if local channels were not optimized out.
- * \retval non-zero if local channels were optimized out.
+ * \retval 0 if unreal channels were not optimized out.
+ * \retval non-zero if unreal channels were optimized out.
  */
-static int got_optimized_out(struct ast_channel *ast, struct local_pvt *p)
+static int got_optimized_out(struct ast_channel *ast, struct ast_unreal_pvt *p)
 {
 	/* Do a few conditional checks early on just to see if this optimization is possible */
-	if (ast_test_flag(p, LOCAL_NO_OPTIMIZATION) || !p->chan || !p->owner) {
+	if (ast_test_flag(p, AST_UNREAL_NO_OPTIMIZATION) || !p->chan || !p->owner) {
 		return 0;
 	}
 	if (ast == p->owner) {
+/* BUGBUG need to rename ast_bridge_local_optimized_out() to ast_bridge_unreal_optimized_out(). */
 		return ast_bridge_local_optimized_out(p->owner, p->chan);
 	}
 	if (ast == p->chan) {
@@ -463,14 +462,14 @@
 	return 0;
 }
 
-static struct ast_frame  *local_read(struct ast_channel *ast)
+struct ast_frame  *ast_unreal_read(struct ast_channel *ast)
 {
 	return &ast_null_frame;
 }
 
-static int local_write(struct ast_channel *ast, struct ast_frame *f)
-{
-	struct local_pvt *p = ast_channel_tech_pvt(ast);
+int ast_unreal_write(struct ast_channel *ast, struct ast_frame *f)
+{
+	struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
 	int res = -1;
 
 	if (!p) {
@@ -488,7 +487,7 @@
 		}
 		/* fall through */
 	default:
-		res = local_queue_frame(p, IS_OUTBOUND(ast, p), f, ast, 1);
+		res = unreal_queue_frame(p, AST_UNREAL_IS_OUTBOUND(ast, p), f, ast, 1);
 		break;
 	}
 	ao2_unlock(p);
@@ -497,9 +496,9 @@
 	return res;
 }
 
-static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
-{
-	struct local_pvt *p = ast_channel_tech_pvt(newchan);
+int ast_unreal_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
+{
+	struct ast_unreal_pvt *p = ast_channel_tech_pvt(newchan);
 	struct ast_bridge *bridge_owner;
 	struct ast_bridge *bridge_chan;
 
@@ -539,9 +538,9 @@
 	return 0;
 }
 
-static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
-{
-	struct local_pvt *p = ast_channel_tech_pvt(ast);
+int ast_unreal_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
+{
+	struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
 	int res = 0;
 	struct ast_frame f = { AST_FRAME_CONTROL, };
 	int isoutbound;
@@ -550,26 +549,31 @@
 		return -1;
 	}
 
-	ao2_ref(p, 1); /* ref for local_queue_frame */
+	ao2_ref(p, 1); /* ref for unreal_queue_frame */
 
 	/* If this is an MOH hold or unhold, do it on the Local channel versus real channel */
-	if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_HOLD) {
+	if (!ast_test_flag(p, AST_UNREAL_MOH_PASSTHRU) && condition == AST_CONTROL_HOLD) {
 		ast_moh_start(ast, data, NULL);
-	} else if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_UNHOLD) {
+	} else if (!ast_test_flag(p, AST_UNREAL_MOH_PASSTHRU) && condition == AST_CONTROL_UNHOLD) {
 		ast_moh_stop(ast);
 	} else if (condition == AST_CONTROL_CONNECTED_LINE || condition == AST_CONTROL_REDIRECTING) {
 		struct ast_channel *this_channel;
 		struct ast_channel *the_other_channel;
 
-		/* A connected line update frame may only contain a partial amount of data, such
-		 * as just a source, or just a ton, and not the full amount of information. However,
-		 * the collected information is all stored in the outgoing channel's connectedline
-		 * structure, so when receiving a connected line update on an outgoing local channel,
-		 * we need to transmit the collected connected line information instead of whatever
-		 * happens to be in this control frame. The same applies for redirecting information, which
-		 * is why it is handled here as well.*/
+		/*
+		 * A connected line update frame may only contain a partial
+		 * amount of data, such as just a source, or just a ton, and not
+		 * the full amount of information.  However, the collected
+		 * information is all stored in the outgoing channel's
+		 * connectedline structure, so when receiving a connected line
+		 * update on an outgoing unreal channel, we need to transmit the
+		 * collected connected line information instead of whatever
+		 * happens to be in this control frame.  The same applies for
+		 * redirecting information, which is why it is handled here as
+		 * well.
+		 */
 		ao2_lock(p);
-		isoutbound = IS_OUTBOUND(ast, p);
+		isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
 		if (isoutbound) {
 			this_channel = p->chan;
 			the_other_channel = p->owner;
@@ -590,7 +594,7 @@
 			}
 			f.subclass.integer = condition;
 			f.data.ptr = frame_data;
-			res = local_queue_frame(p, isoutbound, &f, ast, 1);
+			res = unreal_queue_frame(p, isoutbound, &f, ast, 1);
 		}
 		ao2_unlock(p);
 	} else {
@@ -598,15 +602,15 @@
 		ao2_lock(p);
 		/*
 		 * Block -1 stop tones events if we are to be optimized out.  We
-		 * don't need a flurry of these events on a local channel chain
+		 * don't need a flurry of these events on a unreal channel chain
 		 * when initially connected to slow the optimization process.
 		 */
-		if (0 <= condition || ast_test_flag(p, LOCAL_NO_OPTIMIZATION)) {
-			isoutbound = IS_OUTBOUND(ast, p);
+		if (0 <= condition || ast_test_flag(p, AST_UNREAL_NO_OPTIMIZATION)) {
+			isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
 			f.subclass.integer = condition;
 			f.data.ptr = (void *) data;
 			f.datalen = datalen;
-			res = local_queue_frame(p, isoutbound, &f, ast, 1);
+			res = unreal_queue_frame(p, isoutbound, &f, ast, 1);
 
 			if (!res && condition == AST_CONTROL_T38_PARAMETERS
 				&& datalen == sizeof(struct ast_control_t38_parameters)) {
@@ -626,9 +630,9 @@
 	return res;
 }
 
-static int local_digit_begin(struct ast_channel *ast, char digit)
-{
-	struct local_pvt *p = ast_channel_tech_pvt(ast);
+int ast_unreal_digit_begin(struct ast_channel *ast, char digit)
+{
+	struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
 	int res = -1;
 	struct ast_frame f = { AST_FRAME_DTMF_BEGIN, };
 	int isoutbound;
@@ -637,20 +641,20 @@
 		return -1;
 	}
 
-	ao2_ref(p, 1); /* ref for local_queue_frame */
+	ao2_ref(p, 1); /* ref for unreal_queue_frame */
 	ao2_lock(p);
-	isoutbound = IS_OUTBOUND(ast, p);
+	isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
 	f.subclass.integer = digit;
-	res = local_queue_frame(p, isoutbound, &f, ast, 0);
+	res = unreal_queue_frame(p, isoutbound, &f, ast, 0);
 	ao2_unlock(p);
 	ao2_ref(p, -1);
 
 	return res;
 }
 
-static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
-{
-	struct local_pvt *p = ast_channel_tech_pvt(ast);
+int ast_unreal_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
+{
+	struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
 	int res = -1;
 	struct ast_frame f = { AST_FRAME_DTMF_END, };
 	int isoutbound;
@@ -659,21 +663,21 @@
 		return -1;
 	}
 
-	ao2_ref(p, 1); /* ref for local_queue_frame */
+	ao2_ref(p, 1); /* ref for unreal_queue_frame */
 	ao2_lock(p);
-	isoutbound = IS_OUTBOUND(ast, p);
+	isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
 	f.subclass.integer = digit;
 	f.len = duration;
-	res = local_queue_frame(p, isoutbound, &f, ast, 0);
+	res = unreal_queue_frame(p, isoutbound, &f, ast, 0);
 	ao2_unlock(p);
 	ao2_ref(p, -1);
 
 	return res;
 }
 
-static int local_sendtext(struct ast_channel *ast, const char *text)
-{
-	struct local_pvt *p = ast_channel_tech_pvt(ast);
+int ast_unreal_sendtext(struct ast_channel *ast, const char *text)
+{
+	struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
 	int res = -1;
 	struct ast_frame f = { AST_FRAME_TEXT, };
 	int isoutbound;
@@ -682,20 +686,20 @@
 		return -1;
 	}
 
-	ao2_ref(p, 1); /* ref for local_queue_frame */
+	ao2_ref(p, 1); /* ref for unreal_queue_frame */
 	ao2_lock(p);
-	isoutbound = IS_OUTBOUND(ast, p);
+	isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
 	f.data.ptr = (char *) text;
 	f.datalen = strlen(text) + 1;
-	res = local_queue_frame(p, isoutbound, &f, ast, 0);
+	res = unreal_queue_frame(p, isoutbound, &f, ast, 0);
 	ao2_unlock(p);
 	ao2_ref(p, -1);
 	return res;
 }
 
-static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
-{
-	struct local_pvt *p = ast_channel_tech_pvt(ast);
+int ast_unreal_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
+{
+	struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
 	int res = -1;
 	struct ast_frame f = { AST_FRAME_HTML, };
 	int isoutbound;
@@ -704,24 +708,28 @@
 		return -1;
 	}
 
-	ao2_ref(p, 1); /* ref for local_queue_frame */
+	ao2_ref(p, 1); /* ref for unreal_queue_frame */
 	ao2_lock(p);
-	isoutbound = IS_OUTBOUND(ast, p);
+	isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
 	f.subclass.integer = subclass;
 	f.data.ptr = (char *)data;
 	f.datalen = datalen;
-	res = local_queue_frame(p, isoutbound, &f, ast, 0);
+	res = unreal_queue_frame(p, isoutbound, &f, ast, 0);
 	ao2_unlock(p);
 	ao2_ref(p, -1);
 
 	return res;
 }
 
+/* BUGBUG need to create ast_local_setup_bridge(). */
+/* BUGBUG need to create ast_local_setup_masquerade(). */
+/* BUGBUG need to create ast_local_setup_dialplan(). */
+/* BUGBUG need to separate local_call() from unreal channel start. */
 /*! \brief Initiate new call, part of PBX interface
  *         dest is the dial string */
 static int local_call(struct ast_channel *ast, const char *dest, int timeout)
 {
-	struct local_pvt *p = ast_channel_tech_pvt(ast);
+	struct ast_local_pvt *p = ast_channel_tech_pvt(ast);
 	int pvt_locked = 0;
 
 	struct ast_channel *owner = NULL;
@@ -733,6 +741,7 @@
 	char *slash;
 	const char *exten;
 	const char *context;
+	const char *owner_cid;
 
 	if (!p) {
 		return -1;
@@ -743,7 +752,7 @@
 	ao2_ref(p, 1);
 	ast_channel_unlock(ast);
 
-	awesome_locking(p, &chan, &owner);
+	ast_unreal_lock_all(&p->base, &chan, &owner);
 	pvt_locked = 1;
 
 	if (owner != ast) {
@@ -791,9 +800,11 @@
 		}
 	}
 	ast_channel_datastore_inherit(owner, chan);
-	/* If the local channel has /n or /b on the end of it,
-	 * we need to lop that off for our argument to setting
-	 * up the CC_INTERFACES variable
+
+	/*
+	 * If the local channel has /n on the end of it, we need to lop
+	 * that off for our argument to setting up the CC_INTERFACES
+	 * variable.
 	 */
 	if ((slash = strrchr(reduced_dest, '/'))) {
 		*slash = '\0';
@@ -808,11 +819,18 @@
 
 	ast_channel_unlock(chan);
 
-	if (!ast_exists_extension(chan, context, exten, 1,
-		S_COR(ast_channel_caller(owner)->id.number.valid, ast_channel_caller(owner)->id.number.str, NULL))) {
+	owner_cid = S_COR(ast_channel_caller(owner)->id.number.valid,
+		ast_channel_caller(owner)->id.number.str, NULL);
+	if (owner_cid) {
+		owner_cid = ast_strdupa(owner_cid);
+	}
+	ast_channel_unlock(owner);
+	owner = ast_channel_unref(owner);
+
+	if (!ast_exists_extension(chan, context, exten, 1, owner_cid)) {
 		ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", exten, context);
 		res = -1;
-		chan = ast_channel_unref(chan); /* we already unlocked it, so clear it here so the cleanup label won't touch it. */
+		chan = ast_channel_unref(chan); /* we already unlocked it, clear it here so the cleanup label won't touch it. */
 		goto return_cleanup;
 	}
 
@@ -849,20 +867,20 @@
 		"Context: %s\r\n"
 		"Exten: %s\r\n"
 		"LocalOptimization: %s\r\n",
-		ast_channel_name(p->owner), ast_channel_name(p->chan),
-		ast_channel_uniqueid(p->owner), ast_channel_uniqueid(p->chan),
+		ast_channel_name(p->base.owner), ast_channel_name(p->base.chan),
+		ast_channel_uniqueid(p->base.owner), ast_channel_uniqueid(p->base.chan),
 		p->context, p->exten,
-		ast_test_flag(p, LOCAL_NO_OPTIMIZATION) ? "Yes" : "No");
+		ast_test_flag(&p->base, AST_UNREAL_NO_OPTIMIZATION) ? "Yes" : "No");
 
 
 	/* Start switch on sub channel */
 	res = ast_pbx_start(chan);
 	if (!res) {
 		ao2_lock(p);
-		ast_set_flag(p, LOCAL_LAUNCHED_PBX);
+		ast_set_flag(&p->base, AST_UNREAL_CARETAKER_THREAD);
 		ao2_unlock(p);
 	}
-	chan = ast_channel_unref(chan); /* chan is already unlocked, clear it here so the cleanup lable won't touch it. */
+	chan = ast_channel_unref(chan); /* we already unlocked it, clear it here so the cleanup label won't touch it. */
 
 return_cleanup:
 	if (p) {
@@ -873,7 +891,7 @@
 	}
 	if (chan) {
 		ast_channel_unlock(chan);
-		chan = ast_channel_unref(chan);
+		ast_channel_unref(chan);
 	}
 
 	/* owner is supposed to be == to ast,  if it
@@ -883,7 +901,7 @@
 			ast_channel_unlock(owner);
 			ast_channel_lock(ast);
 		}
-		owner = ast_channel_unref(owner);
+		ast_channel_unref(owner);
 	} else {
 		/* we have to exit with ast locked */
 		ast_channel_lock(ast);
@@ -892,176 +910,200 @@
 	return res;
 }
 
-/*! \brief Hangup a call through the local proxy channel */
-static int local_hangup(struct ast_channel *ast)
-{
-	struct local_pvt *p = ast_channel_tech_pvt(ast);
-	int isoutbound;
+int ast_unreal_hangup(struct ast_unreal_pvt *p, struct ast_channel *ast)
+{
 	int hangup_chan = 0;
 	int res = 0;
-	struct ast_frame f = { AST_FRAME_CONTROL, { AST_CONTROL_HANGUP }, .data.uint32 = ast_channel_hangupcause(ast) };
+	int cause;
 	struct ast_channel *owner = NULL;
 	struct ast_channel *chan = NULL;
 
-	if (!p) {
-		return -1;
-	}
-
-	/* give the pvt a ref since we are unlocking the channel. */
-	ao2_ref(p, 1);
-
-	/* the pvt isn't going anywhere, we gave it a ref */
+	/* the pvt isn't going anywhere, it has a ref */
 	ast_channel_unlock(ast);
 
 	/* lock everything */
-	awesome_locking(p, &chan, &owner);
+	ast_unreal_lock_all(p, &chan, &owner);
 
 	if (ast != chan && ast != owner) {
 		res = -1;
-		goto local_hangup_cleanup;
-	}
-
-	isoutbound = IS_OUTBOUND(ast, p); /* just comparing pointer of ast */
-
-	if (p->chan && ast_channel_hangupcause(ast) == AST_CAUSE_ANSWERED_ELSEWHERE) {
-		ast_channel_hangupcause_set(p->chan, AST_CAUSE_ANSWERED_ELSEWHERE);
-		ast_debug(2, "This local call has AST_CAUSE_ANSWERED_ELSEWHERE set.\n");
-	}
-
-	if (isoutbound) {
-		const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS");
-
-		if (status && p->owner) {
-			ast_channel_hangupcause_set(p->owner, ast_channel_hangupcause(p->chan));
-			pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
-		}
-
-		ast_clear_flag(p, LOCAL_LAUNCHED_PBX);
+		goto unreal_hangup_cleanup;
+	}
+
+	cause = ast_channel_hangupcause(ast);
+
+	if (ast == p->chan) {
+		/* Outgoing side is hanging up. */
+		ast_clear_flag(p, AST_UNREAL_CARETAKER_THREAD);
 		p->chan = NULL;
+		if (p->owner) {
+			const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS");
+
+			if (status) {
+				ast_channel_hangupcause_set(p->owner, cause);
+				pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
+			}
+			ast_queue_hangup_with_cause(p->owner, cause);
+		}
 	} else {
+		/* Owner side is hanging up. */
+		p->owner = NULL;
 		if (p->chan) {
-			ast_queue_hangup(p->chan);
-		}
-		p->owner = NULL;
-	}
-
-	ast_channel_tech_pvt_set(ast, NULL); /* this is one of our locked channels, doesn't matter which */
-
-	if (!p->owner && !p->chan) {
-		ao2_unlock(p);
-
-		ao2_unlink(locals, p);
-		ao2_ref(p, -1);
-		p = NULL;
-		res = 0;
-		goto local_hangup_cleanup;
-	}
-	if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX)) {
-		/* Need to actually hangup since there is no PBX */
-		hangup_chan = 1;
-	} else {
-		local_queue_frame(p, isoutbound, &f, NULL, 0);
-	}
-
-local_hangup_cleanup:
-	if (p) {
-		ao2_unlock(p);
-		ao2_ref(p, -1);
-	}
+			if (cause == AST_CAUSE_ANSWERED_ELSEWHERE) {
+				ast_channel_hangupcause_set(p->chan, AST_CAUSE_ANSWERED_ELSEWHERE);
+				ast_debug(2, "%s has AST_CAUSE_ANSWERED_ELSEWHERE set.\n",
+					ast_channel_name(p->chan));
+			}
+			if (!ast_test_flag(p, AST_UNREAL_CARETAKER_THREAD)) {
+				/*
+				 * Need to actually hangup p->chan since nothing else is taking
+				 * care of it.
+				 */
+				hangup_chan = 1;
+			} else {
+				ast_queue_hangup_with_cause(p->chan, cause);
+			}
+		}
+	}
+
+	/* this is one of our locked channels, doesn't matter which */
+	ast_channel_tech_pvt_set(ast, NULL);
+
+unreal_hangup_cleanup:
+	ao2_unlock(p);
 	if (owner) {
 		ast_channel_unlock(owner);
-		owner = ast_channel_unref(owner);
+		ast_channel_unref(owner);
 	}
 	if (chan) {
 		ast_channel_unlock(chan);
 		if (hangup_chan) {
 			ast_hangup(chan);
 		}
-		chan = ast_channel_unref(chan);
-	}
-
-	/* leave with the same stupid channel locked that came in */
+		ast_channel_unref(chan);
+	}
+
+	/* leave with the channel locked that came in */
 	ast_channel_lock(ast);
+
+	return res;
+}
+
+/*! \brief Hangup a call through the local proxy channel */
+static int local_hangup(struct ast_channel *ast)
+{
+	struct ast_local_pvt *p = ast_channel_tech_pvt(ast);
+	int res;
+
+	if (!p) {
+		return -1;
+	}
+
+	/* give the pvt a ref to fulfill calling requirements. */
+	ao2_ref(p, +1);
+	res = ast_unreal_hangup(&p->base, ast);
+	if (!res) {
+		int unlink;
+
+		ao2_lock(p);
+		unlink = !p->base.owner && !p->base.chan;
+		ao2_unlock(p);
+		if (unlink) {
+			ao2_unlink(locals, p);
+		}
+	}
+	ao2_ref(p, -1);
+
 	return res;
 }
 
 /*!
  * \internal
- * \brief struct local_pvt destructor.
- *
- * \param vdoomed Void local_pvt to destroy.
+ * \brief struct ast_unreal_pvt destructor.
+ *
+ * \param vdoomed Void ast_local_pvt to destroy.
  *
  * \return Nothing
  */
 static void local_pvt_destructor(void *vdoomed)
 {
-	struct local_pvt *doomed = vdoomed;
-
-	doomed->reqcap = ast_format_cap_destroy(doomed->reqcap);
+	struct ast_local_pvt *doomed = vdoomed;
+
+	doomed->base.reqcap = ast_format_cap_destroy(doomed->base.reqcap);
 
 	ast_module_unref(ast_module_info->self);
 }
 
+/* BUGBUG need to separate local_alloc() from unreal private setup. */
 /*! \brief Create a call structure */
-static struct local_pvt *local_alloc(const char *data, struct ast_format_cap *cap)
-{
-	struct local_pvt *tmp = NULL;
+static struct ast_local_pvt *local_alloc(const char *data, struct ast_format_cap *cap)
+{
+	struct ast_local_pvt *pvt;
 	char *parse;
-	char *c = NULL;
-	char *opts = NULL;
-
-	if (!(tmp = ao2_alloc(sizeof(*tmp), local_pvt_destructor))) {
+	char *context;
+	char *opts;
+
+	static const struct ast_jb_conf jb_conf = {
+		.flags = 0,
+		.max_size = -1,
+		.resync_threshold = -1,
+		.impl = "",
+		.target_extra = -1,
+	};
+
+	if (!(pvt = ao2_alloc(sizeof(*pvt), local_pvt_destructor))) {
 		return NULL;
 	}
-	if (!(tmp->reqcap = ast_format_cap_dup(cap))) {
-		ao2_ref(tmp, -1);
+	if (!(pvt->base.reqcap = ast_format_cap_dup(cap))) {
+		ao2_ref(pvt, -1);
 		return NULL;
 	}
 
+	memcpy(&pvt->base.jb_conf, &jb_conf, sizeof(pvt->base.jb_conf));
+
 	ast_module_ref(ast_module_info->self);
 
-	/* Initialize private structure information */
 	parse = ast_strdupa(data);
-
-	memcpy(&tmp->jb_conf, &g_jb_conf, sizeof(tmp->jb_conf));
 
 	/* Look for options */
 	if ((opts = strchr(parse, '/'))) {
 		*opts++ = '\0';
 		if (strchr(opts, 'n'))
-			ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION);
+			ast_set_flag(&pvt->base, AST_UNREAL_NO_OPTIMIZATION);
 		if (strchr(opts, 'j')) {
-			if (ast_test_flag(tmp, LOCAL_NO_OPTIMIZATION))
-				ast_set_flag(&tmp->jb_conf, AST_JB_ENABLED);
+			if (ast_test_flag(&pvt->base, AST_UNREAL_NO_OPTIMIZATION))
+				ast_set_flag(&pvt->base.jb_conf, AST_JB_ENABLED);
 			else {
 				ast_log(LOG_ERROR, "You must use the 'n' option with the 'j' option to enable the jitter buffer\n");
 			}
 		}
 		if (strchr(opts, 'm')) {
-			ast_set_flag(tmp, LOCAL_MOH_PASSTHRU);
+			ast_set_flag(&pvt->base, AST_UNREAL_MOH_PASSTHRU);
 		}
 	}
 
 	/* Look for a context */
-	if ((c = strchr(parse, '@'))) {
-		*c++ = '\0';
-	}
-
-	ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context));
-	ast_copy_string(tmp->exten, parse, sizeof(tmp->exten));
-
-	ao2_link(locals, tmp);
-
-	return tmp; /* this is returned with a ref */
-}
-
+	if ((context = strchr(parse, '@'))) {
+		*context++ = '\0';
+	}
+
+	ast_copy_string(pvt->context, S_OR(context, "default"), sizeof(pvt->context));
+	ast_copy_string(pvt->exten, parse, sizeof(pvt->exten));
+	snprintf(pvt->base.name, sizeof(pvt->base.name), "%s@%s", pvt->exten, pvt->context);
+
+	ao2_link(locals, pvt);
+
+	return pvt; /* this is returned with a ref */
+}
+
+/* BUGBUG need to separate local_new() from unreal channel setup. */
 /*! \brief Start new local channel */
-static struct ast_channel *local_new(struct local_pvt *p, int state, const char *linkedid, struct ast_callid *callid)
+static struct ast_channel *local_new(struct ast_local_pvt *p, int state, const char *linkedid, struct ast_callid *callid)
 {
 	struct ast_channel *owner;
 	struct ast_channel *chan;
 	struct ast_format fmt;
 	int generated_seqno = ast_atomic_fetchadd_int((int *)&name_sequence, +1);
+	const struct ast_channel_tech *tech = &local_tech;
 
 	/*
 	 * Allocate two new Asterisk channels
@@ -1072,10 +1114,10 @@
 	 */
 	if (!(owner = ast_channel_alloc(1, state, NULL, NULL, NULL,
 			p->exten, p->context, linkedid, 0,
-			"Local/%s@%s-%08x;1", p->exten, p->context, generated_seqno))
+			"%s/%s-%08x;1", tech->type, p->base.name, generated_seqno))
 		|| !(chan = ast_channel_alloc(1, AST_STATE_RING, NULL, NULL, NULL,
 			p->exten, p->context, ast_channel_linkedid(owner), 0,
-			"Local/%s@%s-%08x;2", p->exten, p->context, generated_seqno))) {
+			"%s/%s-%08x;2", tech->type, p->base.name, generated_seqno))) {
 		if (owner) {
 			owner = ast_channel_release(owner);
 		}
@@ -1088,16 +1130,16 @@
 		ast_channel_callid_set(chan, callid);
 	}
 
-	ast_channel_tech_set(owner, &local_tech);
-	ast_channel_tech_set(chan, &local_tech);
+	ast_channel_tech_set(owner, tech);
+	ast_channel_tech_set(chan, tech);
 	ast_channel_tech_pvt_set(owner, p);
 	ast_channel_tech_pvt_set(chan, p);
 
-	ast_format_cap_copy(ast_channel_nativeformats(owner), p->reqcap);
-	ast_format_cap_copy(ast_channel_nativeformats(chan), p->reqcap);
+	ast_format_cap_copy(ast_channel_nativeformats(owner), p->base.reqcap);
+	ast_format_cap_copy(ast_channel_nativeformats(chan), p->base.reqcap);
 
 	/* Determine our read/write format and set it on each channel */
-	ast_best_codec(p->reqcap, &fmt);
+	ast_best_codec(p->base.reqcap, &fmt);
 	ast_format_copy(ast_channel_writeformat(owner), &fmt);
 	ast_format_copy(ast_channel_writeformat(chan), &fmt);
 	ast_format_copy(ast_channel_rawwriteformat(owner), &fmt);
@@ -1110,18 +1152,20 @@
 	ast_set_flag(ast_channel_flags(owner), AST_FLAG_DISABLE_DEVSTATE_CACHE);
 	ast_set_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_DEVSTATE_CACHE);
 
-	p->owner = owner;
-	p->chan = chan;
-
-	ast_jb_configure(owner, &p->jb_conf);
+	p->base.owner = owner;
+	p->base.chan = chan;
+
+	ast_jb_configure(owner, &p->base.jb_conf);
 
 	return owner;
 }
 
+/* BUGBUG need to create ast_unreal_new(). */
+/* BUGBUG need to separate local_request() from unreal channel setup. */
 /*! \brief Part of PBX interface */
 static struct ast_channel *local_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
 {
-	struct local_pvt *p;
+	struct ast_local_pvt *p;
 	struct ast_channel *chan;
 	struct ast_callid *callid = ast_read_threadstorage_callid();
 
@@ -1136,8 +1180,8 @@
 		ao2_unlink(locals, p);
 	} else if (ast_channel_cc_params_init(chan, requestor ? ast_channel_get_cc_config_params((struct ast_channel *)requestor) : NULL)) {
 		ao2_unlink(locals, p);
-		p->owner = ast_channel_release(p->owner);
-		p->chan = ast_channel_release(p->chan);
+		p->base.owner = ast_channel_release(p->base.owner);
+		p->base.chan = ast_channel_release(p->base.chan);
 		chan = NULL;
 	}
 	ao2_ref(p, -1); /* kill the ref from the alloc */
@@ -1154,7 +1198,7 @@
 /*! \brief CLI command "local show channels" */
 static char *locals_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-	struct local_pvt *p = NULL;
+	struct ast_local_pvt *p;
 	struct ao2_iterator it;
 
 	switch (cmd) {
@@ -1180,7 +1224,9 @@
 	it = ao2_iterator_init(locals, 0);
 	while ((p = ao2_iterator_next(&it))) {
 		ao2_lock(p);
-		ast_cli(a->fd, "%s -- %s@%s\n", p->owner ? ast_channel_name(p->owner) : "<unowned>", p->exten, p->context);
+		ast_cli(a->fd, "%s -- %s\n",
+			p->base.owner ? ast_channel_name(p->base.owner) : "<unowned>",
+			p->base.name);
 		ao2_unlock(p);
 		ao2_ref(p, -1);
 	}
@@ -1196,8 +1242,8 @@
 static int manager_optimize_away(struct mansession *s, const struct message *m)
 {
 	const char *channel;
-	struct local_pvt *p;
-	struct local_pvt *found;
+	struct ast_local_pvt *p;
+	struct ast_local_pvt *found;
 	struct ast_channel *chan;
 
 	channel = astman_get_header(m, "Channel");
@@ -1218,7 +1264,7 @@
 	found = p ? ao2_find(locals, p, 0) : NULL;
 	if (found) {
 		ao2_lock(found);
-		ast_clear_flag(found, LOCAL_NO_OPTIMIZATION);
+		ast_clear_flag(&found->base, AST_UNREAL_NO_OPTIMIZATION);
 		ao2_unlock(found);
 		ao2_ref(found, -1);
 		astman_send_ack(s, m, "Queued channel to be optimized away");
@@ -1235,6 +1281,7 @@
 	return (obj == arg) ? CMP_MATCH : 0;
 }
 
+/* BUGBUG need to move this file to main/core_local.c and make it not dynamically loadable. */
 /*! \brief Load module into PBX, register channel */
 static int load_module(void)
 {
@@ -1256,7 +1303,7 @@
 		ast_format_cap_destroy(local_tech.capabilities);
 		return AST_MODULE_LOAD_FAILURE;
 	}
-	ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
+	ast_cli_register_multiple(cli_local, ARRAY_LEN(cli_local));
 	ast_manager_register_xml("LocalOptimizeAway", EVENT_FLAG_SYSTEM|EVENT_FLAG_CALL, manager_optimize_away);
 
 	return AST_MODULE_LOAD_SUCCESS;
@@ -1265,18 +1312,18 @@
 /*! \brief Unload the local proxy channel from Asterisk */
 static int unload_module(void)
 {
-	struct local_pvt *p = NULL;
+	struct ast_local_pvt *p;
 	struct ao2_iterator it;
 
 	/* First, take us out of the channel loop */
-	ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
+	ast_cli_unregister_multiple(cli_local, ARRAY_LEN(cli_local));
 	ast_manager_unregister("LocalOptimizeAway");
 	ast_channel_unregister(&local_tech);
 
 	it = ao2_iterator_init(locals, 0);
 	while ((p = ao2_iterator_next(&it))) {
-		if (p->owner) {
-			ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
+		if (p->base.owner) {
+			ast_softhangup(p->base.owner, AST_SOFTHANGUP_APPUNLOAD);
 		}
 		ao2_ref(p, -1);
 	}

Added: team/rmudgett/bridge_phase/include/asterisk/core_local.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/include/asterisk/core_local.h?view=auto&rev=387627
==============================================================================
--- team/rmudgett/bridge_phase/include/asterisk/core_local.h (added)
+++ team/rmudgett/bridge_phase/include/asterisk/core_local.h Fri May  3 19:08:21 2013
@@ -1,0 +1,120 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013 Digium, Inc.
+ *
+ * Richard Mudgett <rmudgett 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 Local proxy channel and other unreal channel derivatives framework.
+ *
+ * \author Richard Mudgett <rmudgett at digium.com>
+ *
+ * See Also:
+ * \arg \ref AstCREDITS
+ */
+
+#ifndef _ASTERISK_CORE_LOCAL_H
+#define _ASTERISK_CORE_LOCAL_H
+
+#include "asterisk/channel.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+/* ------------------------------------------------------------------- */
+
+/*!
+ * \brief The base pvt structure for local channel derivatives.
+ *

[... 91 lines stripped ...]



More information about the asterisk-commits mailing list