[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