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

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon May 13 12:36:35 CDT 2013


Author: rmudgett
Date: Mon May 13 12:36:33 2013
New Revision: 388527

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=388527
Log:
Add ability to set a callback call when a channel leaves the bridging system.

Modified:
    team/rmudgett/bridge_phase/include/asterisk/bridging.h
    team/rmudgett/bridge_phase/main/bridging.c

Modified: team/rmudgett/bridge_phase/include/asterisk/bridging.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/include/asterisk/bridging.h?view=diff&rev=388527&r1=388526&r2=388527
==============================================================================
--- team/rmudgett/bridge_phase/include/asterisk/bridging.h (original)
+++ team/rmudgett/bridge_phase/include/asterisk/bridging.h Mon May 13 12:36:33 2013
@@ -1419,6 +1419,67 @@
  */
 void ast_after_bridge_goto_discard(struct ast_channel *chan);
 
+/*! Reason the the after bridge callback will not be called. */
+enum ast_after_bridge_cb_reason {
+	/*! The datastore is being destroyed.  Likely due to hangup. */
+	AST_AFTER_BRIDGE_CB_REASON_DESTROY,
+	/*! Something else replaced the callback with another. */
+	AST_AFTER_BRIDGE_CB_REASON_REPLACED,
+	/*! The callback was removed because of a masquerade. (fixup) */
+	AST_AFTER_BRIDGE_CB_REASON_MASQUERADE,
+	/*! The channel departed bridge. */
+	AST_AFTER_BRIDGE_CB_REASON_DEPART,
+	/*! Was explicitly removed by external code. */
+	AST_AFTER_BRIDGE_CB_REASON_REMOVED,
+};
+
+/*!
+ * \brief After bridge callback failed.
+ * \since 12.0.0
+ *
+ * \param reason Reason callback is failing.
+ * \param data Extra data what setup the callback wanted to pass.
+ *
+ * \return Nothing
+ */
+typedef void (*ast_after_bridge_cb_failed)(enum ast_after_bridge_cb_reason reason, void *data);
+
+/*!
+ * \brief After bridge callback function.
+ * \since 12.0.0
+ *
+ * \param chan Channel just leaving bridging system.
+ * \param data Extra data what setup the callback wanted to pass.
+ *
+ * \return Nothing
+ */
+typedef void (*ast_after_bridge_cb)(struct ast_channel *chan, void *data);
+
+/*!
+ * \brief Discard channel after bridge callback.
+ * \since 12.0.0
+ *
+ * \param chan Channel to discard after bridge callback.
+ * \param reason Why are we doing this.
+ *
+ * \return Nothing
+ */
+void ast_after_bridge_callback_discard(struct ast_channel *chan, enum ast_after_bridge_cb_reason reason);
+
+/*!
+ * \brief Setup an after bridge callback for when the channel leaves the bridging system.
+ * \since 12.0.0
+ *
+ * \param chan Channel to setup an after bridge callback on.
+ * \param callback Function to call when the channel leaves the bridging system.
+ * \param failed Function to call when will not be calling the callback.
+ * \param data Extra data to pass with the callback.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int ast_after_bridge_callback_set(struct ast_channel *chan, ast_after_bridge_cb callback, ast_after_bridge_cb_failed failed, void *data);
+
 /*!
  * \brief Get a container of all channels in the bridge
  * \since 12.0.0

Modified: team/rmudgett/bridge_phase/main/bridging.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/main/bridging.c?view=diff&rev=388527&r1=388526&r2=388527
==============================================================================
--- team/rmudgett/bridge_phase/main/bridging.c (original)
+++ team/rmudgett/bridge_phase/main/bridging.c Mon May 13 12:36:33 2013
@@ -2552,6 +2552,167 @@
 	return bridge_channel;
 }
 
+struct after_bridge_cb_ds {
+	/*! Desired callback function. */
+	ast_after_bridge_cb callback;
+	/*! After bridge callback will not be called and destroy any resources data may contain. */
+	ast_after_bridge_cb_failed failed;
+	/*! Extra data to pass to the callback. */
+	void *data;
+};
+
+/*!
+ * \internal
+ * \brief Destroy the after bridge callback datastore.
+ * \since 12.0.0
+ *
+ * \param data After bridge callback data to destroy.
+ *
+ * \return Nothing
+ */
+static void after_bridge_cb_destroy(void *data)
+{
+	struct after_bridge_cb_ds *after_bridge = data;
+
+	if (after_bridge->failed) {
+		after_bridge->failed(AST_AFTER_BRIDGE_CB_REASON_DESTROY, after_bridge->data);
+		after_bridge->failed = NULL;
+	}
+}
+
+/*!
+ * \internal
+ * \brief Fixup the after bridge callback datastore.
+ * \since 12.0.0
+ *
+ * \param data After bridge callback data to fixup.
+ * \param old_chan The datastore is moving from this channel.
+ * \param new_chan The datastore is moving to this channel.
+ *
+ * \return Nothing
+ */
+static void after_bridge_cb_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
+{
+	/* There can be only one.  Discard any already on the new channel. */
+	ast_after_bridge_callback_discard(new_chan, AST_AFTER_BRIDGE_CB_REASON_MASQUERADE);
+}
+
+static const struct ast_datastore_info after_bridge_cb_info = {
+	.type = "after-bridge-cb",
+	.destroy = after_bridge_cb_destroy,
+	.chan_fixup = after_bridge_cb_fixup,
+};
+
+/*!
+ * \internal
+ * \brief Remove channel after the bridge callback and return it.
+ * \since 12.0.0
+ *
+ * \param chan Channel to remove after bridge callback.
+ *
+ * \retval datastore on success.
+ * \retval NULL on error or not found.
+ */
+static struct ast_datastore *after_bridge_cb_remove(struct ast_channel *chan)
+{
+	struct ast_datastore *datastore;
+
+	ast_channel_lock(chan);
+	datastore = ast_channel_datastore_find(chan, &after_bridge_cb_info, NULL);
+	if (datastore && ast_channel_datastore_remove(chan, datastore)) {
+		datastore = NULL;
+	}
+	ast_channel_unlock(chan);
+
+	return datastore;
+}
+
+void ast_after_bridge_callback_discard(struct ast_channel *chan, enum ast_after_bridge_cb_reason reason)
+{
+	struct ast_datastore *datastore;
+
+	datastore = after_bridge_cb_remove(chan);
+	if (datastore) {
+		struct after_bridge_cb_ds *after_bridge = datastore->data;
+
+		if (after_bridge && after_bridge->failed) {
+			after_bridge->failed(reason, after_bridge->data);
+			after_bridge->failed = NULL;
+		}
+		ast_datastore_free(datastore);
+	}
+}
+
+/*!
+ * \internal
+ * \brief Run any after bridge callback if possible.
+ * \since 12.0.0
+ *
+ * \param chan Channel to run after bridge callback.
+ *
+ * \return Nothing
+ */
+static void after_bridge_callback_run(struct ast_channel *chan)
+{
+	struct ast_datastore *datastore;
+	struct after_bridge_cb_ds *after_bridge;
+
+	if (ast_check_hangup(chan)) {
+		return;
+	}
+
+	/* Get after bridge goto datastore. */
+	datastore = after_bridge_cb_remove(chan);
+	if (!datastore) {
+		return;
+	}
+
+	after_bridge = datastore->data;
+	if (after_bridge) {
+		after_bridge->failed = NULL;
+		after_bridge->callback(chan, after_bridge->data);
+	}
+
+	/* Discard after bridge callback datastore. */
+	ast_datastore_free(datastore);
+}
+
+int ast_after_bridge_callback_set(struct ast_channel *chan, ast_after_bridge_cb callback, ast_after_bridge_cb_failed failed, void *data)
+{
+	struct ast_datastore *datastore;
+	struct after_bridge_cb_ds *after_bridge;
+
+	/* Sanity checks. */
+	ast_assert(chan != NULL);
+	if (!chan || !callback) {
+		return -1;
+	}
+
+	/* Create a new datastore. */
+	datastore = ast_datastore_alloc(&after_bridge_cb_info, NULL);
+	if (!datastore) {
+		return -1;
+	}
+	after_bridge = ast_calloc(1, sizeof(*after_bridge));
+	if (!after_bridge) {
+		ast_datastore_free(datastore);
+		return -1;
+	}
+
+	/* Initialize it. */
+	after_bridge->callback = callback;
+	after_bridge->failed = failed;
+	after_bridge->data = data;
+
+	/* Put it on the channel replacing any existing one. */
+	ast_channel_lock(chan);
+	ast_after_bridge_callback_discard(chan, AST_AFTER_BRIDGE_CB_REASON_REPLACED);
+	ast_channel_datastore_add(chan, datastore);
+	ast_channel_unlock(chan);
+
+	return 0;
+}
+
 struct after_bridge_goto_ds {
 	/*! Goto string that can be parsed by ast_parseable_goto(). */
 	const char *parseable_goto;
@@ -2922,6 +3083,7 @@
 
 join_exit:;
 /* BUGBUG this is going to cause problems for DTMF atxfer attended bridge between B & C.  Maybe an ast_bridge_join_internal() that does not do the after bridge goto for this case. */
+	after_bridge_callback_run(chan);
 	if (!(ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO)
 		&& !ast_after_bridge_goto_setup(chan)) {
 		/* Claim the after bridge goto is an async goto destination. */
@@ -2948,6 +3110,7 @@
 	ast_bridge_features_destroy(bridge_channel->features);
 	bridge_channel->features = NULL;
 
+	ast_after_bridge_callback_discard(bridge_channel->chan, AST_AFTER_BRIDGE_CB_REASON_DEPART);
 	ast_after_bridge_goto_discard(bridge_channel->chan);
 
 	return NULL;
@@ -2977,6 +3140,7 @@
 
 	ao2_ref(bridge_channel, -1);
 
+	after_bridge_callback_run(chan);
 	ast_after_bridge_goto_run(chan);
 	return NULL;
 }




More information about the asterisk-commits mailing list