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

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon May 6 16:15:08 CDT 2013


Author: rmudgett
Date: Mon May  6 16:15:06 2013
New Revision: 387783

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=387783
Log:
More unreal code separated from local channel code.

* Separated local_call() from unreal channel start.  Extracted
ast_unreal_call_setup() and local_bridge_event().  Also fixed using the
wrong callerid when checking if the exten exists.

* Separated local_alloc() from unreal private setup.  Extracted
ast_unreal_alloc() and ast_unreal_destructor().

* Separated local_new() from unreal channel setup.  Extracted
ast_unreal_new_channels().  In the process gave the channels a reference
to the private object in case the derivative channel does not put privates
in a global container.

* Separated local_request() from unreal channel setup.  Pushed
ast_channel_cc_params_init() call into ast_unreal_new_channels().

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().
* Move channels/chan_local.c to main/core_local.c and make it not dynamically loadable.

Modified:
    team/rmudgett/bridge_phase/channels/chan_local.c
    team/rmudgett/bridge_phase/include/asterisk/core_local.h

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=387783&r1=387782&r2=387783
==============================================================================
--- team/rmudgett/bridge_phase/channels/chan_local.c (original)
+++ team/rmudgett/bridge_phase/channels/chan_local.c Mon May  6 16:15:06 2013
@@ -721,119 +721,65 @@
 	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 ast_local_pvt *p = ast_channel_tech_pvt(ast);
-	int pvt_locked = 0;
-
-	struct ast_channel *owner = NULL;
-	struct ast_channel *chan = NULL;
-	int res;
+void ast_unreal_call_setup(struct ast_channel *semi1, struct ast_channel *semi2)
+{
 	struct ast_var_t *varptr;
 	struct ast_var_t *clone_var;
-	char *reduced_dest = ast_strdupa(dest);
-	char *slash;
-	const char *exten;
-	const char *context;
-	const char *owner_cid;
-
-	if (!p) {
-		return -1;
-	}
-
-	/* since we are letting go of channel locks that were locked coming into
-	 * this function, then we need to give the tech pvt a ref */
-	ao2_ref(p, 1);
-	ast_channel_unlock(ast);
-
-	ast_unreal_lock_all(&p->base, &chan, &owner);
-	pvt_locked = 1;
-
-	if (owner != ast) {
-		res = -1;
-		goto return_cleanup;
-	}
-
-	if (!owner || !chan) {
-		res = -1;
-		goto return_cleanup;
-	}
 
 	/*
-	 * Note that cid_num and cid_name aren't passed in the ast_channel_alloc
-	 * call, so it's done here instead.
+	 * Note that cid_num and cid_name aren't passed in the
+	 * ast_channel_alloc calls in ast_unreal_new_channels().  It's
+	 * done here instead.
+	 */
+	ast_party_redirecting_copy(ast_channel_redirecting(semi2), ast_channel_redirecting(semi1));
+
+	ast_party_dialed_copy(ast_channel_dialed(semi2), ast_channel_dialed(semi1));
+
+	ast_connected_line_copy_to_caller(ast_channel_caller(semi2), ast_channel_connected(semi1));
+	ast_connected_line_copy_from_caller(ast_channel_connected(semi2), ast_channel_caller(semi1));
+
+	ast_channel_language_set(semi2, ast_channel_language(semi1));
+	ast_channel_accountcode_set(semi2, ast_channel_accountcode(semi1));
+	ast_channel_musicclass_set(semi2, ast_channel_musicclass(semi1));
+
+	ast_channel_cc_params_init(semi2, ast_channel_get_cc_config_params(semi1));
+
+	/*
+	 * Make sure we inherit the AST_CAUSE_ANSWERED_ELSEWHERE if it's
+	 * set on the queue/dial call request in the dialplan.
+	 */
+	if (ast_channel_hangupcause(semi1) == AST_CAUSE_ANSWERED_ELSEWHERE) {
+		ast_channel_hangupcause_set(semi2, AST_CAUSE_ANSWERED_ELSEWHERE);
+	}
+
+	/*
+	 * Copy the channel variables from the semi1 channel to the
+	 * outgoing channel.
 	 *
-	 * All these failure points just return -1. The individual strings will
-	 * be cleared when we destroy the channel.
+	 * Note that due to certain assumptions, they MUST be in the
+	 * same order.
 	 */
-	ast_party_redirecting_copy(ast_channel_redirecting(chan), ast_channel_redirecting(owner));
-
-	ast_party_dialed_copy(ast_channel_dialed(chan), ast_channel_dialed(owner));
-
-	ast_connected_line_copy_to_caller(ast_channel_caller(chan), ast_channel_connected(owner));
-	ast_connected_line_copy_from_caller(ast_channel_connected(chan), ast_channel_caller(owner));
-
-	ast_channel_language_set(chan, ast_channel_language(owner));
-	ast_channel_accountcode_set(chan, ast_channel_accountcode(owner));
-	ast_channel_musicclass_set(chan, ast_channel_musicclass(owner));
-	ast_cdr_update(chan);
-
-	ast_channel_cc_params_init(chan, ast_channel_get_cc_config_params(owner));
-
-	/* Make sure we inherit the AST_CAUSE_ANSWERED_ELSEWHERE if it's set on the queue/dial call request in the dialplan */
-	if (ast_channel_hangupcause(ast) == AST_CAUSE_ANSWERED_ELSEWHERE) {
-		ast_channel_hangupcause_set(chan, AST_CAUSE_ANSWERED_ELSEWHERE);
-	}
-
-	/* copy the channel variables from the incoming channel to the outgoing channel */
-	/* Note that due to certain assumptions, they MUST be in the same order */
-	AST_LIST_TRAVERSE(ast_channel_varshead(owner), varptr, entries) {
+	AST_LIST_TRAVERSE(ast_channel_varshead(semi1), varptr, entries) {
 		clone_var = ast_var_assign(varptr->name, varptr->value);
 		if (clone_var) {
-			AST_LIST_INSERT_TAIL(ast_channel_varshead(chan), clone_var, entries);
-		}
-	}
-	ast_channel_datastore_inherit(owner, chan);
-
-	/*
-	 * 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';
-	}
-	ast_set_cc_interfaces_chanvar(chan, reduced_dest);
-
-	exten = ast_strdupa(ast_channel_exten(chan));
-	context = ast_strdupa(ast_channel_context(chan));
-
-	ao2_unlock(p);
-	pvt_locked = 0;
-
-	ast_channel_unlock(chan);
-
-	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, clear it here so the cleanup label won't touch it. */
-		goto return_cleanup;
-	}
-
+			AST_LIST_INSERT_TAIL(ast_channel_varshead(semi2), clone_var, entries);
+		}
+	}
+	ast_channel_datastore_inherit(semi1, semi2);
+}
+
+/*!
+ * \internal
+ * \brief Post the LocalBridge AMI event.
+ * \since 12.0.0
+ *
+ * \param p ast_local_pvt to rais the bridge event.
+ *
+ * \return Nothing
+ */
+static void local_bridge_event(struct ast_local_pvt *p)
+{
+	ao2_lock(p);
 	/*** DOCUMENTATION
 		<managerEventInstance>
 			<synopsis>Raised when two halves of a Local Channel form a bridge.</synopsis>
@@ -871,16 +817,91 @@
 		ast_channel_uniqueid(p->base.owner), ast_channel_uniqueid(p->base.chan),
 		p->context, p->exten,
 		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->base, AST_UNREAL_CARETAKER_THREAD);
-		ao2_unlock(p);
-	}
-	chan = ast_channel_unref(chan); /* we already unlocked it, clear it here so the cleanup label won't touch it. */
+	ao2_unlock(p);
+}
+
+/* BUGBUG need to create ast_local_setup_bridge(). */
+/* BUGBUG need to create ast_local_setup_masquerade(). */
+/* BUGBUG need to create ast_local_setup_dialplan(). */
+/*! \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 ast_local_pvt *p = ast_channel_tech_pvt(ast);
+	int pvt_locked = 0;
+
+	struct ast_channel *owner = NULL;
+	struct ast_channel *chan = NULL;
+	int res;
+	char *reduced_dest = ast_strdupa(dest);
+	char *slash;
+	const char *chan_cid;
+
+	if (!p) {
+		return -1;
+	}
+
+	/* since we are letting go of channel locks that were locked coming into
+	 * this function, then we need to give the tech pvt a ref */
+	ao2_ref(p, 1);
+	ast_channel_unlock(ast);
+
+	ast_unreal_lock_all(&p->base, &chan, &owner);
+	pvt_locked = 1;
+
+	if (owner != ast) {
+		res = -1;
+		goto return_cleanup;
+	}
+
+	if (!owner || !chan) {
+		res = -1;
+		goto return_cleanup;
+	}
+
+	ast_unreal_call_setup(owner, chan);
+
+	/*
+	 * 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';
+	}
+	ast_set_cc_interfaces_chanvar(chan, reduced_dest);
+
+	ao2_unlock(p);
+	pvt_locked = 0;
+
+	ast_channel_unlock(owner);
+
+	chan_cid = S_COR(ast_channel_caller(chan)->id.number.valid,
+		ast_channel_caller(chan)->id.number.str, NULL);
+	if (chan_cid) {
+		chan_cid = ast_strdupa(chan_cid);
+	}
+	ast_channel_unlock(chan);
+
+	if (!ast_exists_extension(NULL, p->context, p->exten, 1, chan_cid)) {
+		ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n",
+			p->exten, p->context);
+		res = -1;
+	} else {
+		local_bridge_event(p);
+	
+		/* Start switch on sub channel */
+		res = ast_pbx_start(chan);
+		if (!res) {
+			ao2_lock(p);
+			ast_set_flag(&p->base, AST_UNREAL_CARETAKER_THREAD);
+			ao2_unlock(p);
+		}
+	}
+
+	/* we already unlocked them, clear them here so the cleanup label won't touch them. */
+	owner = ast_channel_unref(owner);
+	chan = ast_channel_unref(chan);
 
 return_cleanup:
 	if (p) {
@@ -967,6 +988,7 @@
 
 	/* this is one of our locked channels, doesn't matter which */
 	ast_channel_tech_pvt_set(ast, NULL);
+	ao2_ref(p, -1);
 
 unreal_hangup_cleanup:
 	ao2_unlock(p);
@@ -1016,31 +1038,16 @@
 	return res;
 }
 
-/*!
- * \internal
- * \brief struct ast_unreal_pvt destructor.
- *
- * \param vdoomed Void ast_local_pvt to destroy.
- *
- * \return Nothing
- */
-static void local_pvt_destructor(void *vdoomed)
-{
-	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 ast_local_pvt *local_alloc(const char *data, struct ast_format_cap *cap)
-{
-	struct ast_local_pvt *pvt;
-	char *parse;
-	char *context;
-	char *opts;
+void ast_unreal_destructor(void *vdoomed)
+{
+	struct ast_unreal_pvt *doomed = vdoomed;
+
+	doomed->reqcap = ast_format_cap_destroy(doomed->reqcap);
+}
+
+struct ast_unreal_pvt *ast_unreal_alloc(size_t size, ao2_destructor_fn destructor, struct ast_format_cap *cap)
+{
+	struct ast_unreal_pvt *unreal;
 
 	static const struct ast_jb_conf jb_conf = {
 		.flags = 0,
@@ -1050,29 +1057,61 @@
 		.target_extra = -1,
 	};
 
-	if (!(pvt = ao2_alloc(sizeof(*pvt), local_pvt_destructor))) {
+	unreal = ao2_alloc(size, destructor);
+	if (!unreal) {
 		return NULL;
 	}
-	if (!(pvt->base.reqcap = ast_format_cap_dup(cap))) {
-		ao2_ref(pvt, -1);
+	unreal->reqcap = ast_format_cap_dup(cap);
+	if (!unreal->reqcap) {
+		ao2_ref(unreal, -1);
 		return NULL;
 	}
 
-	memcpy(&pvt->base.jb_conf, &jb_conf, sizeof(pvt->base.jb_conf));
-
-	ast_module_ref(ast_module_info->self);
+	memcpy(&unreal->jb_conf, &jb_conf, sizeof(unreal->jb_conf));
+
+	return unreal;
+}
+
+/*!
+ * \internal
+ * \brief struct ast_local_pvt destructor.
+ *
+ * \param vdoomed Object to destroy.
+ *
+ * \return Nothing
+ */
+static void local_pvt_destructor(void *vdoomed)
+{
+	struct ast_local_pvt *doomed = vdoomed;
+
+	ast_unreal_destructor(&doomed->base);
+}
+
+/*! \brief Create a call structure */
+static struct ast_local_pvt *local_alloc(const char *data, struct ast_format_cap *cap)
+{
+	struct ast_local_pvt *pvt;
+	char *parse;
+	char *context;
+	char *opts;
+
+	pvt = (struct ast_local_pvt *) ast_unreal_alloc(sizeof(*pvt), local_pvt_destructor, cap);
+	if (!pvt) {
+		return NULL;
+	}
 
 	parse = ast_strdupa(data);
 
 	/* Look for options */
 	if ((opts = strchr(parse, '/'))) {
 		*opts++ = '\0';
-		if (strchr(opts, 'n'))
+		if (strchr(opts, 'n')) {
 			ast_set_flag(&pvt->base, AST_UNREAL_NO_OPTIMIZATION);
+		}
 		if (strchr(opts, 'j')) {
-			if (ast_test_flag(&pvt->base, AST_UNREAL_NO_OPTIMIZATION))
+			if (ast_test_flag(&pvt->base, AST_UNREAL_NO_OPTIMIZATION)) {
 				ast_set_flag(&pvt->base.jb_conf, AST_JB_ENABLED);
-			else {
+			} else {
 				ast_log(LOG_ERROR, "You must use the 'n' option with the 'j' option to enable the jitter buffer\n");
 			}
 		}
@@ -1090,20 +1129,19 @@
 	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 ast_local_pvt *p, int state, const char *linkedid, struct ast_callid *callid)
+struct ast_channel *ast_unreal_new_channels(struct ast_unreal_pvt *p,
+	const struct ast_channel_tech *tech, int semi1_state, int semi2_state,
+	const char *exten, const char *context, struct ast_channel *requestor,
+	struct ast_callid *callid)
 {
 	struct ast_channel *owner;
 	struct ast_channel *chan;
+	const char *linkedid = requestor ? ast_channel_linkedid(requestor) : NULL;
 	struct ast_format fmt;
-	int generated_seqno = ast_atomic_fetchadd_int((int *)&name_sequence, +1);
-	const struct ast_channel_tech *tech = &local_tech;
+	int generated_seqno = ast_atomic_fetchadd_int((int *) &name_sequence, +1);
 
 	/*
 	 * Allocate two new Asterisk channels
@@ -1112,12 +1150,12 @@
 	 * You can't pass linkedid to both allocations since if linkedid
 	 * isn't set, then each channel will generate its own linkedid.
 	 */
-	if (!(owner = ast_channel_alloc(1, state, NULL, NULL, NULL,
-			p->exten, p->context, linkedid, 0,
-			"%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,
-			"%s/%s-%08x;2", tech->type, p->base.name, generated_seqno))) {
+	if (!(owner = ast_channel_alloc(1, semi1_state, NULL, NULL, NULL,
+			exten, context, linkedid, 0,
+			"%s/%s-%08x;1", tech->type, p->name, generated_seqno))
+		|| !(chan = ast_channel_alloc(1, semi2_state, NULL, NULL, NULL,
+			exten, context, ast_channel_linkedid(owner), 0,
+			"%s/%s-%08x;2", tech->type, p->name, generated_seqno))) {
 		if (owner) {
 			owner = ast_channel_release(owner);
 		}
@@ -1135,11 +1173,11 @@
 	ast_channel_tech_pvt_set(owner, p);
 	ast_channel_tech_pvt_set(chan, p);
 
-	ast_format_cap_copy(ast_channel_nativeformats(owner), p->base.reqcap);
-	ast_format_cap_copy(ast_channel_nativeformats(chan), p->base.reqcap);
+	ast_format_cap_copy(ast_channel_nativeformats(owner), p->reqcap);
+	ast_format_cap_copy(ast_channel_nativeformats(chan), p->reqcap);
 
 	/* Determine our read/write format and set it on each channel */
-	ast_best_codec(p->base.reqcap, &fmt);
+	ast_best_codec(p->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);
@@ -1152,45 +1190,44 @@
 	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->base.owner = owner;
-	p->base.chan = chan;
-
-	ast_jb_configure(owner, &p->base.jb_conf);
+	ast_jb_configure(owner, &p->jb_conf);
+
+	if (ast_channel_cc_params_init(owner, requestor ? ast_channel_get_cc_config_params(requestor) : NULL)) {
+		ast_channel_release(owner);
+		ast_channel_release(chan);
+		return NULL;
+	}
+
+	/* Give the private a ref for each channel. */
+	ao2_ref(p, +2);
+	p->owner = owner;
+	p->chan = chan;
 
 	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 ast_local_pvt *p;
 	struct ast_channel *chan;
-	struct ast_callid *callid = ast_read_threadstorage_callid();
-
-	/* Allocate a new private structure and then Asterisk channel */
+	struct ast_callid *callid;
+
+	/* Allocate a new private structure and then Asterisk channels */
 	p = local_alloc(data, cap);
 	if (!p) {
-		chan = NULL;
-		goto local_request_end;
-	}
-	chan = local_new(p, AST_STATE_DOWN, requestor ? ast_channel_linkedid(requestor) : NULL, callid);
-	if (!chan) {
-		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->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 */
-
-local_request_end:
-
+		return NULL;
+	}
+	callid = ast_read_threadstorage_callid();
+	chan = ast_unreal_new_channels(&p->base, &local_tech, AST_STATE_DOWN, AST_STATE_RING,
+		p->exten, p->context, (struct ast_channel *) requestor, callid);
+	if (chan) {
+		ao2_link(locals, p);
+	}
 	if (callid) {
 		ast_callid_unref(callid);
 	}
+	ao2_ref(p, -1); /* kill the ref from the alloc */
 
 	return chan;
 }
@@ -1329,6 +1366,7 @@
 	}
 	ao2_iterator_destroy(&it);
 	ao2_ref(locals, -1);
+	locals = NULL;
 
 	ast_format_cap_destroy(local_tech.capabilities);
 	return 0;

Modified: 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=diff&rev=387783&r1=387782&r2=387783
==============================================================================
--- team/rmudgett/bridge_phase/include/asterisk/core_local.h (original)
+++ team/rmudgett/bridge_phase/include/asterisk/core_local.h Mon May  6 16:15:06 2013
@@ -96,6 +96,63 @@
 int ast_unreal_setoption(struct ast_channel *chan, int option, void *data, int datalen);
 
 /*!
+ * \brief struct ast_unreal_pvt destructor.
+ * \since 12.0.0
+ *
+ * \param vdoomed Void ast_unreal_pvt to destroy.
+ *
+ * \return Nothing
+ */
+void ast_unreal_destructor(void *vdoomed);
+
+/*!
+ * \brief Allocate the base unreal struct for a derivative.
+ * \since 12.0.0
+ *
+ * \param size Size of the unreal struct to allocate.
+ * \param destructor Destructor callback.
+ * \param cap Format capabilities to give the unreal private struct.
+ *
+ * \retval pvt on success.
+ * \retval NULL on error.
+ */
+struct ast_unreal_pvt *ast_unreal_alloc(size_t size, ao2_destructor_fn destructor, struct ast_format_cap *cap);
+
+/*!
+ * \brief Create the semi1 and semi2 unreal channels.
+ * \since 12.0.0
+ *
+ * \param p Unreal channel private struct.
+ * \param tech Channel technology to use.
+ * \param semi1_state State to start the semi1(owner) channel in.
+ * \param semi2_state State to start the semi2(outgoing chan) channel in.
+ * \param exten Exten to start the chennels in. (NULL if s)
+ * \param context Context to start the channels in. (NULL if default)
+ * \param requestor Channel requesting creation. (NULL if none)
+ * \param callid Thread callid to use.
+ *
+ * \retval semi1_channel on success.
+ * \retval NULL on error.
+ */
+struct ast_channel *ast_unreal_new_channels(struct ast_unreal_pvt *p,
+	const struct ast_channel_tech *tech, int semi1_state, int semi2_state,
+	const char *exten, const char *context, struct ast_channel *requestor,
+	struct ast_callid *callid);
+
+/*!
+ * \brief Setup unreal owner and chan channels before initiating call.
+ * \since 12.0.0
+ *
+ * \param semi1 Owner channel of unreal channel pair.
+ * \param semi2 Outgoing channel of unreal channel pair.
+ *
+ * \note On entry, the semi1 and semi2 channels are already locked.
+ *
+ * \return Nothing
+ */
+void ast_unreal_call_setup(struct ast_channel *semi1, struct ast_channel *semi2);
+
+/*!
  * \brief Get the other local channel in the pair.
  * \since 12.0.0
  *




More information about the asterisk-commits mailing list