[svn-commits] mmichelson: branch group/ari-greedy-atxfer r419689 - in /team/group/ari-greed...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Mon Jul 28 14:08:53 CDT 2014


Author: mmichelson
Date: Mon Jul 28 14:08:50 2014
New Revision: 419689

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=419689
Log:
This re-adds the content from review 3857, previously committed in revision 419683.


Modified:
    team/group/ari-greedy-atxfer/include/asterisk/bridge_features.h
    team/group/ari-greedy-atxfer/include/asterisk/stasis_app.h
    team/group/ari-greedy-atxfer/main/bridge.c
    team/group/ari-greedy-atxfer/res/res_stasis.c
    team/group/ari-greedy-atxfer/res/stasis/stasis_bridge.c

Modified: team/group/ari-greedy-atxfer/include/asterisk/bridge_features.h
URL: http://svnview.digium.com/svn/asterisk/team/group/ari-greedy-atxfer/include/asterisk/bridge_features.h?view=diff&rev=419689&r1=419688&r2=419689
==============================================================================
--- team/group/ari-greedy-atxfer/include/asterisk/bridge_features.h (original)
+++ team/group/ari-greedy-atxfer/include/asterisk/bridge_features.h Mon Jul 28 14:08:50 2014
@@ -157,6 +157,25 @@
  */
 typedef int (*ast_bridge_talking_indicate_callback)(struct ast_bridge_channel *bridge_channel, void *hook_pvt, int talking);
 
+/*!
+ * \brief Move indicator callback
+ *
+ * \details
+ * This callback can be registered with the bridge channel in order
+ * to be notified when the bridge channel is being moved from one
+ * bridge to another.
+ *
+ * \param bridge_channel The channel executing the feature
+ * \param hook_pvt Private data passed in when the hook was created
+ * \param src The bridge from which the bridge channel is moving
+ * \param dst The bridge into which the bridge channel is moving
+ *
+ * \retval 0 Keep the callback hook.
+ * \retval -1 Remove the callback hook.
+ */
+typedef int (*ast_bridge_move_indicate_callback)(struct ast_bridge_channel *bridge_channel,
+		void *hook_pvt, struct ast_bridge *src, struct ast_bridge *dst);
+
 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),
@@ -173,6 +192,7 @@
 	AST_BRIDGE_HOOK_TYPE_JOIN,
 	AST_BRIDGE_HOOK_TYPE_LEAVE,
 	AST_BRIDGE_HOOK_TYPE_TALK,
+	AST_BRIDGE_HOOK_TYPE_MOVE,
 };
 
 /*! \brief Structure that is the essence of a feature hook. */
@@ -621,6 +641,37 @@
 	enum ast_bridge_hook_remove_flags remove_flags);
 
 /*!
+ * \brief Attach a bridge channel move 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_move_hook(&features, move_callback, NULL, NULL, 0);
+ * \endcode
+ *
+ * This makes the bridging core call \ref callback when a
+ * channel is moved from one bridge to another.  A
+ * pointer to useful data may be provided to the hook_pvt
+ * parameter.
+ */
+int ast_bridge_move_hook(struct ast_bridge_features *features,
+	ast_bridge_move_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
  *
  * \param features Bridge features structure

Modified: team/group/ari-greedy-atxfer/include/asterisk/stasis_app.h
URL: http://svnview.digium.com/svn/asterisk/team/group/ari-greedy-atxfer/include/asterisk/stasis_app.h?view=diff&rev=419689&r1=419688&r2=419689
==============================================================================
--- team/group/ari-greedy-atxfer/include/asterisk/stasis_app.h (original)
+++ team/group/ari-greedy-atxfer/include/asterisk/stasis_app.h Mon Jul 28 14:08:50 2014
@@ -799,6 +799,28 @@
  */
 struct stasis_message_sanitizer *stasis_app_get_sanitizer(void);
 
+/*!
+ * \brief Stasis message type for a StasisEnd event
+ */
+struct stasis_message_type *ast_stasis_end_message_type(void);
+
+/*!
+ * \brief Indicate that this channel has had a StasisEnd published for it
+ *
+ * \param The channel that is exiting Stasis.
+ */
+void stasis_app_channel_set_stasis_end_published(struct ast_channel *chan);
+
+/*!
+ * \brief Has this channel had a StasisEnd published on it?
+ *
+ * \param chan The channel upon which the query rests.
+ *
+ * \retval 0 No
+ * \retval 1 Yes
+ */
+int stasis_app_channel_is_stasis_end_published(struct ast_channel *chan);
+
 /*! @} */
 
 #endif /* _ASTERISK_STASIS_APP_H */

Modified: team/group/ari-greedy-atxfer/main/bridge.c
URL: http://svnview.digium.com/svn/asterisk/team/group/ari-greedy-atxfer/main/bridge.c?view=diff&rev=419689&r1=419688&r2=419689
==============================================================================
--- team/group/ari-greedy-atxfer/main/bridge.c (original)
+++ team/group/ari-greedy-atxfer/main/bridge.c Mon Jul 28 14:08:50 2014
@@ -1817,6 +1817,32 @@
 	ao2_ref(old_bridge, -1);
 }
 
+static void bridge_channel_moving(struct ast_bridge_channel *bridge_channel, struct ast_bridge *src, struct ast_bridge *dst)
+{
+	struct ast_bridge_features *features = bridge_channel->features;
+	struct ast_bridge_hook *hook;
+	struct ao2_iterator iter;
+
+	/* Run any moving hooks. */
+	iter = ao2_iterator_init(features->other_hooks, 0);
+	for (; (hook = ao2_iterator_next(&iter)); ao2_ref(hook, -1)) {
+		int remove_me;
+		ast_bridge_move_indicate_callback move_cb;
+
+		if (hook->type != AST_BRIDGE_HOOK_TYPE_MOVE) {
+			continue;
+		}
+		move_cb = (ast_bridge_move_indicate_callback) hook->callback;
+		remove_me = move_cb(bridge_channel, hook->hook_pvt, src, dst);
+		if (remove_me) {
+			ast_debug(1, "Move 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);
+}
+
 void bridge_do_merge(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridge, struct ast_bridge_channel **kick_me, unsigned int num_kick,
 	unsigned int optimized)
 {
@@ -1864,6 +1890,8 @@
 			 */
 			continue;
 		}
+
+		bridge_channel_moving(bridge_channel, bridge_channel->bridge, dst_bridge);
 
 		/* Point to new bridge.*/
 		bridge_channel_change_bridge(bridge_channel, dst_bridge);
@@ -2114,6 +2142,8 @@
 	ao2_ref(orig_bridge, +1);/* Keep a ref in case the push fails. */
 	bridge_channel_change_bridge(bridge_channel, dst_bridge);
 
+	bridge_channel_moving(bridge_channel, orig_bridge, dst_bridge);
+
 	if (bridge_channel_internal_push(bridge_channel)) {
 		/* Try to put the channel back into the original bridge. */
 		ast_bridge_features_remove(bridge_channel->features,
@@ -3079,6 +3109,18 @@
 
 	return bridge_other_hook(features, hook_cb, hook_pvt, destructor, remove_flags,
 		AST_BRIDGE_HOOK_TYPE_TALK);
+}
+
+int ast_bridge_move_hook(struct ast_bridge_features *features,
+	ast_bridge_move_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_MOVE);
 }
 
 int ast_bridge_interval_hook(struct ast_bridge_features *features,

Modified: team/group/ari-greedy-atxfer/res/res_stasis.c
URL: http://svnview.digium.com/svn/asterisk/team/group/ari-greedy-atxfer/res/res_stasis.c?view=diff&rev=419689&r1=419688&r2=419689
==============================================================================
--- team/group/ari-greedy-atxfer/res/res_stasis.c (original)
+++ team/group/ari-greedy-atxfer/res/res_stasis.c Mon Jul 28 14:08:50 2014
@@ -107,6 +107,31 @@
 
 struct ao2_container *app_bridges_playback;
 
+static struct ast_json *stasis_end_json_payload(struct ast_channel_snapshot *snapshot,
+		const struct stasis_message_sanitizer *sanitize)
+{
+	return ast_json_pack("{s: s, s: o, s: o}",
+		"type", "StasisEnd",
+		"timestamp", ast_json_timeval(ast_tvnow(), NULL),
+		"channel", ast_channel_snapshot_to_json(snapshot, sanitize));
+}
+
+static struct ast_json *stasis_end_to_json(struct stasis_message *message,
+		const struct stasis_message_sanitizer *sanitize)
+{
+	struct ast_channel_blob *payload = stasis_message_data(message);
+
+	if (sanitize && sanitize->channel_snapshot &&
+			sanitize->channel_snapshot(payload->snapshot)) {
+		return NULL;
+	}
+
+	return stasis_end_json_payload(payload->snapshot, sanitize);
+}
+
+STASIS_MESSAGE_TYPE_DEFN(ast_stasis_end_message_type,
+	.to_json = stasis_end_to_json);
+
 const char *stasis_app_name(const struct stasis_app *app)
 {
 	return app_name(app);
@@ -904,10 +929,7 @@
 		return 0;
 	}
 
-	msg = ast_json_pack("{s: s, s: o, s: o}",
-		"type", "StasisEnd",
-		"timestamp", ast_json_timeval(ast_tvnow(), NULL),
-		"channel", ast_channel_snapshot_to_json(snapshot, NULL));
+	msg = stasis_end_json_payload(snapshot, sanitize);
 	if (!msg) {
 		return -1;
 	}
@@ -1061,6 +1083,46 @@
 	return control_is_done(control);
 }
 
+struct ast_datastore_info set_end_published_info = {
+	.type = "stasis_end_published",
+};
+
+void stasis_app_channel_set_stasis_end_published(struct ast_channel *chan)
+{
+	struct ast_datastore *datastore;
+
+	datastore = ast_datastore_alloc(&set_end_published_info, NULL);
+
+	ast_channel_lock(chan);
+	ast_channel_datastore_add(chan, datastore);
+	ast_channel_unlock(chan);
+}
+
+int stasis_app_channel_is_stasis_end_published(struct ast_channel *chan)
+{
+	struct ast_datastore *datastore;
+
+	ast_channel_lock(chan);
+	datastore = ast_channel_datastore_find(chan, &set_end_published_info, NULL);
+	ast_channel_unlock(chan);
+
+	return datastore ? 1 : 0;
+}
+
+static void remove_stasis_end_published(struct ast_channel *chan)
+{
+	struct ast_datastore *datastore;
+
+	ast_channel_lock(chan);
+	datastore = ast_channel_datastore_find(chan, &set_end_published_info, NULL);
+	ast_channel_unlock(chan);
+
+	if (datastore) {
+		ast_channel_datastore_remove(chan, datastore);
+		ast_datastore_free(datastore);
+	}
+}
+
 /*! /brief Stasis dialplan application callback */
 int stasis_app_exec(struct ast_channel *chan, const char *app_name, int argc,
 		    char *argv[])
@@ -1073,6 +1135,11 @@
 	int res = 0;
 
 	ast_assert(chan != NULL);
+
+	/* Just in case there's a lingering indication that the channel has had a stasis
+	 * end published on it, remove that now.
+	 */
+	remove_stasis_end_published(chan);
 
 	app = ao2_find(apps_registry, app_name, OBJ_SEARCH_KEY);
 	if (!app) {
@@ -1182,15 +1249,20 @@
 	}
 
 	app_unsubscribe_bridge(app, stasis_app_get_bridge(control));
-	app_unsubscribe_channel(app, chan);
 	ao2_cleanup(bridge);
 
-	res = send_end_msg(app, chan);
-	remove_masquerade_store(chan);
-	if (res != 0) {
-		ast_log(LOG_ERROR,
-			"Error sending end message to %s\n", app_name);
-		return res;
+	/* Only publish a stasis_end event if it hasn't already been published */
+	if (!stasis_app_channel_is_stasis_end_published(chan)) {
+		app_unsubscribe_channel(app, chan);
+		res = send_end_msg(app, chan);
+		remove_masquerade_store(chan);
+		if (res != 0) {
+			ast_log(LOG_ERROR,
+				"Error sending end message to %s\n", app_name);
+			return res;
+		}
+	} else {
+		remove_stasis_end_published(chan);
 	}
 
 	/* There's an off chance that app is ready for cleanup. Go ahead
@@ -1665,8 +1737,15 @@
 	ast_module_unref(ast_module_info->self);
 }
 
+/*!
+ * \brief Subscription to StasisEnd events
+ */
+struct stasis_subscription *stasis_end_sub;
+
 static int unload_module(void)
 {
+	stasis_end_sub = stasis_unsubscribe(stasis_end_sub);
+
 	stasis_app_unregister_event_sources();
 
 	ao2_cleanup(apps_registry);
@@ -1683,6 +1762,8 @@
 
 	ao2_cleanup(app_bridges_playback);
 	app_bridges_playback = NULL;
+
+	STASIS_MESSAGE_TYPE_CLEANUP(ast_stasis_end_message_type);
 
 	return 0;
 }
@@ -1715,8 +1796,53 @@
 	return &app_sanitizer;
 }
 
+static void remove_masquerade_store_by_name(const char *channel_name)
+{
+	struct ast_channel *chan;
+
+	chan = ast_channel_get_by_name(channel_name);
+	if (!chan) {
+		return;
+	}
+
+	remove_masquerade_store(chan);
+	ast_channel_unref(chan);
+}
+
+static void check_for_stasis_end(void *data, struct stasis_subscription *sub,
+		struct stasis_message *message)
+{
+	struct ast_channel_blob *payload;
+	struct ast_channel_snapshot *snapshot;
+	const char *app_name;
+	char *channel_uri;
+	size_t alloc_size;
+	const char *channels[1];
+
+	if (stasis_message_type(message) != ast_stasis_end_message_type()) {
+		return;
+	}
+
+	payload = stasis_message_data(message);
+	snapshot = payload->snapshot;
+	app_name = ast_json_string_get(ast_json_object_get(payload->blob, "app"));
+
+	/* +8 is for the length of "channel:" */
+	alloc_size = AST_MAX_UNIQUEID + 8;
+	channel_uri = ast_alloca(alloc_size);
+	snprintf(channel_uri, alloc_size, "channel:%s", snapshot->uniqueid);
+
+	channels[0] = channel_uri;
+	stasis_app_unsubscribe(app_name, channels, ARRAY_LEN(channels), NULL);
+
+	remove_masquerade_store_by_name(snapshot->name);
+}
+
 static int load_module(void)
 {
+	if (STASIS_MESSAGE_TYPE_INIT(ast_stasis_end_message_type) != 0) {
+		return AST_MODULE_LOAD_DECLINE;
+	}
 	apps_registry = ao2_container_alloc(APPS_NUM_BUCKETS, app_hash, app_compare);
 	app_controls = ao2_container_alloc(CONTROLS_NUM_BUCKETS, control_hash, control_compare);
 	app_bridges = ao2_container_alloc(BRIDGES_NUM_BUCKETS, bridges_hash, bridges_compare);
@@ -1735,6 +1861,12 @@
 
 	stasis_app_register_event_sources();
 
+	stasis_end_sub = stasis_subscribe(ast_channel_topic_all(), check_for_stasis_end, NULL);
+	if (!stasis_end_sub) {
+		unload_module();
+		return AST_MODULE_LOAD_DECLINE;
+	}
+
 	return AST_MODULE_LOAD_SUCCESS;
 }
 

Modified: team/group/ari-greedy-atxfer/res/stasis/stasis_bridge.c
URL: http://svnview.digium.com/svn/asterisk/team/group/ari-greedy-atxfer/res/stasis/stasis_bridge.c?view=diff&rev=419689&r1=419688&r2=419689
==============================================================================
--- team/group/ari-greedy-atxfer/res/stasis/stasis_bridge.c (original)
+++ team/group/ari-greedy-atxfer/res/stasis/stasis_bridge.c Mon Jul 28 14:08:50 2014
@@ -34,6 +34,9 @@
 #include "asterisk/bridge.h"
 #include "asterisk/bridge_after.h"
 #include "asterisk/bridge_internal.h"
+#include "asterisk/bridge_features.h"
+#include "asterisk/stasis_app.h"
+#include "asterisk/stasis_channels.h"
 #include "stasis_bridge.h"
 #include "control.h"
 #include "command.h"
@@ -42,6 +45,8 @@
 #include "asterisk/pbx.h"
 
 /* ------------------------------------------------------------------- */
+
+static struct ast_bridge_methods bridge_stasis_v_table;
 
 static void bridge_stasis_run_cb(struct ast_channel *chan, void *data)
 {
@@ -138,6 +143,33 @@
 	return ast_bridge_base_v_table.push(self, bridge_channel, swap);
 }
 
+static int bridge_stasis_moving(struct ast_bridge_channel *bridge_channel, void *hook_pvt,
+		struct ast_bridge *src, struct ast_bridge *dst)
+{
+	if (src->v_table == &bridge_stasis_v_table &&
+			dst->v_table != &bridge_stasis_v_table) {
+		RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
+		RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
+		struct ast_channel *chan;
+
+		chan = bridge_channel->chan;
+		ast_assert(chan != NULL);
+
+		control = stasis_app_control_find_by_channel(chan);
+		if (!control) {
+			return -1;
+		}
+
+		blob = ast_json_pack("{s: s}", "app", app_name(control_app(control)));
+
+		stasis_app_channel_set_stasis_end_published(chan);
+
+		ast_channel_publish_blob(chan, ast_stasis_end_message_type(), blob);
+	}
+
+	return -1;
+}
+
 /*!
  * \internal
  * \brief Pull this channel from the Stasis bridge.
@@ -157,10 +189,10 @@
 		ast_bridge_channel_update_accountcodes(NULL, bridge_channel);
 	}
 
+	ast_bridge_move_hook(bridge_channel->features, bridge_stasis_moving, NULL, NULL, 0);
+
 	ast_bridge_base_v_table.pull(self, bridge_channel);
 }
-
-static struct ast_bridge_methods bridge_stasis_v_table;
 
 struct ast_bridge *bridge_stasis_new(uint32_t capabilities, unsigned int flags, const char *name, const char *id)
 {




More information about the svn-commits mailing list