[asterisk-commits] mmichelson: branch russell/ast_channel_ao2 r176808 - in /team/russell/ast_cha...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Feb 17 18:22:32 CST 2009


Author: mmichelson
Date: Tue Feb 17 18:22:32 2009
New Revision: 176808

URL: http://svn.digium.com/svn-view/asterisk?view=rev&rev=176808
Log:
Add autochan interface to ast_channel_ao2 and convert chanspy and mixmonitor to use it

chanspy and mixmonitor are examples of applications which attempt to keep a pointer to
a channel in a thread external to the channel's main (i.e. PBX) thread. In both cases,
the channel that they reference may change due to a masquerade. The autochan interface
is a method by which a pointer to a channel may be automatically updated if a channel
is masqueraded.

This also finishes the conversion of app_chanspy and app_mixmonitor to use refcounted
channels.


Added:
    team/russell/ast_channel_ao2/include/asterisk/autochan.h   (with props)
    team/russell/ast_channel_ao2/main/autochan.c   (with props)
Modified:
    team/russell/ast_channel_ao2/apps/app_chanspy.c
    team/russell/ast_channel_ao2/apps/app_mixmonitor.c
    team/russell/ast_channel_ao2/main/Makefile
    team/russell/ast_channel_ao2/main/channel.c

Modified: team/russell/ast_channel_ao2/apps/app_chanspy.c
URL: http://svn.digium.com/svn-view/asterisk/team/russell/ast_channel_ao2/apps/app_chanspy.c?view=diff&rev=176808&r1=176807&r2=176808
==============================================================================
--- team/russell/ast_channel_ao2/apps/app_chanspy.c (original)
+++ team/russell/ast_channel_ao2/apps/app_chanspy.c Tue Feb 17 18:22:32 2009
@@ -50,6 +50,7 @@
 #include "asterisk/module.h"
 #include "asterisk/lock.h"
 #include "asterisk/options.h"
+#include "asterisk/autochan.h"
 
 #define AST_NAME_STRLEN 256
 #define NUM_SPYGROUPS 128
@@ -336,8 +337,6 @@
 	AST_APP_OPTION('d', OPTION_DTMF_SWITCH_MODES),
 });
 
-static int next_unique_id_to_use = 0;
-
 struct chanspy_translation_helper {
 	/* spy data */
 	struct ast_audiohook spy_audiohook;
@@ -399,26 +398,20 @@
 	.generate = spy_generate,
 };
 
-static int start_spying(struct ast_channel *chan, const char *spychan_name, struct ast_audiohook *audiohook)
+static int start_spying(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook)
 {
 	int res = 0;
 	struct ast_channel *peer = NULL;
 
-	ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, chan->name);
-
-	res = ast_audiohook_attach(chan, audiohook);
-
-	if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan))) { 
+	ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, autochan->chan->name);
+
+	res = ast_audiohook_attach(autochan->chan, audiohook);
+
+	if (!res && ast_test_flag(autochan->chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(autochan->chan))) { 
 		ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);
 	}
 	return res;
 }
-
-struct chanspy_ds {
-	struct ast_channel *chan;
-	char unique_id[20];
-	ast_mutex_t lock;
-};
 
 static void change_spy_mode(const char digit, struct ast_flags *flags)
 {
@@ -434,7 +427,7 @@
 	}
 }
 
-static int channel_spy(struct ast_channel *chan, struct chanspy_ds *spyee_chanspy_ds, 
+static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_autochan, 
 	int *volfactor, int fd, struct ast_flags *flags, char *exitcontext) 
 {
 	struct chanspy_translation_helper csth;
@@ -443,32 +436,22 @@
 	char *name;
 	struct ast_frame *f;
 	struct ast_silence_generator *silgen = NULL;
-	struct ast_channel *spyee = NULL, *spyee_bridge = NULL;
+	struct ast_autochan *spyee_bridge_autochan = NULL;
 	const char *spyer_name;
 
 	ast_channel_lock(chan);
 	spyer_name = ast_strdupa(chan->name);
 	ast_channel_unlock(chan);
 
-	ast_mutex_lock(&spyee_chanspy_ds->lock);
-	if (spyee_chanspy_ds->chan) {
-		spyee = spyee_chanspy_ds->chan;
-		ast_channel_lock(spyee);
-	}
-	ast_mutex_unlock(&spyee_chanspy_ds->lock);
-
-	if (!spyee) {
+	/* We now hold the channel lock on spyee */
+
+	if (ast_check_hangup(chan) || ast_check_hangup(spyee_autochan->chan)) {
 		return 0;
 	}
 
-	/* We now hold the channel lock on spyee */
-
-	if (ast_check_hangup(chan) || ast_check_hangup(spyee)) {
-		ast_channel_unlock(spyee);
-		return 0;
-	}
-
-	name = ast_strdupa(spyee->name);
+	ast_channel_lock(spyee_autochan->chan);
+	name = ast_strdupa(spyee_autochan->chan->name);
+	ast_channel_unlock(spyee_autochan->chan);
 
 	ast_verb(2, "Spying on channel %s\n", name);
 	manager_event(EVENT_FLAG_CALL, "ChanSpyStart",
@@ -480,26 +463,23 @@
 
 	ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy");
 
-	if (start_spying(spyee, spyer_name, &csth.spy_audiohook)) {
+	if (start_spying(spyee_autochan, spyer_name, &csth.spy_audiohook)) {
 		ast_audiohook_destroy(&csth.spy_audiohook);
-		ast_channel_unlock(spyee);
 		return 0;
 	}
 
  	ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy");
 	ast_audiohook_init(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Chanspy");
-  	if (start_spying(spyee, spyer_name, &csth.whisper_audiohook)) {
-		ast_log(LOG_WARNING, "Unable to attach whisper audiohook to spyee %s. Whisper mode disabled!\n", spyee->name);
-	}
-	if ((spyee_bridge = ast_bridged_channel(spyee))) {
-		ast_channel_lock(spyee_bridge);
-		if (start_spying(spyee_bridge, spyer_name, &csth.bridge_whisper_audiohook)) {
-			ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee %s. Barge mode disabled!\n", spyee->name);
-		}
-		ast_channel_unlock(spyee_bridge);
-	}
-	ast_channel_unlock(spyee);
-	spyee = NULL;
+  	if (start_spying(spyee_autochan, spyer_name, &csth.whisper_audiohook)) {
+		ast_log(LOG_WARNING, "Unable to attach whisper audiohook to spyee %s. Whisper mode disabled!\n", name);
+	}
+	if ((spyee_bridge_autochan = ast_autochan_setup(ast_bridged_channel(spyee_autochan->chan)))) {
+		ast_channel_lock(spyee_bridge_autochan->chan);
+		if (start_spying(spyee_bridge_autochan, spyer_name, &csth.bridge_whisper_audiohook)) {
+			ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee %s. Barge mode disabled!\n", name);
+		}
+		ast_channel_unlock(spyee_bridge_autochan->chan);
+	}
 
 	ast_channel_lock(chan);
 	ast_set_flag(chan, AST_FLAG_END_DTMF_ONLY);
@@ -632,6 +612,10 @@
 	ast_audiohook_detach(&csth.spy_audiohook);
 	ast_audiohook_unlock(&csth.spy_audiohook);
 	ast_audiohook_destroy(&csth.spy_audiohook);
+
+	if (spyee_bridge_autochan) {
+		ast_autochan_destroy(spyee_bridge_autochan);
+	}
 	
 	ast_verb(2, "Done Spying on channel %s\n", name);
 	manager_event(EVENT_FLAG_CALL, "ChanSpyStop", "SpyeeChannel: %s\r\n", name);
@@ -639,115 +623,29 @@
 	return running;
 }
 
-/*!
- * \note This relies on the embedded lock to be recursive, as it may be called
- * due to a call to chanspy_ds_free with the lock held there.
- */
-static void chanspy_ds_destroy(void *data)
-{
-	struct chanspy_ds *chanspy_ds = data;
-
-	/* Setting chan to be NULL is an atomic operation, but we don't want this
-	 * value to change while this lock is held.  The lock is held elsewhere
-	 * while it performs non-atomic operations with this channel pointer */
-
-	ast_mutex_lock(&chanspy_ds->lock);
-	chanspy_ds->chan = NULL;
-	ast_mutex_unlock(&chanspy_ds->lock);
-}
-
-static void chanspy_ds_chan_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
-{
-	struct chanspy_ds *chanspy_ds = data;
-	
-	ast_mutex_lock(&chanspy_ds->lock);
-	chanspy_ds->chan = new_chan;
-	ast_mutex_unlock(&chanspy_ds->lock);
-}
-
-static const struct ast_datastore_info chanspy_ds_info = {
-	.type = "chanspy",
-	.destroy = chanspy_ds_destroy,
-	.chan_fixup = chanspy_ds_chan_fixup,
-};
-
-static struct chanspy_ds *chanspy_ds_free(struct chanspy_ds *chanspy_ds)
-{
-	if (!chanspy_ds)
-		return NULL;
-
-	ast_mutex_lock(&chanspy_ds->lock);
-	if (chanspy_ds->chan) {
-		struct ast_datastore *datastore;
-		struct ast_channel *chan;
-
-		chan = chanspy_ds->chan;
-
-		ast_channel_lock(chan);
-		if ((datastore = ast_channel_datastore_find(chan, &chanspy_ds_info, chanspy_ds->unique_id))) {
-			ast_channel_datastore_remove(chan, datastore);
-			/* chanspy_ds->chan is NULL after this call */
-			chanspy_ds_destroy(datastore->data);
-			datastore->data = NULL;
-			ast_datastore_free(datastore);
-		}
-		ast_channel_unlock(chan);
-	}
-	ast_mutex_unlock(&chanspy_ds->lock);
-
-	return NULL;
-}
-
-/*! \note Returns the channel in the chanspy_ds locked as well as the chanspy_ds locked */
-static struct chanspy_ds *setup_chanspy_ds(struct ast_channel *chan, struct chanspy_ds *chanspy_ds)
-{
-	struct ast_datastore *datastore = NULL;
-
-	ast_mutex_lock(&chanspy_ds->lock);
-
-	if (!(datastore = ast_datastore_alloc(&chanspy_ds_info, chanspy_ds->unique_id))) {
-		ast_mutex_unlock(&chanspy_ds->lock);
-		chanspy_ds = chanspy_ds_free(chanspy_ds);
-		ast_channel_unlock(chan);
-		return NULL;
-	}
-	
-	chanspy_ds->chan = chan;
-	datastore->data = chanspy_ds;
-	ast_channel_datastore_add(chan, datastore);
-
-	return chanspy_ds;
-}
-
-static struct chanspy_ds *next_channel(struct ast_channel *chan,
-	const struct ast_channel *last, const char *spec,
-	const char *exten, const char *context, struct chanspy_ds *chanspy_ds)
+static struct ast_autochan *next_channel(struct ast_channel_iterator *iter,
+		struct ast_autochan *autochan, struct ast_channel *chan)
 {
 	struct ast_channel *next;
 	const size_t pseudo_len = strlen("DAHDI/pseudo");
 
+	if (!iter) {
+		return NULL;
+	}
+
 redo:
-	if (!ast_strlen_zero(spec))
-		next = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec));
-	else if (!ast_strlen_zero(exten))
-		next = ast_walk_channel_by_exten_locked(last, exten, context);
-	else
-		next = ast_channel_walk_locked(last);
-
-	if (!next)
+
+	if (!(next = ast_channel_iterator_next(iter))) {
 		return NULL;
+	}
 
 	if (!strncmp(next->name, "DAHDI/pseudo", pseudo_len)) {
-		last = next;
-		ast_channel_unlock(next);
 		goto redo;
 	} else if (next == chan) {
-		last = next;
-		ast_channel_unlock(next);
 		goto redo;
 	}
 
-	return setup_chanspy_ds(next, chanspy_ds);
+	return ast_autochan_setup(next);
 }
 
 static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
@@ -764,7 +662,7 @@
 	char *ptr;
 	int num;
 	int num_spyed_upon = 1;
-	struct chanspy_ds chanspy_ds = { 0, };
+	struct ast_channel_iterator *iter = NULL;
 
 	if (ast_test_flag(flags, OPTION_EXIT)) {
 		const char *c;
@@ -779,10 +677,6 @@
 		ast_channel_unlock(chan);
 	}
 
-	ast_mutex_init(&chanspy_ds.lock);
-
-	snprintf(chanspy_ds.unique_id, sizeof(chanspy_ds.unique_id), "%d", ast_atomic_fetchadd_int(&next_unique_id_to_use, +1));
-
 	if (chan->_state != AST_STATE_UP)
 		ast_answer(chan);
 
@@ -791,8 +685,8 @@
 	waitms = 100;
 
 	for (;;) {
-		struct chanspy_ds *peer_chanspy_ds = NULL, *next_chanspy_ds = NULL;
-		struct ast_channel *prev = NULL, *peer = NULL;
+		struct ast_autochan *autochan = NULL, *next_autochan = NULL;
+		struct ast_channel *prev = NULL;
 
 		if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) {
 			res = ast_streamfile(chan, "beep", chan->language);
@@ -812,6 +706,19 @@
 					ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
 			}
 		}
+		
+		/* Set up the iterator we'll be using during this call */
+		if (!ast_strlen_zero(spec)) {
+			iter = ast_channel_iterator_by_name_new(0, spec, strlen(spec));
+		} else if (!ast_strlen_zero(exten)) {
+			iter = ast_channel_iterator_by_exten_new(0, exten, context);
+		} else {
+			iter = ast_channel_iterator_all_new(0);
+		}
+
+		if (!iter) {
+			return -1;
+		}
 
 		res = ast_waitfordigit(chan, waitms);
 		if (res < 0) {
@@ -832,38 +739,30 @@
 		waitms = 100;
 		num_spyed_upon = 0;
 
-		for (peer_chanspy_ds = next_channel(chan, prev, spec, exten, context, &chanspy_ds);
-		     peer_chanspy_ds;
-			 chanspy_ds_free(peer_chanspy_ds), prev = peer,
-		     peer_chanspy_ds = next_chanspy_ds ? next_chanspy_ds : 
-			 	next_channel(chan, prev, spec, exten, context, &chanspy_ds), next_chanspy_ds = NULL) {
+		for (autochan = next_channel(iter, autochan, chan);
+		     autochan;
+			 prev = autochan->chan, ast_autochan_destroy(autochan),
+		     autochan = next_autochan ? next_autochan : 
+			 	next_channel(iter, autochan, chan), next_autochan = NULL) {
 			int igrp = !mygroup;
 			int ienf = !myenforced;
 			char *s;
 
-			peer = peer_chanspy_ds->chan;
-
-			ast_mutex_unlock(&peer_chanspy_ds->lock);
-
-			if (peer == prev) {
-				ast_channel_unlock(peer);
-				chanspy_ds_free(peer_chanspy_ds);
+			if (autochan->chan == prev) {
+				ast_autochan_destroy(autochan);
 				break;
 			}
 
 			if (ast_check_hangup(chan)) {
-				ast_channel_unlock(peer);
-				chanspy_ds_free(peer_chanspy_ds);
+				ast_autochan_destroy(autochan);
 				break;
 			}
 
-			if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer)) {
-				ast_channel_unlock(peer);
+			if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(autochan->chan)) {
 				continue;
 			}
 
-			if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING)) {
-				ast_channel_unlock(peer);
+			if (ast_check_hangup(autochan->chan) || ast_test_flag(autochan->chan, AST_FLAG_SPYING)) {
 				continue;
 			}
 
@@ -881,7 +780,7 @@
 				num_mygroups = ast_app_separate_args(dup_mygroup, ':', mygroups,
 					ARRAY_LEN(mygroups));
 
-				if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) {
+				if ((group = pbx_builtin_getvar_helper(autochan->chan, "SPYGROUP"))) {
 					ast_copy_string(dup_group, group, sizeof(dup_group));
 					num_groups = ast_app_separate_args(dup_group, ':', groups,
 						ARRAY_LEN(groups));
@@ -898,7 +797,6 @@
 			}
 
 			if (!igrp) {
-				ast_channel_unlock(peer);
 				continue;
 			}
 
@@ -909,7 +807,7 @@
 
 				snprintf(buffer, sizeof(buffer) - 1, ":%s:", myenforced);
 
-				ast_copy_string(ext + 1, peer->name, sizeof(ext) - 1);
+				ast_copy_string(ext + 1, autochan->chan->name, sizeof(ext) - 1);
 				if ((end = strchr(ext, '-'))) {
 					*end++ = ':';
 					*end = '\0';
@@ -927,18 +825,13 @@
 			}
 
 			strcpy(peer_name, "spy-");
-			strncat(peer_name, peer->name, AST_NAME_STRLEN - 4 - 1);
+			strncat(peer_name, autochan->chan->name, AST_NAME_STRLEN - 4 - 1);
 			ptr = strchr(peer_name, '/');
 			*ptr++ = '\0';
 			ptr = strsep(&ptr, "-");
 
 			for (s = peer_name; s < ptr; s++)
 				*s = tolower(*s);
-			/* We have to unlock the peer channel here to avoid a deadlock.
-			 * So, when we need to dereference it again, we have to lock the 
-			 * datastore and get the pointer from there to see if the channel 
-			 * is still valid. */
-			ast_channel_unlock(peer);
 
 			if (!ast_test_flag(flags, OPTION_QUIET)) {
 				if (ast_test_flag(flags, OPTION_NAME)) {
@@ -954,7 +847,7 @@
 								res = ast_waitstream(chan, "");
 							}
 							if (res) {
-								chanspy_ds_free(peer_chanspy_ds);
+								ast_autochan_destroy(autochan);
 								break;
 							}
 						} else {
@@ -966,42 +859,38 @@
 				}
 			}
 
-			res = channel_spy(chan, peer_chanspy_ds, &volfactor, fd, flags, exitcontext);
+			res = channel_spy(chan, autochan, &volfactor, fd, flags, exitcontext);
 			num_spyed_upon++;	
 
 			if (res == -1) {
-				chanspy_ds_free(peer_chanspy_ds);
+				ast_autochan_destroy(autochan);
 				goto exit;
 			} else if (res == -2) {
 				res = 0;
-				chanspy_ds_free(peer_chanspy_ds);
+				ast_autochan_destroy(autochan);
 				goto exit;
 			} else if (res > 1 && spec) {
 				struct ast_channel *next;
 
 				snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
 
-				if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) {
-					peer_chanspy_ds = chanspy_ds_free(peer_chanspy_ds);
-					next_chanspy_ds = setup_chanspy_ds(next, &chanspy_ds);
+				if ((next = ast_channel_get_by_name_prefix(nameprefix, strlen(nameprefix)))) {
+					next_autochan = ast_autochan_setup(next);
+					next = ast_channel_unref(next);
 				} else {
 					/* stay on this channel, if it is still valid */
-
-					ast_mutex_lock(&peer_chanspy_ds->lock);
-					if (peer_chanspy_ds->chan) {
-						ast_channel_lock(peer_chanspy_ds->chan);
-						next_chanspy_ds = peer_chanspy_ds;
-						peer_chanspy_ds = NULL;
+					if (!ast_check_hangup(autochan->chan)) {
+						next_autochan = ast_autochan_setup(autochan->chan);
 					} else {
 						/* the channel is gone */
-						ast_mutex_unlock(&peer_chanspy_ds->lock);
-						next_chanspy_ds = NULL;
+						next_autochan = NULL;
 					}
 				}
-
-				peer = NULL;
-			}
-		}
+			}
+		}
+
+		iter = ast_channel_iterator_destroy(iter);
+
 		if (res == -1 || ast_check_hangup(chan))
 			break;
 	}
@@ -1010,10 +899,6 @@
 	ast_clear_flag(chan, AST_FLAG_SPYING);
 
 	ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
-
-	ast_mutex_lock(&chanspy_ds.lock);
-	ast_mutex_unlock(&chanspy_ds.lock);
-	ast_mutex_destroy(&chanspy_ds.lock);
 
 	return res;
 }

Modified: team/russell/ast_channel_ao2/apps/app_mixmonitor.c
URL: http://svn.digium.com/svn-view/asterisk/team/russell/ast_channel_ao2/apps/app_mixmonitor.c?view=diff&rev=176808&r1=176807&r2=176808
==============================================================================
--- team/russell/ast_channel_ao2/apps/app_mixmonitor.c (original)
+++ team/russell/ast_channel_ao2/apps/app_mixmonitor.c Tue Feb 17 18:22:32 2009
@@ -45,6 +45,7 @@
 #include "asterisk/cli.h"
 #include "asterisk/app.h"
 #include "asterisk/channel.h"
+#include "asterisk/autochan.h"
 
 /*** DOCUMENTATION
 	<application name="MixMonitor" language="en_US">
@@ -138,7 +139,7 @@
 	char *post_process;
 	char *name;
 	unsigned int flags;
-	struct mixmonitor_ds *mixmonitor_ds;
+	struct ast_autochan *autochan;
 };
 
 enum {
@@ -164,50 +165,6 @@
 	AST_APP_OPTION_ARG('W', MUXFLAG_VOLUME, OPT_ARG_VOLUME),
 });
 
-/* This structure is used as a means of making sure that our pointer to
- * the channel we are monitoring remains valid. This is very similar to 
- * what is used in app_chanspy.c.
- */
-struct mixmonitor_ds {
-	struct ast_channel *chan;
-	/* These condition variables are used to be sure that the channel
-	 * hangup code completes before the mixmonitor thread attempts to
-	 * free this structure. The combination of a bookean flag and a
-	 * ast_cond_t ensure that no matter what order the threads run in,
-	 * we are guaranteed to never have the waiting thread block forever
-	 * in the case that the signaling thread runs first.
-	 */
-	unsigned int destruction_ok;
-	ast_cond_t destruction_condition;
-	ast_mutex_t lock;
-};
-
-static void mixmonitor_ds_destroy(void *data)
-{
-	struct mixmonitor_ds *mixmonitor_ds = data;
-
-	ast_mutex_lock(&mixmonitor_ds->lock);
-	mixmonitor_ds->chan = NULL;
-	mixmonitor_ds->destruction_ok = 1;
-	ast_cond_signal(&mixmonitor_ds->destruction_condition);
-	ast_mutex_unlock(&mixmonitor_ds->lock);
-}
-
-static void mixmonitor_ds_chan_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
-{
-	struct mixmonitor_ds *mixmonitor_ds = data;
-
-	ast_mutex_lock(&mixmonitor_ds->lock);
-	mixmonitor_ds->chan = new_chan;
-	ast_mutex_unlock(&mixmonitor_ds->lock);
-}
-
-static struct ast_datastore_info mixmonitor_ds_info = {
-	.type = "mixmonitor",
-	.destroy = mixmonitor_ds_destroy,
-	.chan_fixup = mixmonitor_ds_chan_fixup,
-};
-
 static int startmon(struct ast_channel *chan, struct ast_audiohook *audiohook) 
 {
 	struct ast_channel *peer = NULL;
@@ -249,9 +206,7 @@
 		if (!(fr = ast_audiohook_read_frame(&mixmonitor->audiohook, SAMPLES_PER_FRAME, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR)))
 			continue;
 
-		ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
-		if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || (mixmonitor->mixmonitor_ds->chan && ast_bridged_channel(mixmonitor->mixmonitor_ds->chan))) {
-			ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
+		if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || (mixmonitor->autochan->chan && ast_bridged_channel(mixmonitor->autochan->chan))) {
 			/* Initialize the file if not already done so */
 			if (!fs && !errflag) {
 				oflags = O_CREAT | O_WRONLY;
@@ -271,10 +226,7 @@
 			/* Write out frame */
 			if (fs)
 				ast_writestream(fs, fr);
-		} else {
-			ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
 		}
-
 		/* All done! free it. */
 		ast_frame_free(fr, 0);
 
@@ -294,46 +246,10 @@
 		ast_safe_system(mixmonitor->post_process);
 	}
 
-	ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
-	if (!mixmonitor->mixmonitor_ds->destruction_ok) {
-		ast_cond_wait(&mixmonitor->mixmonitor_ds->destruction_condition, &mixmonitor->mixmonitor_ds->lock);
-	}
-	ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
-	ast_mutex_destroy(&mixmonitor->mixmonitor_ds->lock);
-	ast_cond_destroy(&mixmonitor->mixmonitor_ds->destruction_condition);
-	ast_free(mixmonitor->mixmonitor_ds);
+	ast_autochan_destroy(mixmonitor->autochan);
 	ast_free(mixmonitor);
 
 	return NULL;
-}
-
-static int setup_mixmonitor_ds(struct mixmonitor *mixmonitor, struct ast_channel *chan)
-{
-	struct ast_datastore *datastore = NULL;
-	struct mixmonitor_ds *mixmonitor_ds;
-
-	if (!(mixmonitor_ds = ast_calloc(1, sizeof(*mixmonitor_ds)))) {
-		return -1;
-	}
-	
-	ast_mutex_init(&mixmonitor_ds->lock);
-	ast_cond_init(&mixmonitor_ds->destruction_condition, NULL);
-
-	if (!(datastore = ast_datastore_alloc(&mixmonitor_ds_info, NULL))) {
-		ast_free(mixmonitor_ds);
-		return -1;
-	}
-
-	/* No need to lock mixmonitor_ds since this is still operating in the channel's thread */
-	mixmonitor_ds->chan = chan;
-	datastore->data = mixmonitor_ds;
-
-	ast_channel_lock(chan);
-	ast_channel_datastore_add(chan, datastore);
-	ast_channel_unlock(chan);
-
-	mixmonitor->mixmonitor_ds = mixmonitor_ds;
-	return 0;
 }
 
 static void launch_monitor_thread(struct ast_channel *chan, const char *filename, unsigned int flags,
@@ -369,7 +285,7 @@
 
 	/* Copy over flags and channel name */
 	mixmonitor->flags = flags;
-	if (setup_mixmonitor_ds(mixmonitor, chan)) {
+	if (!(mixmonitor->autochan = ast_autochan_setup(chan))) {
 		return;
 	}
 	mixmonitor->name = (char *) mixmonitor + sizeof(*mixmonitor);

Added: team/russell/ast_channel_ao2/include/asterisk/autochan.h
URL: http://svn.digium.com/svn-view/asterisk/team/russell/ast_channel_ao2/include/asterisk/autochan.h?view=auto&rev=176808
==============================================================================
--- team/russell/ast_channel_ao2/include/asterisk/autochan.h (added)
+++ team/russell/ast_channel_ao2/include/asterisk/autochan.h Tue Feb 17 18:22:32 2009
@@ -1,0 +1,102 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) <Year>, <Your Name Here>
+ *
+ * Mark Michelson <mmichelson 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 "smart" channels that update automatically if a channel is masqueraded
+ *
+ * \author Mark Michelson <mmichelson at digium.com>
+ * 
+ */
+
+#include "asterisk.h"
+#include "asterisk/linkedlists.h"
+
+#ifndef _ASTERISK_AUTOCHAN_H
+#define _ASTERISK_AUTOCHAN_H
+
+struct ast_autochan {
+	struct ast_channel *chan;
+	AST_LIST_ENTRY(ast_autochan) list;
+};
+
+/*! \par Just what the $!@# is an autochan?
+ *
+ * An ast_autochan is a structure which contains an ast_channel. The pointer
+ * inside an autochan has the ability to update itself if the channel it points
+ * to is masqueraded into a different channel.
+ *
+ * This has a great benefit for any application or service which creates a thread
+ * outside of the channel's main operating thread which keeps a pointer to said 
+ * channel. when a masquerade occurs on the channel, the autochan's chan pointer 
+ * will automatically update to point to the new channel.
+ *
+ * Some rules for autochans
+ *
+ * 1. If you are going to use an autochan, then be sure to always refer to the
+ * channel using the chan pointer inside the autochan if possible, since this is
+ * the pointer that will be updated during a masquerade.
+ *
+ * 2. If you are going to save off a pointer to the autochan's chan, then be sure
+ * to save off the pointer using ast_channel_ref and to unref the channel when you
+ * are finished with the pointer. If you do not do this and a masquerade occurs on
+ * the channel, then it is possible that your saved pointer will become invalid.
+ */
+
+/* \brief set up a new ast_autochan structure
+ *
+ * Allocates and initializes an ast_autochan, sets the
+ * autochan's chan pointer to point to the chan parameter, and
+ * adds the autochan to the global list of autochans. The newly-
+ * created autochan is returned to the caller. This function will
+ * cause the refcount of chan to increase by 1.
+ *
+ * \note autochans must be freed using ast_autochan_destroy
+ * \param chan The channel our new autochan will point to
+ * \retval NULL Failure
+ * \retval non-NULL success
+ */
+struct ast_autochan *ast_autochan_setup(struct ast_channel *chan);
+
+/* \brief destroy an ast_autochan structure
+ *
+ * Removes the passed-in autochan from the list of autochans and
+ * unrefs the channel that is pointed to. Also frees the autochan
+ * struct itself. This function will unref the channel reference
+ * which was made in ast_autochan_setup
+ *
+ * \param autochan The autochan that you wish to destroy
+ * \retval void
+ */
+void ast_autochan_destroy(struct ast_autochan *autochan);
+
+/* \brief Switch what channel autochans point to
+ *
+ * Traverses the list of autochans. All autochans which point to
+ * old_chan will be updated to point to new_chan instead. Currently
+ * this is only called from ast_do_masquerade in channel.c. If some
+ * other context for calling this function should be determined, please
+ * call this function with both channels locked.
+ *
+ * \param old_chan The channel that autochans may currently point to
+ * \param new_chan The channel that we want to point those autochans to now
+ * \retval void
+ */
+void ast_autochan_new_channel(struct ast_channel *old_chan, struct ast_channel *new_chan);
+
+#endif /* _ASTERISK_AUTOCHAN_H */

Propchange: team/russell/ast_channel_ao2/include/asterisk/autochan.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/russell/ast_channel_ao2/include/asterisk/autochan.h
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/russell/ast_channel_ao2/include/asterisk/autochan.h
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: team/russell/ast_channel_ao2/main/Makefile
URL: http://svn.digium.com/svn-view/asterisk/team/russell/ast_channel_ao2/main/Makefile?view=diff&rev=176808&r1=176807&r2=176808
==============================================================================
--- team/russell/ast_channel_ao2/main/Makefile (original)
+++ team/russell/ast_channel_ao2/main/Makefile Tue Feb 17 18:22:32 2009
@@ -29,7 +29,7 @@
 	strcompat.o threadstorage.o dial.o event.o adsistub.o audiohook.o \
 	astobj2.o hashtab.o global_datastores.o version.o \
 	features.o taskprocessor.o timing.o datastore.o xml.o xmldoc.o \
-	strings.o
+	strings.o autochan.o
 
 # we need to link in the objects statically, not as a library, because
 # otherwise modules will not have them available if none of the static

Added: team/russell/ast_channel_ao2/main/autochan.c
URL: http://svn.digium.com/svn-view/asterisk/team/russell/ast_channel_ao2/main/autochan.c?view=auto&rev=176808
==============================================================================
--- team/russell/ast_channel_ao2/main/autochan.c (added)
+++ team/russell/ast_channel_ao2/main/autochan.c Tue Feb 17 18:22:32 2009
@@ -1,0 +1,89 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) <Year>, <Your Name Here>
+ *
+ * Mark Michelson <mmichelson 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 "smart" channels
+ *
+ * \author Mark Michelson <mmichelson at digium.com>
+ * 
+ */
+
+#include "asterisk.h"
+#include "asterisk/autochan.h"
+#include "asterisk/utils.h"
+#include "asterisk/linkedlists.h"
+#include "asterisk/options.h"
+#include "asterisk/channel.h"
+
+AST_LIST_HEAD_STATIC(autochans, ast_autochan);
+
+struct ast_autochan *ast_autochan_setup(struct ast_channel *chan)
+{
+	struct ast_autochan *autochan;
+
+	if (!(autochan = ast_calloc(1, sizeof(*autochan)))) {
+		return NULL;
+	}
+
+	autochan->chan = ast_channel_ref(chan);
+
+	AST_LIST_LOCK(&autochans);
+	AST_LIST_INSERT_TAIL(&autochans, autochan, list);
+	AST_LIST_UNLOCK(&autochans);
+
+	ast_debug(1, "Created autochan %p to hold channel %s (%p)\n", autochan, chan->name, chan);
+
+	return autochan;
+}
+
+void ast_autochan_destroy(struct ast_autochan *autochan)
+{
+	struct ast_autochan *autochan_iter;
+
+	AST_LIST_LOCK(&autochans);
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&autochans, autochan_iter, list) {
+		if (autochan_iter == autochan) {
+			AST_LIST_REMOVE_CURRENT(list);
+			ast_debug(1, "Removed autochan %p from the list, about to free it\n", autochan);
+			break;
+		}
+	}
+	AST_LIST_TRAVERSE_SAFE_END;
+	AST_LIST_UNLOCK(&autochans);
+	autochan->chan = ast_channel_unref(autochan->chan);
+	ast_free(autochan);
+}
+
+void ast_autochan_new_channel(struct ast_channel *old_chan, struct ast_channel *new_chan)
+{
+	struct ast_autochan *autochan;
+
+	AST_LIST_LOCK(&autochans);
+	AST_LIST_TRAVERSE(&autochans, autochan, list) {
+		if (autochan->chan == old_chan) {
+			autochan->chan = ast_channel_unref(old_chan);
+			autochan->chan = ast_channel_ref(new_chan);
+			if (option_debug > 1) {
+				ast_log(LOG_DEBUG, "Autochan %p used to hold channel %s (%p) but now holds channel %s (%p)\n", 
+						autochan, old_chan->name, old_chan, new_chan->name, new_chan);
+			}
+		}
+	}
+	AST_LIST_UNLOCK(&autochans);
+}

Propchange: team/russell/ast_channel_ao2/main/autochan.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/russell/ast_channel_ao2/main/autochan.c
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/russell/ast_channel_ao2/main/autochan.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: team/russell/ast_channel_ao2/main/channel.c
URL: http://svn.digium.com/svn-view/asterisk/team/russell/ast_channel_ao2/main/channel.c?view=diff&rev=176808&r1=176807&r2=176808
==============================================================================
--- team/russell/ast_channel_ao2/main/channel.c (original)
+++ team/russell/ast_channel_ao2/main/channel.c Tue Feb 17 18:22:32 2009
@@ -61,6 +61,7 @@
 #include "asterisk/slinfactory.h"
 #include "asterisk/audiohook.h"
 #include "asterisk/timing.h"
+#include "asterisk/autochan.h"
 
 #ifdef HAVE_EPOLL
 #include <sys/epoll.h>
@@ -4140,6 +4141,8 @@
 		AST_LIST_APPEND_LIST(&original->datastores, &clonechan->datastores, entry);
 	}
 
+	ast_autochan_new_channel(clonechan, original);
+
 	clone_variables(original, clonechan);
 	/* Presense of ADSI capable CPE follows clone */
 	original->adsicpe = clonechan->adsicpe;




More information about the asterisk-commits mailing list