[asterisk-commits] rmudgett: branch group/bridge_construction r382567 - in /team/group/bridge_co...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Wed Mar 6 18:43:58 CST 2013
Author: rmudgett
Date: Wed Mar 6 18:43:54 2013
New Revision: 382567
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=382567
Log:
* Add hangup event hooks.
* Rework DTMF and interval hooks. Involved renaming associated functions
and structs. Relaid out struct ast_bridge_hook.
* Rework DTMF attended transfer to eliminate the need for specially
interpreting the ast_bridge_join() return value. Completed the
elimination of AST_BRIDGE_CHANNEL_STATE_DEPART.
* Added missing destructor parameter to ast_bridge_features_enable().
Modified:
team/group/bridge_construction/apps/confbridge/conf_config_parser.c
team/group/bridge_construction/bridges/bridge_builtin_features.c
team/group/bridge_construction/bridges/bridge_builtin_interval_features.c
team/group/bridge_construction/include/asterisk/bridging.h
team/group/bridge_construction/include/asterisk/bridging_features.h
team/group/bridge_construction/main/bridging.c
team/group/bridge_construction/main/features.c
Modified: team/group/bridge_construction/apps/confbridge/conf_config_parser.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/apps/confbridge/conf_config_parser.c?view=diff&rev=382567&r1=382566&r2=382567
==============================================================================
--- team/group/bridge_construction/apps/confbridge/conf_config_parser.c (original)
+++ team/group/bridge_construction/apps/confbridge/conf_config_parser.c Wed Mar 6 18:43:54 2013
@@ -2052,7 +2052,7 @@
ao2_ref(menu, +1);
pvt->menu = menu;
- ast_bridge_features_hook(&conference_bridge_user->features, pvt->menu_entry.dtmf, menu_hook_callback, pvt, menu_hook_destroy);
+ ast_bridge_dtmf_hook(&conference_bridge_user->features, pvt->menu_entry.dtmf, menu_hook_callback, pvt, menu_hook_destroy);
}
ao2_unlock(menu);
Modified: team/group/bridge_construction/bridges/bridge_builtin_features.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/bridges/bridge_builtin_features.c?view=diff&rev=382567&r1=382566&r2=382567
==============================================================================
--- team/group/bridge_construction/bridges/bridge_builtin_features.c (original)
+++ team/group/bridge_construction/bridges/bridge_builtin_features.c Wed Mar 6 18:43:54 2013
@@ -201,15 +201,45 @@
return 0;
}
+/*! Attended transfer code */
+enum atxfer_code {
+ /*! Party C hungup or other reason to abandon the transfer. */
+ ATXFER_INCOMPLETE,
+ /*! Transfer party C to party A. */
+ ATXFER_COMPLETE,
+ /*! Turn the transfer into a threeway call. */
+ ATXFER_THREEWAY,
+ /*! Hangup party C and return party B to the bridge. */
+ ATXFER_ABORT,
+};
+
+/*! \brief Attended transfer feature to complete transfer */
+static int attended_transfer_complete(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
+{
+ enum atxfer_code *transfer_code = hook_pvt;
+
+ *transfer_code = ATXFER_COMPLETE;
+ ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
+ return 0;
+}
+
/*! \brief Attended transfer feature to turn it into a threeway call */
-static int attended_threeway_transfer(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
-{
- /*
- * This is sort of abusing the depart state but in this instance
- * it is only going to be handled by feature_attended_transfer()
- * so it is okay.
- */
- ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_DEPART);
+static int attended_transfer_threeway(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
+{
+ enum atxfer_code *transfer_code = hook_pvt;
+
+ *transfer_code = ATXFER_THREEWAY;
+ ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
+ return 0;
+}
+
+/*! \brief Attended transfer feature to abort transfer */
+static int attended_transfer_abort(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
+{
+ enum atxfer_code *transfer_code = hook_pvt;
+
+ *transfer_code = ATXFER_ABORT;
+ ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
return 0;
}
@@ -220,10 +250,10 @@
struct ast_channel *peer;
struct ast_bridge *attended_bridge;
struct ast_bridge_features caller_features;
- enum ast_bridge_channel_state attended_bridge_result;
int xfer_failed;
struct ast_bridge_features_attended_transfer *attended_transfer = hook_pvt;
const char *context;
+ enum atxfer_code transfer_code = ATXFER_INCOMPLETE;
/* BUGBUG the peer needs to be put on hold for the transfer. */
ast_channel_lock(bridge_channel->chan);
@@ -264,22 +294,31 @@
return 0;
}
- /* Before we join setup a features structure with the hangup option, just in case they want to use DTMF */
+ /* Setup a DTMF menu to control the transfer. */
ast_bridge_features_init(&caller_features);
/* BUGBUG bridging API features does not support features.conf featuremap */
/* BUGBUG bridging API features does not support the features.conf atxfer bounce between C & B channels */
-/* BUGBUG The atxfer feature hooks need to be passed a pointer to where to mark which hook happened. Rather than relying on the bridge join return value. */
- ast_bridge_features_enable(&caller_features, AST_BRIDGE_BUILTIN_HANGUP,
+ ast_bridge_hangup_hook(&caller_features,
+ attended_transfer_complete, &transfer_code, NULL);
+ ast_bridge_dtmf_hook(&caller_features,
+ attended_transfer && !ast_strlen_zero(attended_transfer->abort)
+ ? attended_transfer->abort : "*1",
+ attended_transfer_abort, &transfer_code, NULL);
+ ast_bridge_dtmf_hook(&caller_features,
attended_transfer && !ast_strlen_zero(attended_transfer->complete)
- ? attended_transfer->complete : "*1",
- NULL);
- ast_bridge_features_hook(&caller_features,
+ ? attended_transfer->complete : "*2",
+ attended_transfer_complete, &transfer_code, NULL);
+ ast_bridge_dtmf_hook(&caller_features,
attended_transfer && !ast_strlen_zero(attended_transfer->threeway)
- ? attended_transfer->threeway : "*2",
- attended_threeway_transfer, NULL, NULL);
-
- /* But for the caller we want to join the bridge in a blocking fashion so we don't spin around in this function doing nothing while waiting */
- attended_bridge_result = ast_bridge_join(attended_bridge, bridge_channel->chan, NULL, &caller_features, NULL, 0);
+ ? attended_transfer->threeway : "*3",
+ attended_transfer_threeway, &transfer_code, NULL);
+
+ /*
+ * For the caller we want to join the bridge in a blocking
+ * fashion so we don't spin around in this function doing
+ * nothing while waiting.
+ */
+ ast_bridge_join(attended_bridge, bridge_channel->chan, NULL, &caller_features, NULL, 0);
/* Wait for peer thread to exit bridge and die. */
if (!ast_autoservice_start(bridge_channel->chan)) {
@@ -294,21 +333,16 @@
ast_bridge_destroy(attended_bridge);
xfer_failed = -1;
- switch (attended_bridge_result) {
- case AST_BRIDGE_CHANNEL_STATE_END:
- if (!ast_check_hangup_locked(bridge_channel->chan)) {
- /* Transferer aborted the transfer. */
- break;
- }
-
+ switch (transfer_code) {
+ case ATXFER_INCOMPLETE:
+ /* Peer hungup */
+ break;
+ case ATXFER_COMPLETE:
/* The peer takes our place in the bridge. */
ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
xfer_failed = ast_bridge_impart(bridge, peer, bridge_channel->chan, NULL, 1);
break;
- case AST_BRIDGE_CHANNEL_STATE_HANGUP:
- /* Peer hungup */
- break;
- case AST_BRIDGE_CHANNEL_STATE_DEPART:
+ case ATXFER_THREEWAY:
/*
* Transferer wants to convert to a threeway call.
*
@@ -317,7 +351,8 @@
*/
xfer_failed = ast_bridge_impart(bridge, peer, NULL, NULL, 1);
break;
- default:
+ case ATXFER_ABORT:
+ /* Transferer decided not to transfer the call after all. */
break;
}
if (xfer_failed) {
Modified: team/group/bridge_construction/bridges/bridge_builtin_interval_features.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/bridges/bridge_builtin_interval_features.c?view=diff&rev=382567&r1=382566&r2=382567
==============================================================================
--- team/group/bridge_construction/bridges/bridge_builtin_interval_features.c (original)
+++ team/group/bridge_construction/bridges/bridge_builtin_interval_features.c Wed Mar 6 18:43:54 2013
@@ -134,7 +134,7 @@
}
if (limits->frequency) {
- ast_bridge_features_interval_update(bridge_channel, limits->frequency);
+ ast_bridge_interval_hook_update(bridge_channel, limits->frequency);
}
return !limits->frequency ? -1 : 0;
@@ -177,7 +177,7 @@
copy_bridge_features_limits(feature_limits, limits);
features->limits = feature_limits;
- if (ast_bridge_features_interval_hook(features, feature_limits->duration,
+ if (ast_bridge_interval_hook(features, feature_limits->duration,
bridge_features_duration_callback, feature_limits, NULL)) {
ast_log(LOG_ERROR, "Failed to schedule the duration limiter to the bridge channel.\n");
return -1;
@@ -186,15 +186,15 @@
feature_limits->quitting_time = ast_tvadd(ast_tvnow(), ast_samp2tv(feature_limits->duration, 1000));
if (!ast_strlen_zero(feature_limits->connect_sound)) {
- if (ast_bridge_features_interval_hook(features, 1, bridge_features_connect_callback, feature_limits, NULL)) {
+ if (ast_bridge_interval_hook(features, 1,
+ bridge_features_connect_callback, feature_limits, NULL)) {
ast_log(LOG_WARNING, "Failed to schedule connect sound to the bridge channel.\n");
}
}
if (feature_limits->warning && feature_limits->warning < feature_limits->duration) {
- if (ast_bridge_features_interval_hook(features, feature_limits->duration - feature_limits->warning,
- bridge_features_warning_callback,
- feature_limits, NULL)) {
+ if (ast_bridge_interval_hook(features, feature_limits->duration - feature_limits->warning,
+ bridge_features_warning_callback, feature_limits, NULL)) {
ast_log(LOG_WARNING, "Failed to schedule warning sound playback to the bridge channel.\n");
}
}
Modified: team/group/bridge_construction/include/asterisk/bridging.h
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/include/asterisk/bridging.h?view=diff&rev=382567&r1=382566&r2=382567
==============================================================================
--- team/group/bridge_construction/include/asterisk/bridging.h (original)
+++ team/group/bridge_construction/include/asterisk/bridging.h Wed Mar 6 18:43:54 2013
@@ -92,8 +92,6 @@
AST_BRIDGE_CHANNEL_STATE_END,
/*! Bridged channel was forced out and should be hung up */
AST_BRIDGE_CHANNEL_STATE_HANGUP,
- /*! Bridged channel was ast_bridge_depart() from the bridge without being hung up */
- AST_BRIDGE_CHANNEL_STATE_DEPART,
};
/*! \brief Return values for bridge technology write function */
@@ -531,7 +529,6 @@
*
* \return Nothing
*/
-
void ast_bridge_merge_inhibit(struct ast_bridge *bridge, int request);
/*!
Modified: team/group/bridge_construction/include/asterisk/bridging_features.h
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/include/asterisk/bridging_features.h?view=diff&rev=382567&r1=382566&r2=382567
==============================================================================
--- team/group/bridge_construction/include/asterisk/bridging_features.h (original)
+++ team/group/bridge_construction/include/asterisk/bridging_features.h Wed Mar 6 18:43:54 2013
@@ -97,23 +97,23 @@
struct ast_bridge_channel;
/*!
- * \brief Features hook callback type
+ * \brief Hook callback type
*
* \param bridge The bridge that the channel is part of
* \param bridge_channel Channel executing the feature
* \param hook_pvt Private data passed in when the hook was created
*
- * \retval 0 success
- * \retval -1 failure The callback hook is removed.
- */
-typedef int (*ast_bridge_features_hook_callback)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt);
-
-/*!
- * \brief Features hook pvt destructor callback
- *
- * \param hook_pvt Private data passed in when the hook was create to destroy
- */
-typedef void (*ast_bridge_features_hook_pvt_destructor)(void *hook_pvt);
+ * \retval 0 Keep the callback hook.
+ * \retval -1 Remove the callback hook.
+ */
+typedef int (*ast_bridge_hook_callback)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt);
+
+/*!
+ * \brief Hook pvt destructor callback
+ *
+ * \param hook_pvt Private data passed in when the hook was created to destroy
+ */
+typedef void (*ast_bridge_hook_pvt_destructor)(void *hook_pvt);
/*!
* \brief Talking indicator callback
@@ -138,30 +138,43 @@
*/
#define MAXIMUM_DTMF_FEATURE_STRING 8
-/*!
- * \brief Structure that is the essence of a features hook
- */
-struct ast_bridge_features_hook {
- union {
- /*! DTMF String that is examined during a feature hook lookup */
- char dtmf[MAXIMUM_DTMF_FEATURE_STRING];
- /*! Interval that the feature hook should execute at in milliseconds */
- unsigned int interval;
- };
- /*! Time at which the interval should actually trip */
- struct timeval interval_trip_time;
- /*! Callback that is called when DTMF string is matched */
- ast_bridge_features_hook_callback callback;
+/*! Extra parameters for a DTMF feature hook. */
+struct ast_bridge_hook_dtmf {
+ /*! DTMF String that is examined during a feature hook lookup */
+ char code[MAXIMUM_DTMF_FEATURE_STRING];
+};
+
+/*! Extra parameters for an interval timer hook. */
+struct ast_bridge_hook_timer {
+ /*! Time at which the hook should actually trip */
+ struct timeval trip_time;
+ /*! Heap index for interval hook */
+ ssize_t __heap_index;
+ /*! Interval that the hook should execute at in milliseconds */
+ unsigned int interval;
+ /*! Sequence number for the hook to ensure expiration ordering */
+ unsigned int seqno;
+};
+
+/*!
+ * \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_features_hook_pvt_destructor destructor;
+ ast_bridge_hook_pvt_destructor destructor;
/*! Unique data that was passed into us */
void *hook_pvt;
- /*! Sequence number for the hook if it is an interval hook */
- unsigned int seqno;
- /*! Linked list information */
- AST_LIST_ENTRY(ast_bridge_features_hook) entry;
- /*! Heap index for interval hooks */
- ssize_t __heap_index;
+ /*! 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;
};
#define BRIDGE_FEATURES_INTERVAL_RATE 10
@@ -170,22 +183,24 @@
* \brief Structure that contains features information
*/
struct ast_bridge_features {
- /*! Attached DTMF based feature hooks */
- AST_LIST_HEAD_NOLOCK(, ast_bridge_features_hook) hooks;
- /*! Attached interval based feature hooks */
+ /*! Attached DTMF feature hooks */
+ AST_LIST_HEAD_NOLOCK(, ast_bridge_hook) dtmf_hooks;
+ /*! Attached hangup interception hooks */
+ AST_LIST_HEAD_NOLOCK(, ast_bridge_hook) hangup_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;
- /*! Used to determine when interval based features should be checked */
- struct ast_timer *interval_timer;
/*! Talker callback pvt data */
void *talker_pvt_data;
/*! Feature flags that are enabled */
struct ast_flags feature_flags;
- /*! Limits feature data */
- struct ast_bridge_features_limits *limits;
/*! Used to assign the sequence number to the next interval hook added. */
unsigned int interval_sequence;
/*! Bit to indicate that the feature_flags and hook list is setup */
@@ -195,7 +210,6 @@
/* BUGBUG why is dtmf_passthrough not a feature_flags bit? */
/*! Bit to indicate whether DTMF should be passed into the bridge tech or not. */
unsigned int dtmf_passthrough:1;
-
};
/*!
@@ -214,6 +228,8 @@
/* BUGBUG the context should be figured out based upon TRANSFER_CONTEXT channel variable of A/B or current context of A/B. More appropriate for when channel moved to other bridges. */
/*! Context to use for transfers */
char context[AST_MAX_CONTEXT];
+ /*! DTMF string used to abort the transfer */
+ char abort[MAXIMUM_DTMF_FEATURE_STRING];
/*! DTMF string used to turn the transfer into a three way conference */
char threeway[MAXIMUM_DTMF_FEATURE_STRING];
/*! DTMF string used to complete the transfer */
@@ -262,7 +278,7 @@
* This registers the function bridge_builtin_attended_transfer as the function responsible for the built in
* attended transfer feature.
*/
-int ast_bridge_features_register(enum ast_bridge_builtin_feature feature, ast_bridge_features_hook_callback callback, const char *dtmf);
+int ast_bridge_features_register(enum ast_bridge_builtin_feature feature, ast_bridge_hook_callback callback, const char *dtmf);
/*!
* \brief Unregister a handler for a built in feature
@@ -321,7 +337,35 @@
int ast_bridge_interval_unregister(enum ast_bridge_builtin_interval interval);
/*!
- * \brief Attach a custom hook to a bridge features structure
+ * \brief Attach a hangup 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
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ *
+ * Example usage:
+ *
+ * \code
+ * struct ast_bridge_features features;
+ * ast_bridge_features_init(&features);
+ * ast_bridge_hangup_hook(&features, hangup_callback, NULL, NULL);
+ * \endcode
+ *
+ * This makes the bridging core call hangup_callback if a
+ * channel that has this hook hangs up. A pointer to useful
+ * data may be provided to the hook_pvt parameter.
+ */
+int ast_bridge_hangup_hook(struct ast_bridge_features *features,
+ ast_bridge_hook_callback callback,
+ void *hook_pvt,
+ ast_bridge_hook_pvt_destructor destructor);
+
+/*!
+ * \brief Attach a DTMF hook to a bridge features structure
*
* \param features Bridge features structure
* \param dtmf DTMF string to be activated upon
@@ -337,25 +381,24 @@
* \code
* struct ast_bridge_features features;
* ast_bridge_features_init(&features);
- * ast_bridge_features_hook(&features, "#", pound_callback, NULL, NULL);
+ * ast_bridge_dtmf_hook(&features, "#", pound_callback, NULL, NULL);
* \endcode
*
* This makes the bridging core call pound_callback if a channel that has this
* feature structure inputs the DTMF string '#'. A pointer to useful data may be
* provided to the hook_pvt parameter.
*/
-int ast_bridge_features_hook(struct ast_bridge_features *features,
+int ast_bridge_dtmf_hook(struct ast_bridge_features *features,
const char *dtmf,
- ast_bridge_features_hook_callback callback,
+ ast_bridge_hook_callback callback,
void *hook_pvt,
- ast_bridge_features_hook_pvt_destructor destructor);
-
-/*!
- * \brief attach a custom interval hook to a bridge features structure
+ ast_bridge_hook_pvt_destructor destructor);
+
+/*!
+ * \brief attach an interval hook to a bridge features structure
*
* \param features Bridge features structure
* \param interval The interval that the hook should execute at in milliseconds
- * \param strict If set this takes into account the time spent executing the callback when rescheduling the interval hook
* \param callback Function to execute upon activation
* \param hook_pvt Unique data
* \param destructor Optional destructor callback for hook_pvt data
@@ -366,17 +409,17 @@
* \code
* struct ast_bridge_features features;
* ast_bridge_features_init(&features);
- * ast_bridge_features_interval_hook(&features, 1000, 0, playback_callback, NULL, NULL);
+ * ast_bridge_interval_hook(&features, 1000, playback_callback, NULL, NULL);
* \endcode
*
* This makes the bridging core call playback_callback every second. A pointer to useful
* data may be provided to the hook_pvt parameter.
*/
-int ast_bridge_features_interval_hook(struct ast_bridge_features *features,
+int ast_bridge_interval_hook(struct ast_bridge_features *features,
unsigned int interval,
- ast_bridge_features_hook_callback callback,
+ ast_bridge_hook_callback callback,
void *hook_pvt,
- ast_bridge_features_hook_pvt_destructor destructor);
+ ast_bridge_hook_pvt_destructor destructor);
/*!
* \brief Update the interval on an interval hook that is currently executing a callback
@@ -390,7 +433,7 @@
* Example usage:
*
* \code
- * ast_bridge_features_interval_update(bridge_channel, 10000);
+ * ast_bridge_interval_hook_update(bridge_channel, 10000);
* \endcode
*
* This updates the executing interval hook so that it will be triggered next in 10 seconds.
@@ -398,7 +441,7 @@
* \note This can only be called from the context of the interval hook callback itself. If this
* is called outside the callback then behavior is undefined.
*/
-int ast_bridge_features_interval_update(struct ast_bridge_channel *bridge_channel, unsigned int interval);
+int ast_bridge_interval_hook_update(struct ast_bridge_channel *bridge_channel, unsigned int interval);
/*!
* \brief Set a callback on the features structure to receive talking notifications on.
@@ -422,23 +465,24 @@
* \param feature Feature to enable
* \param dtmf Optionally the DTMF stream to trigger the feature, if not specified it will be the default
* \param config Configuration structure unique to the built in type
- *
- * \retval 0 on success
- * \retval -1 on failure
- *
- * Example usage:
- *
- * \code
- * struct ast_bridge_features features;
- * ast_bridge_features_init(&features);
- * ast_bridge_features_enable(&features, AST_BRIDGE_BUILTIN_ATTENDEDTRANSFER, NULL);
+ * \param destructor Optional destructor callback for config data
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ *
+ * Example usage:
+ *
+ * \code
+ * struct ast_bridge_features features;
+ * ast_bridge_features_init(&features);
+ * ast_bridge_features_enable(&features, AST_BRIDGE_BUILTIN_ATTENDEDTRANSFER, NULL, NULL);
* \endcode
*
* This enables the attended transfer DTMF option using the default DTMF string. An alternate
* string may be provided using the dtmf parameter. Internally this is simply setting up a hook
* to a built in feature callback function.
*/
-int ast_bridge_features_enable(struct ast_bridge_features *features, enum ast_bridge_builtin_feature feature, const char *dtmf, void *config);
+int ast_bridge_features_enable(struct ast_bridge_features *features, enum ast_bridge_builtin_feature feature, const char *dtmf, void *config, ast_bridge_hook_pvt_destructor destructor);
/*!
* \brief Constructor function for ast_bridge_features_limits
Modified: team/group/bridge_construction/main/bridging.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/main/bridging.c?view=diff&rev=382567&r1=382566&r2=382567
==============================================================================
--- team/group/bridge_construction/main/bridging.c (original)
+++ team/group/bridge_construction/main/bridging.c Wed Mar 6 18:43:54 2013
@@ -553,7 +553,7 @@
static struct ast_frame *bridge_handle_dtmf(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
{
struct ast_bridge_features *features;
- struct ast_bridge_features_hook *hook;
+ struct ast_bridge_hook *hook;
features = bridge_channel->features;
if (!features) {
@@ -567,8 +567,8 @@
/* 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. */
/* See if this DTMF matches the beginnings of any feature hooks, if so we switch to the feature state to either execute the feature or collect more DTMF */
- AST_LIST_TRAVERSE(&features->hooks, hook, entry) {
- if (hook->dtmf[0] == frame->subclass.integer) {
+ AST_LIST_TRAVERSE(&features->dtmf_hooks, hook, entry) {
+ if (hook->parms.dtmf.code[0] == frame->subclass.integer) {
struct ast_frame action = {
.frametype = AST_FRAME_BRIDGE_ACTION,
.subclass.integer = AST_BRIDGE_ACTION_FEATURE,
@@ -584,9 +584,61 @@
return frame;
}
+/*!
+ * \internal
+ * \brief Handle bridge hangup event.
+ * \since 12.0.0
+ *
+ * \param bridge Bridge involved in a hangup.
+ * \param bridge_channel Which channel is hanging up.
+ *
+ * \return Nothing
+ */
+static void bridge_handle_hangup(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
+{
+ struct ast_bridge_features *features;
+
+ features = bridge_channel->features;
+ if (!features) {
+ features = &bridge->features;
+ }
+
+ if (features->usable) {
+ struct ast_bridge_hook *hook;
+
+ /* Run any hangup hooks. */
+ AST_LIST_TRAVERSE_SAFE_BEGIN(&features->hangup_hooks, hook, entry) {
+ int failed;
+
+ failed = hook->callback(bridge, bridge_channel, hook->hook_pvt);
+ if (failed) {
+ ast_debug(1, "Hangup hook %p is being removed from bridge channel %p(%s)\n",
+ hook, bridge_channel, ast_channel_name(bridge_channel->chan));
+ AST_LIST_REMOVE_CURRENT(entry);
+ if (hook->destructor) {
+ hook->destructor(hook->hook_pvt);
+ }
+ ast_free(hook);
+ }
+ }
+ AST_LIST_TRAVERSE_SAFE_END;
+ }
+
+ /* Default hangup action. */
+ ao2_lock(bridge_channel);
+ switch (bridge_channel->state) {
+ case AST_BRIDGE_CHANNEL_STATE_WAIT:
+ ast_bridge_change_state_nolock(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
+ break;
+ default:
+ break;
+ }
+ ao2_unlock(bridge_channel);
+}
+
static int bridge_channel_interval_ready(struct ast_bridge_channel *bridge_channel)
{
- struct ast_bridge_features_hook *hook;
+ struct ast_bridge_hook *hook;
if (!bridge_channel->features || !bridge_channel->features->usable
|| !bridge_channel->features->interval_hooks) {
@@ -594,7 +646,7 @@
}
hook = ast_heap_peek(bridge_channel->features->interval_hooks, 1);
- if (!hook || ast_tvdiff_ms(hook->interval_trip_time, ast_tvnow()) > 0) {
+ if (!hook || ast_tvdiff_ms(hook->parms.timer.trip_time, ast_tvnow()) > 0) {
return 0;
}
@@ -674,16 +726,7 @@
}
/* This is pretty simple... see if they hung up */
if (!frame || (frame->frametype == AST_FRAME_CONTROL && frame->subclass.integer == AST_CONTROL_HANGUP)) {
- /* Signal the thread that is handling the bridged channel that it should be ended */
- ao2_lock(bridge_channel);
- switch (bridge_channel->state) {
- case AST_BRIDGE_CHANNEL_STATE_WAIT:
- ast_bridge_change_state_nolock(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
- break;
- default:
- break;
- }
- ao2_unlock(bridge_channel);
+ bridge_handle_hangup(bridge, bridge_channel);
} else if (frame->frametype == AST_FRAME_CONTROL && bridge_drop_control_frame(frame->subclass.integer)) {
ast_debug(1, "Dropping control frame %d from bridge channel %p(%s)\n",
frame->subclass.integer, bridge_channel,
@@ -1413,14 +1456,14 @@
/*! \brief Internal function that activates interval hooks on a bridge channel */
static void bridge_channel_interval(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
{
- struct ast_bridge_features_hook *hook;
+ struct ast_bridge_hook *hook;
while ((hook = ast_heap_peek(bridge_channel->features->interval_hooks, 1))) {
int res;
struct timeval start = ast_tvnow();
int execution_time = 0;
- if (ast_tvdiff_ms(hook->interval_trip_time, start) > 0) {
+ if (ast_tvdiff_ms(hook->parms.timer.trip_time, start) > 0) {
ast_debug(1, "Hook %p on bridge channel %p(%s) wants to happen in the future, stopping our traversal\n",
hook, bridge_channel, ast_channel_name(bridge_channel->chan));
break;
@@ -1432,12 +1475,12 @@
/*
* Must be popped after the callback. The callback could call
- * ast_bridge_features_interval_update().
+ * ast_bridge_interval_hook_update().
*/
ast_heap_pop(bridge_channel->features->interval_hooks);
- if (res || !hook->interval) {
- ast_debug(1, "Hook %p is being removed from bridge channel %p(%s)\n",
+ if (res || !hook->parms.timer.interval) {
+ ast_debug(1, "Interval hook %p is being removed from bridge channel %p(%s)\n",
hook, bridge_channel, ast_channel_name(bridge_channel->chan));
if (hook->destructor) {
hook->destructor(hook->hook_pvt);
@@ -1446,17 +1489,18 @@
continue;
}
- ast_debug(1, "Updating hook %p and adding it back to bridge channel %p(%s)\n",
- hook, bridge_channel, ast_channel_name(bridge_channel->chan));
+ ast_debug(1, "Updating interval hook %p with interval %u on bridge channel %p(%s)\n",
+ hook, hook->parms.timer.interval, bridge_channel,
+ ast_channel_name(bridge_channel->chan));
execution_time = ast_tvdiff_ms(ast_tvnow(), start);
/* resetting start */
start = ast_tvnow();
- hook->interval_trip_time = ast_tvadd(start, ast_samp2tv(hook->interval - execution_time, 1000));
-
- hook->seqno = ast_atomic_fetchadd_int((int *)&bridge_channel->features->interval_sequence, +1);
+ 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);
ast_heap_push(bridge_channel->features->interval_hooks, hook);
}
}
@@ -1469,7 +1513,7 @@
static void bridge_channel_feature(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
{
struct ast_bridge_features *features = (bridge_channel->features ? bridge_channel->features : &bridge->features);
- struct ast_bridge_features_hook *hook = NULL;
+ struct ast_bridge_hook *hook = NULL;
char dtmf[MAXIMUM_DTMF_FEATURE_STRING] = "";
int look_for_dtmf = 1, dtmf_len = 0;
@@ -1502,20 +1546,22 @@
look_for_dtmf = 0;
/* See if a DTMF feature hook matches or can match */
- AST_LIST_TRAVERSE(&features->hooks, hook, entry) {
+ AST_LIST_TRAVERSE(&features->dtmf_hooks, hook, entry) {
/* If this hook matches just break out now */
- if (!strcmp(hook->dtmf, dtmf)) {
+ if (!strcmp(hook->parms.dtmf.code, dtmf)) {
ast_debug(1, "DTMF feature hook %p matched DTMF string '%s' on bridge channel %p(%s)\n",
hook, dtmf, bridge_channel, ast_channel_name(bridge_channel->chan));
look_for_dtmf = 0;
break;
- } else if (!strncmp(hook->dtmf, dtmf, dtmf_len)) {
+ } else if (!strncmp(hook->parms.dtmf.code, dtmf, dtmf_len)) {
ast_debug(1, "DTMF feature hook %p can match DTMF string '%s', it wants '%s', on bridge channel %p(%s)\n",
- hook, dtmf, hook->dtmf, bridge_channel, ast_channel_name(bridge_channel->chan));
+ hook, dtmf, hook->parms.dtmf.code, bridge_channel,
+ ast_channel_name(bridge_channel->chan));
look_for_dtmf = 1;
} else {
ast_debug(1, "DTMF feature hook %p does not match DTMF string '%s', it wants '%s', on bridge channel %p(%s)\n",
- hook, dtmf, hook->dtmf, bridge_channel, ast_channel_name(bridge_channel->chan));
+ hook, dtmf, hook->parms.dtmf.code, bridge_channel,
+ ast_channel_name(bridge_channel->chan));
}
}
@@ -1530,7 +1576,27 @@
/* If a hook was actually matched execute it on this channel, otherwise stream up the DTMF to the other channels */
if (hook) {
- hook->callback(bridge, bridge_channel, hook->hook_pvt);
+ int failed;
+
+ failed = hook->callback(bridge, bridge_channel, hook->hook_pvt);
+ if (failed) {
+ struct ast_bridge_hook *cur;
+
+ AST_LIST_TRAVERSE_SAFE_BEGIN(&features->dtmf_hooks, cur, entry) {
+ if (cur == hook) {
+ ast_debug(1, "DTMF hook %p is being removed from bridge channel %p(%s)\n",
+ hook, bridge_channel, ast_channel_name(bridge_channel->chan));
+ AST_LIST_REMOVE_CURRENT(entry);
+ if (hook->destructor) {
+ hook->destructor(hook->hook_pvt);
+ }
+ ast_free(hook);
+ break;
+ }
+ }
+ AST_LIST_TRAVERSE_SAFE_END;
+ }
+
/*
* If we are handing the channel off to an external hook for
* ownership, we are not guaranteed what kind of state it will
@@ -1538,15 +1604,7 @@
* here if the hook did not already change the state.
*/
if (bridge_channel->chan && ast_check_hangup_locked(bridge_channel->chan)) {
- ao2_lock(bridge_channel);
- switch (bridge_channel->state) {
- case AST_BRIDGE_CHANNEL_STATE_WAIT:
- ast_bridge_change_state_nolock(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
- break;
- default:
- break;
- }
- ao2_unlock(bridge_channel);
+ bridge_handle_hangup(bridge, bridge_channel);
}
} else {
ast_bridge_dtmf_stream(bridge, dtmf, bridge_channel->chan);
@@ -2170,18 +2228,16 @@
{
struct ast_bridge_channel *bridge_channel = data;
struct ast_channel *chan;
- enum ast_bridge_channel_state state;
if (bridge_channel->callid) {
ast_callid_threadassoc_add(bridge_channel->callid);
}
bridge_channel_join(bridge_channel);
- state = bridge_channel->state;
chan = bridge_channel->chan;
/* cleanup */
- ast_channel_internal_bridge_channel_set(bridge_channel->chan, NULL);
+ ast_channel_internal_bridge_channel_set(chan, NULL);
bridge_channel->chan = NULL;
bridge_channel->swap = NULL;
ast_bridge_features_destroy(bridge_channel->features);
@@ -2461,7 +2517,7 @@
technology->suspended = 0;
}
-int ast_bridge_features_register(enum ast_bridge_builtin_feature feature, ast_bridge_features_hook_callback callback, const char *dtmf)
+int ast_bridge_features_register(enum ast_bridge_builtin_feature feature, ast_bridge_hook_callback callback, const char *dtmf)
{
if (ARRAY_LEN(builtin_features_handlers) <= feature
|| builtin_features_handlers[feature]) {
@@ -2514,26 +2570,50 @@
}
-int ast_bridge_features_hook(struct ast_bridge_features *features,
+int ast_bridge_dtmf_hook(struct ast_bridge_features *features,
const char *dtmf,
- ast_bridge_features_hook_callback callback,
+ ast_bridge_hook_callback callback,
void *hook_pvt,
- ast_bridge_features_hook_pvt_destructor destructor)
-{
- struct ast_bridge_features_hook *hook;
+ ast_bridge_hook_pvt_destructor destructor)
+{
+ struct ast_bridge_hook *hook;
/* Allocate new memory and setup it's various variables */
hook = ast_calloc(1, sizeof(*hook));
if (!hook) {
return -1;
}
- ast_copy_string(hook->dtmf, dtmf, sizeof(hook->dtmf));
+ ast_copy_string(hook->parms.dtmf.code, dtmf, sizeof(hook->parms.dtmf.code));
hook->callback = callback;
hook->destructor = destructor;
hook->hook_pvt = hook_pvt;
- /* Once done we add it onto the list. Now it will be picked up when DTMF is used */
- AST_LIST_INSERT_TAIL(&features->hooks, hook, entry);
+ /* Once done we add it onto the list. */
+ AST_LIST_INSERT_TAIL(&features->dtmf_hooks, hook, entry);
+
+ features->usable = 1;
+
+ return 0;
+}
+
+int ast_bridge_hangup_hook(struct ast_bridge_features *features,
+ ast_bridge_hook_callback callback,
+ void *hook_pvt,
+ ast_bridge_hook_pvt_destructor destructor)
+{
+ struct ast_bridge_hook *hook;
+
+ /* Allocate new memory and setup it's various variables */
+ hook = ast_calloc(1, sizeof(*hook));
+ if (!hook) {
+ return -1;
+ }
+ hook->callback = callback;
+ hook->destructor = destructor;
+ hook->hook_pvt = hook_pvt;
+
+ /* Once done we add it onto the list. */
+ AST_LIST_INSERT_TAIL(&features->hangup_hooks, hook, entry);
features->usable = 1;
@@ -2550,13 +2630,13 @@
features->talker_pvt_data = pvt_data;
}
-int ast_bridge_features_interval_hook(struct ast_bridge_features *features,
+int ast_bridge_interval_hook(struct ast_bridge_features *features,
unsigned int interval,
- ast_bridge_features_hook_callback callback,
+ ast_bridge_hook_callback callback,
void *hook_pvt,
- ast_bridge_features_hook_pvt_destructor destructor)
-{
- struct ast_bridge_features_hook *hook = NULL;
+ ast_bridge_hook_pvt_destructor destructor)
+{
+ struct ast_bridge_hook *hook = NULL;
if (!interval || !callback || !features || !features->interval_hooks
|| !(hook = ast_calloc(1, sizeof(*hook)))) {
@@ -2572,24 +2652,24 @@
ast_timer_set_rate(features->interval_timer, BRIDGE_FEATURES_INTERVAL_RATE);
}
- hook->interval = interval;
+ hook->parms.timer.interval = interval;
hook->callback = callback;
hook->destructor = destructor;
hook->hook_pvt = hook_pvt;
- ast_debug(1, "Putting interval hook %p in the interval hooks heap on features %p\n",
- hook, features);
- hook->interval_trip_time = ast_tvadd(ast_tvnow(), ast_samp2tv(hook->interval, 1000));
- hook->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->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);
ast_heap_push(features->interval_hooks, hook);
features->usable = 1;
return 0;
}
-int ast_bridge_features_interval_update(struct ast_bridge_channel *bridge_channel, unsigned int interval)
-{
- struct ast_bridge_features_hook *hook;
+int ast_bridge_interval_hook_update(struct ast_bridge_channel *bridge_channel, unsigned int interval)
+{
+ struct ast_bridge_hook *hook;
if (!bridge_channel->features || !bridge_channel->features->usable
|| !bridge_channel->features->interval_hooks) {
@@ -2600,14 +2680,13 @@
if (!hook) {
return -1;
}
- hook->interval = interval;
+ hook->parms.timer.interval = interval;
return 0;
}
-int ast_bridge_features_enable(struct ast_bridge_features *features, enum ast_bridge_builtin_feature feature, const char *dtmf, void *config)
-{
-/* BUGBUG a destructor for config is needed if it is going to be non-NULL */
+int ast_bridge_features_enable(struct ast_bridge_features *features, enum ast_bridge_builtin_feature feature, const char *dtmf, void *config, ast_bridge_hook_pvt_destructor destructor)
+{
if (ARRAY_LEN(builtin_features_handlers) <= feature
|| !builtin_features_handlers[feature]) {
return -1;
@@ -2624,8 +2703,11 @@
}
}
- /* The rest is basically pretty easy. We create another hook using the built in feature's callback and DTMF, easy as pie. */
- return ast_bridge_features_hook(features, dtmf, builtin_features_handlers[feature], config, NULL);
+ /*
+ * The rest is basically pretty easy. We create another hook
+ * using the built in feature's DTMF callback. Easy as pie.
+ */
+ return ast_bridge_dtmf_hook(features, dtmf, builtin_features_handlers[feature], config, destructor);
}
int ast_bridge_features_limits_construct(struct ast_bridge_features_limits *limits)
@@ -2649,6 +2731,7 @@
{
if (builtin_interval_handlers[AST_BRIDGE_BUILTIN_INTERVAL_LIMITS]) {
int (*bridge_features_set_limits_callback)(struct ast_bridge_features *features, struct ast_bridge_features_limits *limits);
+
bridge_features_set_limits_callback = builtin_interval_handlers[AST_BRIDGE_BUILTIN_INTERVAL_LIMITS];
return bridge_features_set_limits_callback(features, limits);
}
@@ -2665,15 +2748,16 @@
static int interval_hook_time_cmp(void *a, void *b)
{
- struct ast_bridge_features_hook *hook_a = a;
- struct ast_bridge_features_hook *hook_b = b;
- int cmp = ast_tvcmp(hook_b->interval_trip_time, hook_a->interval_trip_time);
-
[... 144 lines stripped ...]
More information about the asterisk-commits
mailing list