[asterisk-commits] rmudgett: trunk r395322 - in /trunk: apps/ include/asterisk/ main/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Jul 24 16:13:02 CDT 2013


Author: rmudgett
Date: Wed Jul 24 16:13:00 2013
New Revision: 395322

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=395322
Log:
Refactor ast_bridge_features struct.

* Reduced the number of hook containers to just dtmf_hooks,
interval_hooks, and other_hooks.  As a result, several functions dealing
with the different hook containers could be combined.

* Extended the generic hook struct for DTMF and interval hooks instead of
using a variant record.

* Merged the special talk detector hook into the other_hooks container.

* Replaced ast_bridge_features_set_talk_detector() with
ast_bridge_talk_detector_hook().

(issue ASTERISK-22107)

Modified:
    trunk/apps/app_confbridge.c
    trunk/include/asterisk/bridging_features.h
    trunk/main/bridging.c
    trunk/main/bridging_channel.c

Modified: trunk/apps/app_confbridge.c
URL: http://svnview.digium.com/svn/asterisk/trunk/apps/app_confbridge.c?view=diff&rev=395322&r1=395321&r2=395322
==============================================================================
--- trunk/apps/app_confbridge.c (original)
+++ trunk/apps/app_confbridge.c Wed Jul 24 16:13:00 2013
@@ -1402,25 +1402,26 @@
 	ast_free(pvt_data);
 }
 
-static void conf_handle_talker_cb(struct ast_bridge_channel *bridge_channel, void *pvt_data, int talking)
+static int conf_handle_talker_cb(struct ast_bridge_channel *bridge_channel, void *pvt_data, int talking)
 {
 	const char *conf_name = pvt_data;
 	struct confbridge_conference *conference = ao2_find(conference_bridges, conf_name, OBJ_KEY);
 	struct ast_json *talking_extras;
 
 	if (!conference) {
-		return;
+		/* Remove the hook since the conference does not exist. */
+		return -1;
 	}
 
 	talking_extras = ast_json_pack("{s: s}",
-					 "talking_status", talking ? "on" : "off");
-
+		"talking_status", talking ? "on" : "off");
 	if (!talking_extras) {
-		return;
+		return 0;
 	}
 
 	send_conf_stasis(conference, bridge_channel->chan, confbridge_talking_type(), talking_extras, 0);
 	ast_json_unref(talking_extras);
+	return 0;
 }
 
 static int conf_get_pin(struct ast_channel *chan, struct confbridge_user *user)
@@ -1599,14 +1600,17 @@
 	/* Set a talker indicate call back if talking detection is requested */
 	if (ast_test_flag(&user.u_profile, USER_OPT_TALKER_DETECT)) {
 		char *conf_name = ast_strdup(args.conf_name); /* this is freed during feature cleanup */
-		if (!(conf_name)) {
+
+		if (!conf_name) {
 			res = -1; /* invalid PIN */
 			goto confbridge_cleanup;
 		}
-		ast_bridge_features_set_talk_detector(&user.features,
-			conf_handle_talker_cb,
-			conf_handle_talker_destructor,
-			conf_name);
+		if (ast_bridge_talk_detector_hook(&user.features, conf_handle_talker_cb,
+			conf_name, conf_handle_talker_destructor, AST_BRIDGE_HOOK_REMOVE_ON_PULL)) {
+			ast_free(conf_name);
+			res = -1;
+			goto confbridge_cleanup;
+		}
 	}
 
 	/* Look for a conference bridge matching the provided name */

Modified: trunk/include/asterisk/bridging_features.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/bridging_features.h?view=diff&rev=395322&r1=395321&r2=395322
==============================================================================
--- trunk/include/asterisk/bridging_features.h (original)
+++ trunk/include/asterisk/bridging_features.h Wed Jul 24 16:13:00 2013
@@ -149,13 +149,43 @@
  * \param bridge_channel Channel executing the feature
  * \param talking TRUE if the channel is now talking
  *
- * \retval 0 success
- * \retval -1 failure
- */
-typedef void (*ast_bridge_talking_indicate_callback)(struct ast_bridge_channel *bridge_channel, void *pvt_data, int talking);
-
-
-typedef void (*ast_bridge_talking_indicate_destructor)(void *pvt_data);
+ * \retval 0 Keep the callback hook.
+ * \retval -1 Remove the callback hook.
+ */
+typedef int (*ast_bridge_talking_indicate_callback)(struct ast_bridge_channel *bridge_channel, void *pvt_data, int talking);
+
+enum ast_bridge_hook_remove_flags {
+	/*! The hook is removed when the channel is pulled from the bridge. */
+	AST_BRIDGE_HOOK_REMOVE_ON_PULL = (1 << 0),
+	/*! The hook is removed when the bridge's personality changes. */
+	AST_BRIDGE_HOOK_REMOVE_ON_PERSONALITY_CHANGE = (1 << 1),
+};
+
+enum ast_bridge_hook_type {
+	/*! The hook type has not been specified. */
+	AST_BRIDGE_HOOK_TYPE_NONE,
+	AST_BRIDGE_HOOK_TYPE_DTMF,
+	AST_BRIDGE_HOOK_TYPE_TIMER,
+	AST_BRIDGE_HOOK_TYPE_HANGUP,
+	AST_BRIDGE_HOOK_TYPE_JOIN,
+	AST_BRIDGE_HOOK_TYPE_LEAVE,
+	AST_BRIDGE_HOOK_TYPE_TALK,
+};
+
+/* BUGBUG Need to be able to selectively remove DTMF, hangup, and interval hooks. */
+/*! \brief Structure that is the essence of a feature hook. */
+struct ast_bridge_hook {
+	/*! Callback that is called when hook is tripped */
+	ast_bridge_hook_callback callback;
+	/*! Callback to destroy hook_pvt data right before destruction. */
+	ast_bridge_hook_pvt_destructor destructor;
+	/*! Unique data that was passed into us */
+	void *hook_pvt;
+	/*! Flags determining when hooks should be removed from a bridge channel */
+	struct ast_flags remove_flags;
+	/*! What kind of hook this is. */
+	enum ast_bridge_hook_type type;
+};
 
 /*!
  * \brief Maximum length of a DTMF feature string
@@ -163,13 +193,21 @@
 #define MAXIMUM_DTMF_FEATURE_STRING (11 + 1)
 
 /*! Extra parameters for a DTMF feature hook. */
-struct ast_bridge_hook_dtmf {
+struct ast_bridge_hook_dtmf_parms {
 	/*! DTMF String that is examined during a feature hook lookup */
 	char code[MAXIMUM_DTMF_FEATURE_STRING];
 };
 
+/*! DTMF specific hook. */
+struct ast_bridge_hook_dtmf {
+	/*! Generic feature hook information. */
+	struct ast_bridge_hook generic;
+	/*! Extra parameters for a DTMF feature hook. */
+	struct ast_bridge_hook_dtmf_parms dtmf;
+};
+
 /*! Extra parameters for an interval timer hook. */
-struct ast_bridge_hook_timer {
+struct ast_bridge_hook_timer_parms {
 	/*! Time at which the hook should actually trip */
 	struct timeval trip_time;
 	/*! Heap index for interval hook */
@@ -180,33 +218,12 @@
 	unsigned int seqno;
 };
 
-enum ast_bridge_hook_remove_flags {
-	/*! The hook is removed when the channel is pulled from the bridge. */
-	AST_BRIDGE_HOOK_REMOVE_ON_PULL = (1 << 0),
-	/*! The hook is removed when the bridge's personality changes. */
-	AST_BRIDGE_HOOK_REMOVE_ON_PERSONALITY_CHANGE = (1 << 1),
-};
-
-/* BUGBUG Need to be able to selectively remove DTMF, hangup, and interval hooks. */
-/*! \brief Structure that is the essence of a feature hook. */
-struct ast_bridge_hook {
-	/*! Linked list information */
-	AST_LIST_ENTRY(ast_bridge_hook) entry;
-	/*! Callback that is called when hook is tripped */
-	ast_bridge_hook_callback callback;
-	/*! Callback to destroy hook_pvt data right before destruction. */
-	ast_bridge_hook_pvt_destructor destructor;
-	/*! Unique data that was passed into us */
-	void *hook_pvt;
-	/*! Flags determining when hooks should be removed from a bridge channel */
-	struct ast_flags remove_flags;
-	/*! Extra hook parameters. */
-	union {
-		/*! Extra parameters for a DTMF feature hook. */
-		struct ast_bridge_hook_dtmf dtmf;
-		/*! Extra parameters for an interval timer hook. */
-		struct ast_bridge_hook_timer timer;
-	} parms;
+/*! Timer specific hook. */
+struct ast_bridge_hook_timer {
+	/*! Generic feature hook information. */
+	struct ast_bridge_hook generic;
+	/*! Extra parameters for an interval timer hook. */
+	struct ast_bridge_hook_timer_parms timer;
 };
 
 #define BRIDGE_FEATURES_INTERVAL_RATE 10
@@ -217,24 +234,14 @@
 struct ast_bridge_features {
 	/*! Attached DTMF feature hooks */
 	struct ao2_container *dtmf_hooks;
-	/*! Attached hangup interception hooks container */
-	struct ao2_container *hangup_hooks;
-	/*! Attached bridge channel join interception hooks container */
-	struct ao2_container *join_hooks;
-	/*! Attached bridge channel leave interception hooks container */
-	struct ao2_container *leave_hooks;
+	/*! Attached miscellaneous other hooks. */
+	struct ao2_container *other_hooks;
 	/*! Attached interval hooks */
 	struct ast_heap *interval_hooks;
 	/*! Used to determine when interval based features should be checked */
 	struct ast_timer *interval_timer;
 	/*! Limits feature data */
 	struct ast_bridge_features_limits *limits;
-	/*! Callback to indicate when a bridge channel has started and stopped talking */
-	ast_bridge_talking_indicate_callback talker_cb;
-	/*! Callback to destroy any pvt data stored for the talker. */
-	ast_bridge_talking_indicate_destructor talker_destructor_cb;
-	/*! Talker callback pvt data */
-	void *talker_pvt_data;
 	/*! Feature flags that are enabled */
 	struct ast_flags feature_flags;
 	/*! Used to assign the sequence number to the next interval hook added. */
@@ -575,19 +582,37 @@
 	enum ast_bridge_hook_remove_flags remove_flags);
 
 /*!
- * \brief Set a callback on the features structure to receive talking notifications on.
- *
- * \param features Bridge features structure
- * \param talker_cb Callback function to execute when talking events occur in the bridge core.
- * \param pvt_data Optional unique data that will be passed with the talking events.
- * \param talker_destructor Optional destructor callback for pvt data.
- *
- * \return Nothing
- */
-void ast_bridge_features_set_talk_detector(struct ast_bridge_features *features,
-	ast_bridge_talking_indicate_callback talker_cb,
-	ast_bridge_talking_indicate_destructor talker_destructor,
-	void *pvt_data);
+ * \brief Attach a bridge channel talk detection hook to a bridge features structure
+ *
+ * \param features Bridge features structure
+ * \param callback Function to execute upon activation
+ * \param hook_pvt Unique data
+ * \param destructor Optional destructor callback for hook_pvt data
+ * \param remove_flags Dictates what situations the hook should be removed.
+ *
+ * \retval 0 on success
+ * \retval -1 on failure (The caller must cleanup any hook_pvt resources.)
+ *
+ * Example usage:
+ *
+ * \code
+ * struct ast_bridge_features features;
+ * ast_bridge_features_init(&features);
+ * ast_bridge_talk_hook(&features, talk_callback, NULL, NULL, 0);
+ * \endcode
+ *
+ * This makes the bridging technology call talk_callback when a
+ * channel is recognized as starting and stopping talking.  A
+ * pointer to useful data may be provided to the hook_pvt
+ * parameter.
+ *
+ * \note This hook is currently only supported by softmix.
+ */
+int ast_bridge_talk_detector_hook(struct ast_bridge_features *features,
+	ast_bridge_talking_indicate_callback callback,
+	void *hook_pvt,
+	ast_bridge_hook_pvt_destructor destructor,
+	enum ast_bridge_hook_remove_flags remove_flags);
 
 /*!
  * \brief Enable a built in feature on a bridge features structure

Modified: trunk/main/bridging.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/bridging.c?view=diff&rev=395322&r1=395321&r2=395322
==============================================================================
--- trunk/main/bridging.c (original)
+++ trunk/main/bridging.c Wed Jul 24 16:13:00 2013
@@ -3509,16 +3509,17 @@
 	ast_bridge_hook_pvt_destructor destructor,
 	enum ast_bridge_hook_remove_flags remove_flags)
 {
-	struct ast_bridge_hook *hook;
+	struct ast_bridge_hook_dtmf *hook;
 	int res;
 
 	/* Allocate new hook and setup it's various variables */
-	hook = bridge_hook_generic(sizeof(*hook), callback, hook_pvt, destructor,
-		remove_flags);
+	hook = (struct ast_bridge_hook_dtmf *) bridge_hook_generic(sizeof(*hook), callback,
+		hook_pvt, destructor, remove_flags);
 	if (!hook) {
 		return -1;
 	}
-	ast_copy_string(hook->parms.dtmf.code, dtmf, sizeof(hook->parms.dtmf.code));
+	hook->generic.type = AST_BRIDGE_HOOK_TYPE_DTMF;
+	ast_copy_string(hook->dtmf.code, dtmf, sizeof(hook->dtmf.code));
 
 	/* Once done we put it in the container. */
 	res = ao2_link(features->dtmf_hooks, hook) ? 0 : -1;
@@ -3529,18 +3530,33 @@
 		 * Remove the hook_pvt destructor call from the hook since we
 		 * are returning failure to install the hook.
 		 */
-		hook->destructor = NULL;
+		hook->generic.destructor = NULL;
 	}
 	ao2_ref(hook, -1);
 
 	return res;
 }
 
-int ast_bridge_hangup_hook(struct ast_bridge_features *features,
+/*!
+ * \internal
+ * \brief Attach an other hook to a bridge features structure
+ *
+ * \param features Bridge features structure
+ * \param callback Function to execute upon activation
+ * \param hook_pvt Unique data
+ * \param destructor Optional destructor callback for hook_pvt data
+ * \param remove_flags Dictates what situations the hook should be removed.
+ * \param type What type of hook is being attached.
+ *
+ * \retval 0 on success
+ * \retval -1 on failure (The caller must cleanup any hook_pvt resources.)
+ */
+static int bridge_other_hook(struct ast_bridge_features *features,
 	ast_bridge_hook_callback callback,
 	void *hook_pvt,
 	ast_bridge_hook_pvt_destructor destructor,
-	enum ast_bridge_hook_remove_flags remove_flags)
+	enum ast_bridge_hook_remove_flags remove_flags,
+	enum ast_bridge_hook_type type)
 {
 	struct ast_bridge_hook *hook;
 	int res;
@@ -3551,9 +3567,10 @@
 	if (!hook) {
 		return -1;
 	}
+	hook->type = type;
 
 	/* Once done we put it in the container. */
-	res = ao2_link(features->hangup_hooks, hook) ? 0 : -1;
+	res = ao2_link(features->other_hooks, hook) ? 0 : -1;
 	if (res) {
 		/*
 		 * Could not link the hook into the container.
@@ -3568,36 +3585,24 @@
 	return res;
 }
 
+int ast_bridge_hangup_hook(struct ast_bridge_features *features,
+	ast_bridge_hook_callback callback,
+	void *hook_pvt,
+	ast_bridge_hook_pvt_destructor destructor,
+	enum ast_bridge_hook_remove_flags remove_flags)
+{
+	return bridge_other_hook(features, callback, hook_pvt, destructor, remove_flags,
+		AST_BRIDGE_HOOK_TYPE_HANGUP);
+}
+
 int ast_bridge_join_hook(struct ast_bridge_features *features,
 	ast_bridge_hook_callback callback,
 	void *hook_pvt,
 	ast_bridge_hook_pvt_destructor destructor,
 	enum ast_bridge_hook_remove_flags remove_flags)
 {
-	struct ast_bridge_hook *hook;
-	int res;
-
-	/* Allocate new hook and setup it's various variables */
-	hook = bridge_hook_generic(sizeof(*hook), callback, hook_pvt, destructor,
-		remove_flags);
-	if (!hook) {
-		return -1;
-	}
-
-	/* Once done we put it in the container. */
-	res = ao2_link(features->join_hooks, hook) ? 0 : -1;
-	if (res) {
-		/*
-		 * Could not link the hook into the container.
-		 *
-		 * Remove the hook_pvt destructor call from the hook since we
-		 * are returning failure to install the hook.
-		 */
-		hook->destructor = NULL;
-	}
-	ao2_ref(hook, -1);
-
-	return res;
+	return bridge_other_hook(features, callback, hook_pvt, destructor, remove_flags,
+		AST_BRIDGE_HOOK_TYPE_JOIN);
 }
 
 int ast_bridge_leave_hook(struct ast_bridge_features *features,
@@ -3606,40 +3611,20 @@
 	ast_bridge_hook_pvt_destructor destructor,
 	enum ast_bridge_hook_remove_flags remove_flags)
 {
-	struct ast_bridge_hook *hook;
-	int res;
-
-	/* Allocate new hook and setup it's various variables */
-	hook = bridge_hook_generic(sizeof(*hook), callback, hook_pvt, destructor,
-		remove_flags);
-	if (!hook) {
-		return -1;
-	}
-
-	/* Once done we put it in the container. */
-	res = ao2_link(features->leave_hooks, hook) ? 0 : -1;
-	if (res) {
-		/*
-		 * Could not link the hook into the container.
-		 *
-		 * Remove the hook_pvt destructor call from the hook since we
-		 * are returning failure to install the hook.
-		 */
-		hook->destructor = NULL;
-	}
-	ao2_ref(hook, -1);
-
-	return res;
-}
-
-void ast_bridge_features_set_talk_detector(struct ast_bridge_features *features,
-	ast_bridge_talking_indicate_callback talker_cb,
-	ast_bridge_talking_indicate_destructor talker_destructor,
-	void *pvt_data)
-{
-	features->talker_cb = talker_cb;
-	features->talker_destructor_cb = talker_destructor;
-	features->talker_pvt_data = pvt_data;
+	return bridge_other_hook(features, callback, hook_pvt, destructor, remove_flags,
+		AST_BRIDGE_HOOK_TYPE_LEAVE);
+}
+
+int ast_bridge_talk_detector_hook(struct ast_bridge_features *features,
+	ast_bridge_talking_indicate_callback callback,
+	void *hook_pvt,
+	ast_bridge_hook_pvt_destructor destructor,
+	enum ast_bridge_hook_remove_flags remove_flags)
+{
+	ast_bridge_hook_callback hook_cb = (ast_bridge_hook_callback) callback;
+
+	return bridge_other_hook(features, hook_cb, hook_pvt, destructor, remove_flags,
+		AST_BRIDGE_HOOK_TYPE_TALK);
 }
 
 int ast_bridge_interval_hook(struct ast_bridge_features *features,
@@ -3649,7 +3634,7 @@
 	ast_bridge_hook_pvt_destructor destructor,
 	enum ast_bridge_hook_remove_flags remove_flags)
 {
-	struct ast_bridge_hook *hook;
+	struct ast_bridge_hook_timer *hook;
 	int res;
 
 	if (!features ||!interval || !callback) {
@@ -3665,17 +3650,18 @@
 	}
 
 	/* Allocate new hook and setup it's various variables */
-	hook = bridge_hook_generic(sizeof(*hook), callback, hook_pvt, destructor,
-		remove_flags);
+	hook = (struct ast_bridge_hook_timer *) bridge_hook_generic(sizeof(*hook), callback,
+		hook_pvt, destructor, remove_flags);
 	if (!hook) {
 		return -1;
 	}
-	hook->parms.timer.interval = interval;
-	hook->parms.timer.trip_time = ast_tvadd(ast_tvnow(), ast_samp2tv(hook->parms.timer.interval, 1000));
-	hook->parms.timer.seqno = ast_atomic_fetchadd_int((int *) &features->interval_sequence, +1);
+	hook->generic.type = AST_BRIDGE_HOOK_TYPE_TIMER;
+	hook->timer.interval = interval;
+	hook->timer.trip_time = ast_tvadd(ast_tvnow(), ast_samp2tv(hook->timer.interval, 1000));
+	hook->timer.seqno = ast_atomic_fetchadd_int((int *) &features->interval_sequence, +1);
 
 	ast_debug(1, "Putting interval hook %p with interval %u in the heap on features %p\n",
-		hook, hook->parms.timer.interval, features);
+		hook, hook->timer.interval, features);
 	ast_heap_wrlock(features->interval_hooks);
 	res = ast_heap_push(features->interval_hooks, hook);
 	ast_heap_unlock(features->interval_hooks);
@@ -3686,7 +3672,7 @@
 		 * Remove the hook_pvt destructor call from the hook since we
 		 * are returning failure to install the hook.
 		 */
-		hook->destructor = NULL;
+		hook->generic.destructor = NULL;
 		ao2_ref(hook, -1);
 	}
 
@@ -3836,24 +3822,22 @@
 void ast_bridge_features_remove(struct ast_bridge_features *features, enum ast_bridge_hook_remove_flags remove_flags)
 {
 	hooks_remove_container(features->dtmf_hooks, remove_flags);
-	hooks_remove_container(features->hangup_hooks, remove_flags);
-	hooks_remove_container(features->join_hooks, remove_flags);
-	hooks_remove_container(features->leave_hooks, remove_flags);
+	hooks_remove_container(features->other_hooks, remove_flags);
 	hooks_remove_heap(features->interval_hooks, remove_flags);
 }
 
 static int interval_hook_time_cmp(void *a, void *b)
 {
-	struct ast_bridge_hook *hook_a = a;
-	struct ast_bridge_hook *hook_b = b;
+	struct ast_bridge_hook_timer *hook_a = a;
+	struct ast_bridge_hook_timer *hook_b = b;
 	int cmp;
 
-	cmp = ast_tvcmp(hook_b->parms.timer.trip_time, hook_a->parms.timer.trip_time);
+	cmp = ast_tvcmp(hook_b->timer.trip_time, hook_a->timer.trip_time);
 	if (cmp) {
 		return cmp;
 	}
 
-	cmp = hook_b->parms.timer.seqno - hook_a->parms.timer.seqno;
+	cmp = hook_b->timer.seqno - hook_a->timer.seqno;
 	return cmp;
 }
 
@@ -3875,21 +3859,21 @@
  */
 static int bridge_dtmf_hook_sort(const void *obj_left, const void *obj_right, int flags)
 {
-	const struct ast_bridge_hook *hook_left = obj_left;
-	const struct ast_bridge_hook *hook_right = obj_right;
+	const struct ast_bridge_hook_dtmf *hook_left = obj_left;
+	const struct ast_bridge_hook_dtmf *hook_right = obj_right;
 	const char *right_key = obj_right;
 	int cmp;
 
 	switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
 	default:
 	case OBJ_POINTER:
-		right_key = hook_right->parms.dtmf.code;
+		right_key = hook_right->dtmf.code;
 		/* Fall through */
 	case OBJ_KEY:
-		cmp = strcasecmp(hook_left->parms.dtmf.code, right_key);
+		cmp = strcasecmp(hook_left->dtmf.code, right_key);
 		break;
 	case OBJ_PARTIAL_KEY:
-		cmp = strncasecmp(hook_left->parms.dtmf.code, right_key, strlen(right_key));
+		cmp = strncasecmp(hook_left->dtmf.code, right_key, strlen(right_key));
 		break;
 	}
 	return cmp;
@@ -3908,30 +3892,16 @@
 		return -1;
 	}
 
-	/* Initialize the hangup hooks container */
-	features->hangup_hooks = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL,
+	/* Initialize the miscellaneous other hooks container */
+	features->other_hooks = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL,
 		NULL);
-	if (!features->hangup_hooks) {
-		return -1;
-	}
-
-	/* Initialize the join hooks container */
-	features->join_hooks = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL,
-		NULL);
-	if (!features->join_hooks) {
-		return -1;
-	}
-
-	/* Initialize the leave hooks container */
-	features->leave_hooks = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL,
-		NULL);
-	if (!features->leave_hooks) {
+	if (!features->other_hooks) {
 		return -1;
 	}
 
 	/* Initialize the interval hooks heap */
 	features->interval_hooks = ast_heap_create(8, interval_hook_time_cmp,
-		offsetof(struct ast_bridge_hook, parms.timer.heap_index));
+		offsetof(struct ast_bridge_hook_timer, timer.heap_index));
 	if (!features->interval_hooks) {
 		return -1;
 	}
@@ -3942,7 +3912,7 @@
 /* BUGBUG make ast_bridge_features_cleanup() static when make ast_bridge_join() requires features to be allocated. */
 void ast_bridge_features_cleanup(struct ast_bridge_features *features)
 {
-	struct ast_bridge_hook *hook;
+	struct ast_bridge_hook_timer *hook;
 
 	/* Destroy the interval hooks heap. */
 	if (features->interval_hooks) {
@@ -3964,22 +3934,9 @@
 		features->limits = NULL;
 	}
 
-	if (features->talker_destructor_cb && features->talker_pvt_data) {
-		features->talker_destructor_cb(features->talker_pvt_data);
-		features->talker_pvt_data = NULL;
-	}
-
-	/* Destroy the leave hooks container. */
-	ao2_cleanup(features->leave_hooks);
-	features->leave_hooks = NULL;
-
-	/* Destroy the join hooks container. */
-	ao2_cleanup(features->join_hooks);
-	features->join_hooks = NULL;
-
-	/* Destroy the hangup hooks container. */
-	ao2_cleanup(features->hangup_hooks);
-	features->hangup_hooks = NULL;
+	/* Destroy the miscellaneous other hooks container. */
+	ao2_cleanup(features->other_hooks);
+	features->other_hooks = NULL;
 
 	/* Destroy the DTMF hooks container. */
 	ao2_cleanup(features->dtmf_hooks);

Modified: trunk/main/bridging_channel.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/bridging_channel.c?view=diff&rev=395322&r1=395321&r2=395322
==============================================================================
--- trunk/main/bridging_channel.c (original)
+++ trunk/main/bridging_channel.c Wed Jul 24 16:13:00 2013
@@ -410,15 +410,18 @@
 	struct ao2_iterator iter;
 
 	/* Run any hangup hooks. */
-	iter = ao2_iterator_init(features->hangup_hooks, 0);
+	iter = ao2_iterator_init(features->other_hooks, 0);
 	for (; (hook = ao2_iterator_next(&iter)); ao2_ref(hook, -1)) {
 		int remove_me;
 
+		if (hook->type != AST_BRIDGE_HOOK_TYPE_HANGUP) {
+			continue;
+		}
 		remove_me = hook->callback(bridge_channel->bridge, bridge_channel, hook->hook_pvt);
 		if (remove_me) {
 			ast_debug(1, "Hangup hook %p is being removed from %p(%s)\n",
 				hook, bridge_channel, ast_channel_name(bridge_channel->chan));
-			ao2_unlink(features->hangup_hooks, hook);
+			ao2_unlink(features->other_hooks, hook);
 		}
 	}
 	ao2_iterator_destroy(&iter);
@@ -698,12 +701,12 @@
 static int bridge_channel_interval_ready(struct ast_bridge_channel *bridge_channel)
 {
 	struct ast_bridge_features *features = bridge_channel->features;
-	struct ast_bridge_hook *hook;
+	struct ast_bridge_hook_timer *hook;
 	int ready;
 
 	ast_heap_wrlock(features->interval_hooks);
 	hook = ast_heap_peek(features->interval_hooks, 1);
-	ready = hook && ast_tvdiff_ms(hook->parms.timer.trip_time, ast_tvnow()) <= 0;
+	ready = hook && ast_tvdiff_ms(hook->timer.trip_time, ast_tvnow()) <= 0;
 	ast_heap_unlock(features->interval_hooks);
 
 	return ready;
@@ -833,7 +836,7 @@
 /*! \brief Internal function that activates interval hooks on a bridge channel */
 static void bridge_channel_interval(struct ast_bridge_channel *bridge_channel)
 {
-	struct ast_bridge_hook *hook;
+	struct ast_bridge_hook_timer *hook;
 	struct timeval start;
 
 	ast_heap_wrlock(bridge_channel->features->interval_hooks);
@@ -842,7 +845,7 @@
 		int interval;
 		unsigned int execution_time;
 
-		if (ast_tvdiff_ms(hook->parms.timer.trip_time, start) > 0) {
+		if (ast_tvdiff_ms(hook->timer.trip_time, start) > 0) {
 			ast_debug(1, "Hook %p on %p(%s) wants to happen in the future, stopping our traversal\n",
 				hook, bridge_channel, ast_channel_name(bridge_channel->chan));
 			break;
@@ -852,11 +855,12 @@
 
 		ast_debug(1, "Executing hook %p on %p(%s)\n",
 			hook, bridge_channel, ast_channel_name(bridge_channel->chan));
-		interval = hook->callback(bridge_channel->bridge, bridge_channel, hook->hook_pvt);
+		interval = hook->generic.callback(bridge_channel->bridge, bridge_channel,
+			hook->generic.hook_pvt);
 
 		ast_heap_wrlock(bridge_channel->features->interval_hooks);
 		if (ast_heap_peek(bridge_channel->features->interval_hooks,
-			hook->parms.timer.heap_index) != hook
+			hook->timer.heap_index) != hook
 			|| !ast_heap_remove(bridge_channel->features->interval_hooks, hook)) {
 			/* Interval hook is already removed from the bridge_channel. */
 			ao2_ref(hook, -1);
@@ -872,11 +876,11 @@
 		}
 		if (interval) {
 			/* Set new interval for the hook. */
-			hook->parms.timer.interval = interval;
+			hook->timer.interval = interval;
 		}
 
 		ast_debug(1, "Updating interval hook %p with interval %u on %p(%s)\n",
-			hook, hook->parms.timer.interval, bridge_channel,
+			hook, hook->timer.interval, bridge_channel,
 			ast_channel_name(bridge_channel->chan));
 
 		/* resetting start */
@@ -887,12 +891,12 @@
 		 * to skip over any missed intervals because the hook was
 		 * delayed or took too long.
 		 */
-		execution_time = ast_tvdiff_ms(start, hook->parms.timer.trip_time);
-		while (hook->parms.timer.interval < execution_time) {
-			execution_time -= hook->parms.timer.interval;
-		}
-		hook->parms.timer.trip_time = ast_tvadd(start, ast_samp2tv(hook->parms.timer.interval - execution_time, 1000));
-		hook->parms.timer.seqno = ast_atomic_fetchadd_int((int *) &bridge_channel->features->interval_sequence, +1);
+		execution_time = ast_tvdiff_ms(start, hook->timer.trip_time);
+		while (hook->timer.interval < execution_time) {
+			execution_time -= hook->timer.interval;
+		}
+		hook->timer.trip_time = ast_tvadd(start, ast_samp2tv(hook->timer.interval - execution_time, 1000));
+		hook->timer.seqno = ast_atomic_fetchadd_int((int *) &bridge_channel->features->interval_sequence, +1);
 
 		if (ast_heap_push(bridge_channel->features->interval_hooks, hook)) {
 			/* Could not push the hook back onto the heap. */
@@ -916,7 +920,7 @@
 static void bridge_channel_feature(struct ast_bridge_channel *bridge_channel)
 {
 	struct ast_bridge_features *features = bridge_channel->features;
-	struct ast_bridge_hook *hook = NULL;
+	struct ast_bridge_hook_dtmf *hook = NULL;
 	char dtmf[MAXIMUM_DTMF_FEATURE_STRING] = "";
 	size_t dtmf_len = 0;
 	unsigned int digit_timeout;
@@ -965,7 +969,7 @@
 				bridge_channel, ast_channel_name(bridge_channel->chan), dtmf);
 			break;
 		}
-		if (strlen(hook->parms.dtmf.code) == dtmf_len) {
+		if (strlen(hook->dtmf.code) == dtmf_len) {
 			ast_debug(1, "DTMF feature hook %p matched DTMF string '%s' on %p(%s)\n",
 				hook, dtmf, bridge_channel, ast_channel_name(bridge_channel->chan));
 			break;
@@ -983,7 +987,8 @@
 	if (hook) {
 		int remove_me;
 
-		remove_me = hook->callback(bridge_channel->bridge, bridge_channel, hook->hook_pvt);
+		remove_me = hook->generic.callback(bridge_channel->bridge, bridge_channel,
+			hook->generic.hook_pvt);
 		if (remove_me) {
 			ast_debug(1, "DTMF hook %p is being removed from %p(%s)\n",
 				hook, bridge_channel, ast_channel_name(bridge_channel->chan));
@@ -1008,10 +1013,27 @@
 static void bridge_channel_talking(struct ast_bridge_channel *bridge_channel, int talking)
 {
 	struct ast_bridge_features *features = bridge_channel->features;
-
-	if (features->talker_cb) {
-		features->talker_cb(bridge_channel, features->talker_pvt_data, talking);
-	}
+	struct ast_bridge_hook *hook;
+	struct ao2_iterator iter;
+
+	/* Run any talk detection hooks. */
+	iter = ao2_iterator_init(features->other_hooks, 0);
+	for (; (hook = ao2_iterator_next(&iter)); ao2_ref(hook, -1)) {
+		int remove_me;
+		ast_bridge_talking_indicate_callback talk_cb;
+
+		if (hook->type != AST_BRIDGE_HOOK_TYPE_TALK) {
+			continue;
+		}
+		talk_cb = (ast_bridge_talking_indicate_callback) hook->callback;
+		remove_me = talk_cb(bridge_channel, hook->hook_pvt, talking);
+		if (remove_me) {
+			ast_debug(1, "Talk detection hook %p is being removed from %p(%s)\n",
+				hook, bridge_channel, ast_channel_name(bridge_channel->chan));
+			ao2_unlink(features->other_hooks, hook);
+		}
+	}
+	ao2_iterator_destroy(&iter);
 }
 
 /*! \brief Internal function that plays back DTMF on a bridge channel */
@@ -1533,7 +1555,7 @@
 static struct ast_frame *bridge_handle_dtmf(struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
 {
 	struct ast_bridge_features *features = bridge_channel->features;
-	struct ast_bridge_hook *hook;
+	struct ast_bridge_hook_dtmf *hook;
 	char dtmf[2];
 
 /* BUGBUG the feature hook matching needs to be done here.  Any matching feature hook needs to be queued onto the bridge_channel.  Also the feature hook digit timeout needs to be handled. */
@@ -1678,58 +1700,36 @@
 
 /*!
  * \internal
- * \brief Handle bridge channel join event.
+ * \brief Handle bridge channel join/leave event.
  * \since 12.0.0
  *
- * \param bridge_channel Which channel is joining.
+ * \param bridge_channel Which channel is involved.
+ * \param type Specified join/leave event.
  *
  * \return Nothing
  */
-static void bridge_channel_handle_join(struct ast_bridge_channel *bridge_channel)
+static void bridge_channel_event_join_leave(struct ast_bridge_channel *bridge_channel, enum ast_bridge_hook_type type)
 {
 	struct ast_bridge_features *features = bridge_channel->features;
 	struct ast_bridge_hook *hook;
 	struct ao2_iterator iter;
 
-	/* Run any join hooks. */
-	iter = ao2_iterator_init(features->join_hooks, AO2_ITERATOR_UNLINK);
-	hook = ao2_iterator_next(&iter);
+	/* Run the specified hooks. */
+	iter = ao2_iterator_init(features->other_hooks, 0);
+	for (; (hook = ao2_iterator_next(&iter)); ao2_ref(hook, -1)) {
+		if (hook->type == type) {
+			break;
+		}
+	}
 	if (hook) {
+		/* Found the first specified hook to run. */
 		bridge_channel_suspend(bridge_channel);
 		ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
 		do {
-			hook->callback(bridge_channel->bridge, bridge_channel, hook->hook_pvt);
-			ao2_ref(hook, -1);
-		} while ((hook = ao2_iterator_next(&iter)));
-		ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
-		bridge_channel_unsuspend(bridge_channel);
-	}
-	ao2_iterator_destroy(&iter);
-}
-
-/*!
- * \internal
- * \brief Handle bridge channel leave event.
- * \since 12.0.0
- *
- * \param bridge_channel Which channel is leaving.
- *
- * \return Nothing
- */
-static void bridge_channel_handle_leave(struct ast_bridge_channel *bridge_channel)
-{
-	struct ast_bridge_features *features = bridge_channel->features;
-	struct ast_bridge_hook *hook;
-	struct ao2_iterator iter;
-
-	/* Run any leave hooks. */
-	iter = ao2_iterator_init(features->leave_hooks, AO2_ITERATOR_UNLINK);
-	hook = ao2_iterator_next(&iter);
-	if (hook) {
-		bridge_channel_suspend(bridge_channel);
-		ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
-		do {
-			hook->callback(bridge_channel->bridge, bridge_channel, hook->hook_pvt);
+			if (hook->type == type) {
+				hook->callback(bridge_channel->bridge, bridge_channel, hook->hook_pvt);
+				ao2_unlink(features->other_hooks, hook);
+			}
 			ao2_ref(hook, -1);
 		} while ((hook = ao2_iterator_next(&iter)));
 		ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
@@ -1786,12 +1786,12 @@
 		}
 
 		ast_bridge_unlock(bridge_channel->bridge);
-		bridge_channel_handle_join(bridge_channel);
+		bridge_channel_event_join_leave(bridge_channel, AST_BRIDGE_HOOK_TYPE_JOIN);
 		while (bridge_channel->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
 			/* Wait for something to do. */
 			bridge_channel_wait(bridge_channel);
 		}
-		bridge_channel_handle_leave(bridge_channel);
+		bridge_channel_event_join_leave(bridge_channel, AST_BRIDGE_HOOK_TYPE_LEAVE);
 		ast_bridge_channel_lock_bridge(bridge_channel);
 	}
 




More information about the asterisk-commits mailing list